使用已知的公钥和源代码反转 Java 摘要函数

逆向工程 加密 爪哇
2021-06-15 21:59:01

Java 应用程序使用消息摘要验证来自 clearnet 服务器(无 SSL)的 XML 字符串未被篡改。它使用本地存储的公钥来实现,使用变量访问pk_enc

该应用程序向外部服务器请求 2 个字符串:XML 和一个哈希(均为 base64 编码):

String xml_enc = // ...
String hashStr_enc = // ...

然后应用程序从 base64 解码:

String xml = new String(Base64.decode(xml_enc));
byte[] hashStr = Base64.decode(hashStr_enc);

xml我们现在有一个可读的XML字符串,并在hashStr_dec一堆乱码。

然后验证这两个函数的结果是否相等:

public String createMD5hashForResponseXMLDocument(String xml) {
    try {
        byte[] e = xml.getBytes();
        MessageDigest algorithm = MessageDigest.getInstance("MD5");
        algorithm.reset();
        algorithm.update(e);
        byte[] messageDigest = algorithm.digest();
        StringBuffer hexString = new StringBuffer();

        for (int i = 0; i < messageDigest.length; ++i) {
            hexString.append(Integer.toString((messageDigest[i] & 255) + 256, 16).substring(1));
        }

        return hexString.toString();
    } catch (Exception e) {
        e.printStackTrace();
        return "";
    }
}

public String decryptRSAcipherUsedForSigning(String pk_enc, byte[] hashStr) {
    try {

        X509EncodedKeySpec e = new X509EncodedKeySpec(decodeBASE64(pk_enc));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        RSAPublicKey RSApublicKey = (RSAPublicKey) keyFactory.generatePublic(e);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
        cipher.init(2, RSApublicKey);
        byte[] MD5hash = cipher.doFinal(hashStr);
        return new String(MD5hash);

    } catch (Exception e) {
        e.printStackTrace();
        return "";
    }
}

只要您不接触 XML,一切都可以正常工作,并且这两个函数的计算结果相等。


我现在想修改 XML 并正确计算散列(与上面发生的情况相反)。鉴于我有pk_enc它不应该是不可能的。

我怎样才能做到这一点?这是我尝试过的。为简单起见,我使用了与原始 XML 相同的 XML。

首先,我将未编码的 XML 提供给createMD5hashForResponseXMLDocument

String xml_md5 = createMD5hashForResponseXMLDocument(my_xml_string);

然后我运行这个函数。它与decryptRSAcipherUsedForSigning但我更改cipher.init(2, RSApublicKey);相同cipher.init(1, RSApublicKey);

public byte[] encryptHash(String pk_enc, String xml_m5d) {
        try {
            X509EncodedKeySpec e = new X509EncodedKeySpec(decodeBASE64(pk_enc));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPublicKey RSApublicKey = (RSAPublicKey) keyFactory.generatePublic(e);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
            cipher.init(1, RSApublicKey);
            byte[] result = cipher.doFinal(xml_m5d.getBytes());
            return result;

        } catch (Exception e) {
            e.printStackTrace();
            return "".getBytes();
        }
    }

这不起作用:提供与我开始使用的相同的 XML,它不会产生相同的结果。此外,如果我尝试将其反馈给decryptRSAcipherUsedForSigning,则会收到此错误:

javax.crypto.BadPaddingException: Decryption error
    at sun.security.rsa.RSAPadding.unpadV15(Unknown Source)
    at sun.security.rsa.RSAPadding.unpad(Unknown Source)
    at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:356)
    at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
    at javax.crypto.Cipher.doFinal(Cipher.java:2164)
    at com.test.test.MainTest.decryptRSAcipherUsedForSigning(MainTest.java:112)
    at com.test.test.MainTest.Execute(MainTest.java:59)
    at com.test.test.test.main(test.java:13)

请注意,我知道 String 和 byte[] 之间的区别,并且我一直很小心,不要在两者之间进行不当切换。虽然我不排除这可能是问题所在,但应该没问题。

1个回答

只要我没有相应的私钥,这是不可能做到的pk_enc

使用公钥解密意味着验证:我不知道,看到用于解密的公钥并得出错误的结论,即足以加密数据。

它不是。