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[] 之间的区别,并且我一直很小心,不要在两者之间进行不当切换。虽然我不排除这可能是问题所在,但应该没问题。