http://blog.local.ch/archive/2007/10/29/openssl-php-to-java.html
で紹介されている方法と逆をすればできるはずです。
1.ライブラリインストール
必要なライブラリをインストールします。
http://www.bouncycastle.org/
インストール方法
http://www.langedge.jp/blog/index.php?itemid=150
残念ながら、openssl-php-to-java.html に掲載のJavaプログラムを実行するとキャストエラーが発生します。プログラムを変更しなければなりませんが、なかかな解決が難しそうなエラーです。
そこで、プログラムを変更することはしないで、PEM形式の公開鍵、秘密鍵をJavaが直接扱える形式を変換することにします。 形式を変換することで外部ライブラリを使う必要がなくなります。ただし、PHP では公開鍵、秘密鍵はPEM形式である必要がありますので、同じ鍵が複数のフォーマットで存在することになります。
2.JavaによるデータのRC4暗号化と RC4暗号キーの公開鍵暗号化
//データをRC4暗号化する
// RC4暗号キーを公開鍵で暗号化する
// plainKey = RC4暗号キー
// path = 公開鍵ファイル
private static byte[] encryptRSA(byte[] plainKey, String path) throws Exception
{
File keyFile = new File(path);
byte[] encodedKey = new byte[(int)keyFile.length()];
FileInputStream fis = new FileInputStream(keyFile);
fis.read(encodedKey); fis.close();
X509EncodedKeySpec publicKeySpec =
new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA" );
PublicKey pubKey = kf.generatePublic(publicKeySpec);
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, pubKey);
return rsa.doFinal(plainKey);
}
byte[] ciphertext = encryptRC4(plainKey.getBytes(), plainText.getBytes());
1.ライブラリインストール
必要なライブラリをインストールします。
http://www.bouncycastle.org/
インストール方法
http://www.langedge.jp/blog/index.php?itemid=150
残念ながら、openssl-php-to-java.html に掲載のJavaプログラムを実行するとキャストエラーが発生します。プログラムを変更しなければなりませんが、なかかな解決が難しそうなエラーです。
そこで、プログラムを変更することはしないで、PEM形式の公開鍵、秘密鍵をJavaが直接扱える形式を変換することにします。 形式を変換することで外部ライブラリを使う必要がなくなります。ただし、PHP では公開鍵、秘密鍵はPEM形式である必要がありますので、同じ鍵が複数のフォーマットで存在することになります。
2.JavaによるデータのRC4暗号化と RC4暗号キーの公開鍵暗号化
//データをRC4暗号化する
// plainKey = RC4暗号鍵
// plainText = 暗号化するデータ
// plainText = 暗号化するデータ
private static byte[] encryptRC4(byte[] plainKey, byte[] plainText) throws Exception
{
SecretKey skeySpec = new SecretKeySpec(plainKey, "RC4");
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
return cipher.doFinal(plainText);
}
SecretKey skeySpec = new SecretKeySpec(plainKey, "RC4");
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
return cipher.doFinal(plainText);
}
// RC4暗号キーを公開鍵で暗号化する
// plainKey = RC4暗号キー
// path = 公開鍵ファイル
private static byte[] encryptRSA(byte[] plainKey, String path) throws Exception
{
File keyFile = new File(path);
byte[] encodedKey = new byte[(int)keyFile.length()];
FileInputStream fis = new FileInputStream(keyFile);
fis.read(encodedKey); fis.close();
X509EncodedKeySpec publicKeySpec =
new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA" );
PublicKey pubKey = kf.generatePublic(publicKeySpec);
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, pubKey);
return rsa.doFinal(plainKey);
}
byte[] ciphertext = encryptRC4(plainKey.getBytes(), plainText.getBytes());
byte[] cipherKey = encryptRSA(plainKey.getBytes(), path);
PHPでデータを公開鍵で暗号化するには以下のようにします。
$public_key = openssl_pkey_get_public(file_get_contents( <PEM形式公開鍵ファイル> ));
openssl_seal($data, $encrypted_data, $env_key, array($public_key));
プレーンデータ $dataが $public_key で RC4暗号化されます。RC4の暗号鍵は自動生成されます。結果として $encrypted_data に暗号化されたデータが、$env_key[0]に RC4暗号鍵が暗号化されたものがセットされます。
つまり、$encrypted_data = ciphertext, $enc_key[0] = cipherKey です。ただし、ciphertext と cipherKeyはバイナリですので、BASE64に変換後、文字列にしてから PHP に渡すことで、PHP側で復号化できます。
String ciphertextBase64String = new String ( Base64.encodeBase64(ciphertext), "UTF-8");
String cipherKeyBase64String = new String( Base64.encodeBase64(cihperKey), "UTF-8");
上記コードのBase64変換は Apache Commons ライブラリの場合です。
3.PHP側での暗号されたデータと鍵の復号化
$private_key = openssl_pkey_get_private(file_get_contents(<PEM形式秘密鍵パス>));
$encrypted_data = base64_decode(<base64化されたciphertext>);
$env_key[0] = base64_decode(<base64化されたcipherKey >);
// 復号処理
if (!openssl_open($encrypted_data, $decrypted_data, $env_key[0], $private_key))
{
die(openssl_error_string() . "\n");
}
// 鍵リソースの解放
openssl_free_key($private_key);
$decrypted_dataが復号化されたプレーンテキストになります。
4.結果
Windows 上のJavaで暗号化したものは PHP で復号化できますが、Linux上のJavaで暗号化したものはPHPで復号エラーが発生します。Javaで復号化する限り問題はまったくありません。
Windows 上でRC4鍵を暗号化すると、毎回異なる暗号データが生成されるがLinux上では毎回同じ暗号データが生成されてしまいます。 WindowsとLinuxでは異なるバージョンの Java を使っているための相違だと考え、両者で同じバージョンを使ってみましたが問題は解決しませんでした。.
5. Linux対応
Linux上の PHPでは復号化処理中に PCKS1パッディングエラーとなっていましたので、それに関連のエラーであることは予想できましたが、対応策が分かりませんでした。Webを検索しているとRSA暗号のパディング指定ができることがわかりました。
encryptRSA(byte[] plainKey, String path) 関数の1行を以下のように変更します。
変更前 Cipher rsa = Cipher.getInstance("RSA");
変更後 Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding");
パディングを指定すると Linuxでも Javaで暗号化したものをPHPで復号化できるようになりました。
6. OpenSSL vs mcrypt
PHPと Javaの連携では PHPの mcrypt を利用する方法があるようです。
レンタルサーバでは OpenSSLはほとんど利用できるようですが、mcryptパッケージは利用できないことがあります。レンタルサーバを使うのであれば、PHPでの暗号化はOpenSSLを前提とした方が可搬性があるように思われます。