.net 用于RSA加密的公钥是形似这样的字符串:
<RSAKeyValue><Modulus>sYbL…nGb=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
这样的公钥,是Java无法直接使用的。所以从网上找到用于转换这个公钥的类RsaHelper。 (下载RsaHelper)然后:PublicKey pubKey = RsaHelper.decodePublicKeyFromXml(Global.RSA_PUBLIC_KEY);
encryptedString = RsaHelper.encryptDataFromStr(plaintString,pubKey);
这样,RSA加密就完成了,而且加密后的结果给到.net也能成功解密(Java工程用的jdk1.6)。
然后我把Java工程里的代码拷贝到Android工程(android2.3)里,加密后的内容.net端竟然无法解密!!!
难道Android工程与Java工程,用同样的代码同样的公钥加密同样的字符串,结果是不一样的?
我试了一下,在Android工程里,每次加密同一个字符串,加密结果都是一致的。但在Java工程里,即使加密同一个字符串,每次出来的结果都不一样。
跟踪一下RsaHelper的代码,关键的几句如下:
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
问题一定就出在这个Cipher类里了。
通过网络搜索,找到了以下内容:(内容来自http://blog.youkuaiyun.com/sfdev/article/details/2188563)
.Net环境下每次用RSA算法加密都会得到不同的结果,这是因为每次都添加了一些随机数,其实这些随机数的生成也是遵循算法标准的,更专业的说是随机填充算法,比如NoPadding、ISO10126Padding、OAEPPadding、PKCS1Padding、PKCS5Padding、SSL3Padding。
Java主要通过Cipher.getInstance实现RSA,传入的参数是描述为产生某种输出而在给定的输入上执行的操作(或一组操作)的字符串。必须包括加密算法的名称,后面可能跟有一个反馈模式和填充方案。这样的实现就比较灵活,我们可以通过参数指定不同的反馈模式和填充方案;比如Cipher.getInstance("RSA/ECB/PKCS1Padding"),或者Cipher.getInstance("RSA")均可,但用其加密的效果也会不一样;
看到这里,显而易见的一个方法就是在Android工程里getInstance的时候,指定一下随机填充算法。
所以把Cipher cipher = Cipher.getInstance("RSA");改成
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
试一下,成功了!