2013-07-23 110 views
1

我想解密我的Android應用程序中使用我的設備上生成的RSA密鑰的字符串。加密由php服務完成,使用我的應用程序提供的公共rsa密鑰。我的問題是解密,失敗。Android RSA解密(失敗)/服務器端加密(openssl_public_encrypt)

我做了以下內容:

  • 生成密鑰對在Android(與KeyPairGenerator.getInstance( 「RSA」)) - >確定

  • 兩個密鑰(公鑰和私鑰)保存到用Base64.encode(pubKey.getEncoded())編碼後的文件和用私鑰相同的文件。 - >確定

  • 當我打電話給我的web服務,我通過在變量後我的公鑰(在基地64) - >確定

  • Web服務(PHP服務),使用公鑰使用openssl_public_encrypt函數對短字符串進行加密。加密的字符串被轉換爲base64。 - >看起來好,函數不返回FALSE。

  • 應用程序檢索該服務的結果,並對其進行解碼(Base64.decode()) - >行(I已經檢查中,接收到的字節與由openssl_public_encrypt()函數生成的一個原因)

  • 最後一件事是解密這個字符串,我正在做以下事情: - >不是OK

    Cipher cipher = Cipher.getInstance(「RSA」);

    cipher.init(Cipher.DECRYPT_MODE,privateKey);

    byte [] decryptedBytes = cipher.doFinal(cryptedBytes);

    String decryptedString = new String(decryptedBytes);

    System.out.println(decryptedString);

解密的結果與我的原始字符串不匹配。

我錯過了什麼?

+0

'密碼。getInstance(「RSA」)默認爲「教科書RSA」 - 沒有填充 - 根本不安全。我不知道PHP代碼使用了什麼樣的填充,因爲您沒有顯示它,但是您應該在兩端將其更改爲OAEP。 – ntoskrnl

+1

@ntoskrnl你可以把它變成我猜的答案。請注意,默認的「RSA/NONE/NoPadding」僅適用於Bouncy Castle,Java SE - 或更準確地說,Sun JCE - 默認爲「RSA/ECB/PKCS1Padding」。 –

+0

@owlstead好點 - 也說明了顯式聲明模式的重要性,而不是依賴實現之間不同的默認值。 – ntoskrnl

回答

9

OpenSSL默認使用padding = OPENSSL_PKCS1_PADDING。所以要在雙方都有相同的填充機制,你應該使用Cipher.getInstance("RSA/ECB/PKCS1Padding")。這也是您可以在Java SE中使用的。

請注意,依賴加密中的默認操作模式是非常危險的。許多實現具有不同的默認值,並且可能很難查找。因此,請始終嘗試完全指定要使用的算法/模式。

你可以嘗試其他的RSA填充模式,但是請注意 - 不幸的是 - Android已經禁用了很多來自他們改編的Bouncy Castle源代碼的算法和別名。


[編輯]這是一個老的答案,OAEP填充強烈地受到現在使用RSA-KEM建議,或混合加密。

+0

謝謝@owlstead,使用'getInstance(「RSA/ECB/PKCS1Padding」)'我的服務器端腳本可以正確解密我的Android應用程序加密的內容。但是,如果我使用'getInstance(「RSA/None/PKCS1Padding」)'(在服務器端解密雖然不起作用),但我沒有「異常的RSA數據塊」異常。有任何想法嗎? – ericn

+1

這似乎是混合加密的一個明確的例子。 RSA加密不應該單獨使用;通常您應該加密一個新的隨機生成的AES密鑰,並使用該AES密鑰對數據執行加密(例如使用CBC操作模式),這樣您就可以加密幾乎無限量的明文。 –

+0

@MaartenBodewes導致紮根的Android設備,我不想把解密密鑰放在客戶端,所以我怎麼能解密在服務器端,在Android設備加密的文件?請參閱我的相關問題:http://stackoverflow.com/questions/30951805/protected-document-viewer –