androidとGAEでRSA暗号
今作っているアプリでRSA暗号を使おうとしているんですが、ハマりました。
問題はAndroidで暗号化した文字列をGAE(Mac)で復号化しようとすると、復号できないというもの。
そもそもテスト用に作ったMacのjavaプログラムで暗号化したデータと、Androidで暗号化したデータが一致しない。
同じ文字列を同じキー値で暗号化したならば同じ暗号データが手に入るはず
パディングにランダムな文字列を使えば異なるデータになります
なぜか。
Mac(GAE)のJDKに搭載されているJCE(暗号化拡張機能)とAndroidに搭載されているJCEのプロバイダが異なるためのよう。
プロバイダが異なっていても、モード・パディングを揃えれば暗号化/復号化できます
JCEってのはざっくりいうと暗号化/復号化エンジンのインターフェイスみたいなもの*1
実装されているJCEの事をプロバイダって言う。
それぞれどんなプロバイダが搭載されているかリストしてみた。
検証コード
for (Provider provider : providers) {
System.out.println(provider.getName());
System.out.println(provider.getInfo());
System.out.println();
}
GAE(Mac JDK1.6)
- SunPKCS11-Darwin
- SunPKCS11 accessing Mac OS X SmartCardServices
- SUN
- Apple
- Apple Provider (implements DES, Triple DES, AES, Blowfish, PBE, Diffie-Hellman, HMAC/MD5, HMAC/SHA1)
- SunRsaSign
- Sun RSA signature provider
- SunJSSE
- Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)
- SunJCE
- SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC)
- SunJGSS
- Sun (Kerberos v5, SPNEGO)
- SunSASL
- XMLDSig
- XMLDSig (DOM XMLSignatureFactory; DOM KeyInfoFactory)
- SunPCSC
- Sun PC/SC provider
Android 1.6 - Android2.1-update1(emulator)
- DRLCertFactory
- ASN.1, DER, PkiPath, PKCS7
- Crypto
- HARMONY (SHA1 digest; SecureRandom; SHA1withDSA signature)
- HarmonyJSSE
- Harmony JSSE Provider
- BC
- BouncyCastle Security Provider v1.34
これを見ると
Android側で暗号化するときはBC(BouncyCastle)を使って暗号化して、GAE(Mac)側ではSunJCEを使って復号化しようとすると思われます。
そんなことありません
じゃぁ、GAE側もBCで復号化すればいいじゃないかと思ってコードを書き直します。
Cipherインスタンスを作るコード
Cipher cipher = Cipher.getInstance(getCRYPT_ALGORITHM()); cipher.init(Cipher.DECRYPT_MODE, privateKey);
↓
Cipher cipher = Cipher.getInstance(getCRYPT_ALGORITHM(), new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
これで無事復号化できました。
追記 2010-09-01
BC-SunJCEで暗号化/復号化します。
ポイントはアルゴリズムとモードとパディングを同じにすることで暗号化/復号化することができます。
変更する箇所はCipherのインスタンスを作るところ
// 受け渡す文字列は アルゴリズム/モード/パディング の形式で Cipher cipher = Cipher.getInstance("RSA/NONE/NoPadding");
これを暗号化するとき・復号化するときにCipherのインスタンスを作るところで指定してあげれば正常に動作します。
このモードとパディングはいくつか種類があって、暗号化の種類によって指定できるできないが決まっているみたいです。
SunJCEに指定できるパラメータについては、書いてあるページを教えていただきました
Java 暗号化アーキテクチャー Sun プロバイダのドキュメント http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/security/SunProviders.html#SunJCEProvider
BCについてはページを見つけることができませんでした…。
まとめ
同じJCEが安心
暗号化/復号化するときのプロバイダの指定はデフォルトじゃなくて、ちゃんと指定した方がいい。
androidにはデフォルトでBCが入ってたけど、入っているっていう保証はなさそうな気がするからプロバイダをアプリに入れておいた方がいい気がする。
今回GAE(mac)と言ってたのは実際にデプロイしてたわけじゃないから、GAEにはまた別のプロバイダが入ってたりするんじゃないかなぁ…。まさかAppleプロバイダが入ってるとは思えないし。
結局自分でプロバイダ用意した方がいいと思う。
上は打ち消してますけど、自分でプロバイダ用意しようかと思います。
GAEはまだいいにしてもAndroidについては環境が端末の種類だけあるわけですから
プロバイダがないですなんて状態になったら困ります。
暗号アルゴリズムとモードとパディングを合わせましょう。
*1:合ってる??