.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.csdn.net/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");
試一下,成功了!