public static byte[] encrypt(byte[] data) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { final Key publicKey = KeyFactory .getInstance("RSA") .generatePublic(new X509EncodedKeySpec(PUBLIC_KEY_BYTES)); final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); }
public static byte[] decrypt(byte[] data) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { final Key privateKey = KeyFactory .getInstance("RSA") .generatePrivate(new PKCS8EncodedKeySpec(PRIVATE_KEY_BYTES)); final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); }
ポイントは、Cipherのインスタンスを取得するときに、
フィードバックモードとパディングをちゃんと指定すること。
Cipher.getInstance("RSA") // これは悪い例!
同じJavaVM環境なら、こうやって書いても期待通りに動いてしまう。
フィードバックモードおよびパディングを省略すると、
プロバイダ固有のデフォルト値が使われると書いてある。
同じJavaVM環境ならプロバイダーが同じだからデフォルト値も同じなので問題がないというわけ。
ところが、
Sun(Oracle)のJREやJDKにバンドルされているJCEプロバイダのデフォルトはSunJCEで、
Androidの場合はBouncyCastleのようだ。
SunJCEの場合
"RSA"は"RSA/ECB/PKCS1Padding"
がデフォルトみたい。
BouncyCastleの場合は
"RSA"は"RSA/None/NoPadding"
がデフォルトみたい。
これらはたまたま手元の環境で動かしたらそうなっただけで、
デフォルト値が未来永劫変わらない保証はない。
というわけで、フィードバックモードとパディングを省略すると
サーバとAndroid端末の間で渡したデータを復号化できなくなると思った方がよい。
0 件のコメント:
コメントを投稿