我有一个 Java 代码,我可以在其中发送带有扰码密钥的包:
protected void write()
{
writeC(0x00);
writeD(_sessionId);
writeD(PROTOCOL_VERSION);
writeB(_publicKey); --- > scrambled key
writeB(UNKNOWN_GG);
writeB(_blowfishKey);
writeC(0x00);
}
在我的Java代码中,我可以使用以下解密方法正确解密加扰密钥:
public void run()
{
final LoginClient client = getClient();
byte[] decrypted = null;
try
{
final Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding");
rsaCipher.init(Cipher.DECRYPT_MODE, client.getRSAPrivateKey());
decrypted = rsaCipher.doFinal(_raw, 0x00, 0x80);
}
catch (GeneralSecurityException e)
{
LOGGER.error("Failed to generate a cipher.", e);
client.close(LoginFail.REASON_ACCESS_FAILED);
return;
}
try
{
final String user = new String(decrypted, 0x5E, 14).trim().toLowerCase();
final String password = new String(decrypted, 0x6C, 16).trim();
LoginController.getInstance().retrieveAccountInfo(client, user, password);
}
catch (Exception e)
{
LOGGER.error("Failed to decrypt user/password.", e);
client.close(LoginFail.REASON_ACCESS_FAILED);
}
}
在 Java 中,使用以下输入即可正确解密:
乱码密钥:
[124, 168, 24, 242, 228, 213, 212, 54, 235, 100, 160, 114, 163, 61, 75, 218, 182, 245, 166, 34, 214, 132, 15, 71, 135, 194, 141, 227, 38, 1, 217, 145, 203, 135, 209, 137, 111, 33, 54, 34, 57, 0, 189, 243, 199, 219, 109, 56, 15, 225, 143, 59, 176, 108, 76, 204, 232, 133, 216, 126, 70, 30, 115, 74, 25, 0, 133, 38, 128, 16, 28, 183, 155, 24, 188, 86, 117, 191, 135, 36, 211, 165, 104, 217, 6, 182, 164, 136, 101, 215, 42, 113, 111, 55, 208, 207, 105, 35, 182, 47, 241, 107, 139, 215, 213, 249, 43, 125, 219, 34, 53, 103, 250, 92, 154, 128, 75, 189, 168, 128, 229, 6, 239, 177, 101, 126, 218, 75]
Java 私钥:
SunRsaSign RSA private CRT key, 1024 bits
params: null
modulus: 91851415039980683673835443907833548355613725060429787547716446884026400945844827342368025805543719063805785824109075005634172820422680533076648130137521254244221874431195148950936257983839718841574094615493929797376689026996944801887459231860502077721291214210394902757594184173778070286729141127782416296193
private exponent: 6487635995240407475566233880851450254636860602479965310563184653343274943593934811905055029279061836006484620592961353145255138101173202734513392349460393317252650745961877082056763589015732603463063131507792018004450541681668317154023863374611531824451608552071840032997073721859882730955156029598795586149
Chave privada (formato Go):
&rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: big.NewInt(0).SetBytes(new byte[] {0, -126, -52, -2, 101, -128, 16, 28, -73, -101, 24, -68, 86, 117, 15, -21, 104, 31, -91, 104, -39, 6, -74, -92, -120, 101, -41, 42, 113, 111, 55, -48, -49, 105, 35, -74, 47, -15, 107, -117, -41, -43, -7, 43, 125, -37, 34, 53, 103, -6, 92, -102, -128, 75, -67, -88, -128, -27, 6, -17, -79, 101, 126, -38, 75, 101, -88, -99, -44, 100, -59, -56, -127, 112, 124, 28, 36, -42, 25, 0, -123, 38, 80, -50, -5, -48, 50, -85, -49, -30, 21, -89, -110, 73, 54, 9, 94, -94, -92, 103, -90, -98, 74, -67, -11, -20, -7, -106, -114, 28, -7, 88, 95, -11, -67, 21, -69, -5, -47, -28, 76, 13, -125, 55, -49, 35, 96, -87, 1, }),
E: 65537,
},
D: big.NewInt(0).SetBytes(new byte[] {9, 61, 27, 118, -27, -35, -67, 121, -122, 125, -17, -57, -105, -117, 33, 80, -128, 115, -71, 125, 34, -55, 65, -61, -44, -107, -89, 12, -50, 19, 62, 47, 120, 56, -86, -124, -90, 99, -73, 67, -18, 124, 36, 3, 70, -72, 26, -41, -106, 74, 118, 43, 59, -82, 80, -71, -111, -13, -76, 120, 110, 55, -48, -119, 74, -39, 58, 44, -63, -103, -73, -80, 57, 1, 64, -60, -33, -53, -21, 53, -45, -7, -42, 113, 60, 12, 38, 24, -66, 9, -111, 18, -108, -38, 30, 114, -77, -83, -9, 34, 88, -44, -114, -79, -54, -17, 44, 2, -36, -117, -74, 122, -62, -103, 14, 115, -39, 18, 73, -69, -77, -62, -111, -127, -102, -12, 90, 101, }),
}
要解密的字节数组:
[89, 250, 193, 103, 219, 4, 129, 208, 181, 30, 127, 250, 147, 113, 64, 25, 187, 96, 88, 15, 64, 93, 100, 141, 42, 89, 13, 157, 253, 187, 118, 154, 150, 132, 238, 224, 22, 98, 35, 252, 92, 253, 138, 6, 38, 142, 170, 247, 136, 19, 231, 48, 52, 228, 22, 222, 81, 242, 182, 109, 96, 209, 7, 187, 213, 237, 218, 147, 238, 28, 25, 217, 81, 200, 219, 76, 214, 232, 238, 193, 78, 252, 180, 45, 182, 150, 220, 157, 194, 11, 57, 195, 20, 174, 13, 123, 69, 72, 81, 112, 49, 143, 3, 67, 216, 86, 11, 234, 48, 210, 254, 136, 201, 238, 1, 222, 134, 178, 102, 230, 102, 137, 145, 236, 197, 2, 120, 106]
但是,当我尝试使用 crypto/rsa 包在 Golang 中复制解密过程时,我遇到了问题。 Go 的实现如下所示:
func NewScrambledKeyPairTest(bits int) (ScrambledKeyPair, error) {
scrambledModulusJava := []byte{124, 168, 24, 242, 228, 213, 212, 54, 235, 100, 160, 114, 163, 61, 75, 218, 182, 245, 166, 34, 214, 132, 15, 71, 135, 194, 141, 227, 38, 1, 217, 145, 203, 135, 209, 137, 111, 33, 54, 34, 57, 0, 189, 243, 199, 219, 109, 56, 15, 225, 143, 59, 176, 108, 76, 204, 232, 133, 216, 126, 70, 30, 115, 74, 25, 0, 133, 38, 128, 16, 28, 183, 155, 24, 188, 86, 117, 191, 135, 36, 211, 165, 104, 217, 6, 182, 164, 136, 101, 215, 42, 113, 111, 55, 208, 207, 105, 35, 182, 47, 241, 107, 139, 215, 213, 249, 43, 125, 219, 34, 53, 103, 250, 92, 154, 128, 75, 189, 168, 128, 229, 6, 239, 177, 101, 126, 218, 75}
privateKey := &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: big.NewInt(0).SetBytes([]byte{
0, 130, 204, 254, 101, 128, 16, 28, 185, 155, 24, 188, 86, 117, 15, 235, 104, 31, 165, 104, 217, 6, 182, 164, 136, 101, 215, 42, 113, 111, 55, 208, 207, 105, 35, 182, 47, 241, 107, 139, 215, 213, 249, 43, 125, 219, 34, 53, 103, 250, 92, 154, 128, 75, 189, 168, 128, 229, 6, 239, 177, 101, 126, 218, 75, 101, 168, 157, 212, 100, 197, 200, 129, 112, 124, 28, 36, 214, 25, 0, 133, 38, 80, 206, 251, 208, 50, 171, 207, 226, 21, 169, 146, 73, 54, 9, 94, 162, 164, 103, 166, 158, 74, 189, 245, 236, 249, 150, 142, 28, 249, 88, 95, 245, 189, 21, 187, 251, 209, 228, 76, 13, 131, 55, 207, 35, 96, 169, 1,
}),
E: 65537,
},
D: big.NewInt(0).SetBytes([]byte{
9, 61, 27, 118, 229, 221, 189, 121, 134, 125, 239, 199, 151, 139, 33, 80, 128, 115, 185, 125, 34, 201, 65, 195, 212, 149, 167, 12, 206, 19, 62, 47, 120, 56, 170, 132, 166, 99, 185, 67, 238, 124, 36, 3, 70, 184, 26, 215, 150, 74, 118, 43, 59, 174, 80, 185, 145, 243, 180, 120, 110, 55, 208, 137, 74, 217, 58, 44, 193, 153, 183, 176, 57, 1, 64, 196, 223, 203, 235, 53, 211, 249, 214, 113, 60, 12, 38, 24, 190, 9, 145, 18, 148, 218, 30, 114, 179, 173, 247, 34, 88, 212, 142, 177, 202, 239, 44, 2, 220, 139, 182, 122, 194, 153, 14, 115, 217, 18, 73, 187, 179, 194, 145, 129, 154, 244, 90, 101,
}),
}
return ScrambledKeyPair{
Pair: privateKey,
ScrambledModulus: scrambledModulusJava,
}, nil
}
func (p RequestLogin) Run(client *clients.Client, rand io.Reader) error {
privateKey := client.PrivateKey()
c := new(big.Int).SetBytes(p.raw)
m := new(big.Int)
m.Exp(c, privateKey.D, privateKey.N)
em := m.Bytes()
user := string(em[0x5E : 0x5E+14])
pwd := string(em[0x6C : 0x6C+16])
return nil
}
但是我没有成功解密这些字节:
[89, 250, 193, 103, 219, 4, 129, 208, 181, 30, 127, 250, 147, 113, 64, 25, 187, 96, 88, 15, 64, 93, 100, 141, 42, 89, 13, 157, 253, 187, 118, 154, 150, 132, 238, 224, 22, 98, 35, 252, 92, 253, 138, 6, 38, 142, 170, 247, 136, 19, 231, 48, 52, 228, 22, 222, 81, 242, 182, 109, 96, 209, 7, 187, 213, 237, 218, 147, 238, 28, 25, 217, 81, 200, 219, 76, 214, 232, 238, 193, 78, 252, 180, 45, 182, 150, 220, 157, 194, 11, 57, 195, 20, 174, 13, 123, 69, 72, 81, 112, 49, 143, 3, 67, 216, 86, 11, 234, 48, 210, 254, 136, 201, 238, 1, 222, 134, 178, 102, 230, 102, 137, 145, 236, 197, 2, 120, 106]
这些字节在Java中解密后的值是这样的:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 97, 100, 109, 105, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
但在 Golang 中我不能,因为在 Java 中我使用的是: Cipher.getInstance("RSA/ECB/nopadding"); e 在 Golang 中,我还没有找到任何无需填充即可解密字节切片的函数。
您的代码不能直接执行,并且您没有准确描述问题是什么(错误的结果,异常......)。当我用您的数据运行解密(模幂)时:
ciphertextBytes := ([]byte{89, 250, 193, 103, 219, 4, 129, 208, 181, 30, 127, 250, 147, 113, 64, 25, 187, 96, 88, 15, 64, 93, 100, 141, 42, 89, 13, 157, 253, 187, 118, 154, 150, 132, 238, 224, 22, 98, 35, 252, 92, 253, 138, 6, 38, 142, 170, 247, 136, 19, 231, 48, 52, 228, 22, 222, 81, 242, 182, 109, 96, 209, 7, 187, 213, 237, 218, 147, 238, 28, 25, 217, 81, 200, 219, 76, 214, 232, 238, 193, 78, 252, 180, 45, 182, 150, 220, 157, 194, 11, 57, 195, 20, 174, 13, 123, 69, 72, 81, 112, 49, 143, 3, 67, 216, 86, 11, 234, 48, 210, 254, 136, 201, 238, 1, 222, 134, 178, 102, 230, 102, 137, 145, 236, 197, 2, 120, 106})[0:128]
modulusInt := "91851415039980683673835443907833548355613725060429787547716446884026400945844827342368025805543719063805785824109075005634172820422680533076648130137521254244221874431195148950936257983839718841574094615493929797376689026996944801887459231860502077721291214210394902757594184173778070286729141127782416296193"
privateExpInt := "6487635995240407475566233880851450254636860602479965310563184653343274943593934811905055029279061836006484620592961353145255138101173202734513392349460393317252650745961877082056763589015732603463063131507792018004450541681668317154023863374611531824451608552071840032997073721859882730955156029598795586149"
c := new(big.Int)
c.SetBytes(ciphertextBytes)
n := new(big.Int)
n.SetString(modulusInt, 10)
d := new(big.Int)
d.SetString(privateExpInt, 10)
decrypted := new(big.Int).Exp(c, d, n).Bytes()
fmt.Println(hex.EncodeToString(decrypted)) // 24000061646d696e00000000000000000061646d696e000000000000000000000000000000
我得到了正确的结果(十六进制编码):
24000061646d696e00000000000000000061646d696e000000000000000000000000000000
与 Java 代码结果的唯一区别在于,Java 代码自动用 0x00 值从前面填充结果直至密钥大小/模数,而直接模幂当然不会发生这种情况。
要解决此问题,您只需填充自己以使索引正确,例如:
decryptedPadded := append(make([]byte, 128-len(decrypted)), decrypted...)
fmt.Println(hex.EncodeToString(decryptedPadded[0x5E : 0x5E+14])) // 61646d696e000000000000000000
fmt.Println(string(decryptedPadded[0x5E : 0x5E+14])) // admin
安全性:正如评论中已经提到的,没有填充的 RSA 加密是不安全的。此外,现在应使用至少 2048 位(256 字节)的密钥大小。