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 件のコメント:
コメントを投稿