mcrypt拡張モジュールを使った暗号化
libmcryptを利用したPHP拡張モジュールです。DES、3DES、Blowfish、RIJNDAEL(ラインダール:AES暗号とも呼ばれる)、Blowfishなどのブロック暗号をサポートしています。利用可能な暗号モードはCBC、OFB、CFB、ECBです。 PHPで利用するには、libmcryptをインストールし、configureオプションに「--with-mcrypt」を付ける必要があります。また、PHP5以降、libmcrypt 2.5.6以降が必要です。 以下は、SSHやファイル暗号化ソフトウェアなどに広く利用されているBlowfishを使った暗号化・復号のサンプルコードです。「encrypted data」の値は、毎回変わります。※以下のサンプルは、推奨されていない関数mcrypt_cbcを使っています。代替関数のmcrypt_generic() および mdecrypt_generic()を使ったサンプルは、追記2を参照してください。
<?php // 暗号化するデータ $data = '小池さんはラーメン大好き'; $base64_data = base64_encode($data); echo "data : " . $data . "\n"; // 暗号化キー $key = 'the key value for crypting'; /** * 初期化ベクトルを用意する * Windowsの場合、MCRYPT_DEV_URANDOMの代わりにMCRYPT_RANDを使用する */ $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM); // 暗号化処理 $encrypted_data = mcrypt_cbc(MCRYPT_BLOWFISH, $key, $base64_data, MCRYPT_ENCRYPT, $iv); echo "encrypted data : " . base64_encode($encrypted_data)."\n"; // 復号処理 $base64_decrypted_data = mcrypt_cbc(MCRYPT_BLOWFISH, $key, $encrypted_data, MCRYPT_DECRYPT, $iv); $decrypted_data = base64_decode($base64_decrypted_data); echo "decrypted data : " . $decrypted_data . "\n"; echo 'validate : ' . ($data == $decrypted_data ? 'true' : 'false') . "\n";ここでは、CBCモードを使用するため、mcrypt_cbc関数を使用していますが、その他としてmcrypt_encrypt関数/mcrypt_decrypt関数、mcrypt_generic関数が利用可能です。これらの詳細はPHPマニュアルを参照してください。 サンプルの実行結果は以下の通りです。
$ php ./mcrypt_cbc.php data : 小池さんはラーメン大好き encrypted data : bOiwSixcIcwn58/rP5u1RPzmy0wH3T+C7cm4HDtmNDXYiG+NYEuWokFcJg1SLmcq decrypted data : 小池さんはラーメン大好き validate : true $
PEAR::Crypt_Blowfishを使った暗号化
PEARパッケージにも暗号化のパッケージが複数用意されています。先のサンプルで使用した暗号化方式BlowfishのパッケージPEAR::Crypt_Blowfishも用意されています。2007/11/05時点の最新版は1.1.0RC1です。インストールはpearコマンドを使ったいつもの手順でOKです。今回は、Crypt_Blowfish-1.1.0RC1をインストールしました。$ sudo pear install -a Crypt_BlowfishPEAR::Crypt_Blowfishはパッケージ内部で、後述するmcrypt拡張モジュールが利用できる場合、そちらを利用するようになっています。この場合、mcrypt_generic関数を使用することになります。 暗号化・復号のサンプルコードは以下の通りです。なお、以下のサンプルではCBCモードを指定しています(Crypt_Blowfishクラスのfactoryメソッドの第1引数)が、デフォルトのECBモードは現在では推奨されていないモードです。
<?php require_once 'Crypt/Blowfish.php'; echo "mcrypt module is " . (extension_loaded("mcrypt") ? "" : "not ") . "loaded\n"; // 暗号化するデータ $data = '小池さんはラーメン大好き'; echo "data : " . $data . "\n"; // 暗号化キー $key = 'the key value for crypting'; // CBCモードで暗号化するため、初期化ベクトルを用意する $iv = substr(md5(uniqid(rand(), 1)), 0, 8); // 暗号化処理 $blowfish = Crypt_Blowfish::factory('cbc', $key, $iv); $encrypted_data = $blowfish->encrypt(base64_encode($data)); echo "encrypted data : " . base64_encode($encrypted_data) . "\n"; /** * [BK]mcrypt拡張モジュールがロードされている場合、1つのインスタンスを * 使い回すことができない(mcrypt_generic_deinitしていないため)ので、 * 再度インスタンスを取得する必要がある。イケてない。。。 */ if (extension_loaded("mcrypt")) { $blowfish = Crypt_Blowfish::factory('cbc', $key, $iv); } // 復号処理 $decrypted = $blowfish->decrypt($encrypted_data); if (PEAR::isError($decrypted)) { die($decrypted->getMessage() . "\n"); } echo $decrypted . "\n"; $decrypted_data = base64_decode($decrypted); echo "decrypted data : " . $decrypted_data . "\n"; echo 'validate : ' . ($data == $decrypted_data ? 'true' : 'false') . "\n";実行結果は以下のような感じになります。「encrypted data」の値は、毎回変わります。
$ php ./crypt_blowfish.php mcrypt module is not loaded data : 小池さんはラーメン大好き encrypted data : AM7KWxcRFalD8+GNy996PEXlkcGbpo2naceGi9FlIzWpKEy3DBf7ozh1TcAgVTsH 5bCP5rGg44GV44KT44Gv44Op44O844Oh44Oz5aSn5aW944GN decrypted data : 小池さんはラーメン大好き validate : true $また、mcrypt拡張モジュールがロードされている場合は、以下のようになります。
$ php ./crypt_blowfish.php mcrypt module is loaded data : 小池さんはラーメン大好き encrypted data : 4S39zUGp3B7GVSCkyaqQP5m9oTAzLbkMIY2yHp7cUdsrNcAhZ9Gv6XIu7XFaep7R 5bCP5rGg44GV44KT44Gv44Op44O844Oh44Oz5aSn5aW944GN decrypted data : 小池さんはラーメン大好き validate : true $
openssl拡張モジュールを使った暗号化
openssl拡張モジュールを使って、RSA鍵(公開鍵/秘密鍵)を使った暗号化も可能です。先のBlowfishは共通鍵(暗号化・復号に同じ鍵)を使っています。 PHPで利用するには、OpenSSLパッケージをインストールし、configureオプションに「--with-openssl」を付ける必要があります。なお、OpenSSLパッケージは最新のものを使用するようにしましょう。 さて、暗号化・復号を行う前に、以下のような手順で秘密鍵と公開鍵を作成しておきます。$ mkdir certificates $ cd certificates/ $ openssl genrsa -out privkey_rsa.pem $ openssl rsa -pubout -in privkey_rsa.pem -out pubkey_rsa.pem $ chmod 400 privkey_rsa.pem $暗号化・復号のサンプルは、local.ch official blogに掲載されているものを参考にさせていただきました。
<?php /** * $ openssl genrsa -out privkey_rsa.pem * $ openssl rsa -pubout -in privkey_rsa.pem -out pubkey_rsa.pem * * @see http://blog.local.ch/archive/2007/10/29/openssl-php-to-java.html */ // 公開鍵・秘密鍵を保存したディレクトリ define('CERT_DIR', './certificates'); // 暗号化するデータ $data = "小池さんはラーメン大好き"; echo "data : " . $data . "\n"; // 公開鍵を読み込む $public_key = openssl_pkey_get_public(file_get_contents(CERT_DIR . "/pubkey_rsa.pem")); // 暗号化処理 openssl_seal($data, $encrypted_data, $env_key, array($public_key)); echo "encrypted data : " . base64_encode($encrypted_data) ."\n"; echo "env_key : " . base64_encode($env_key[0]) ."\n"; // 鍵リソースの解放 openssl_free_key($public_key); // 秘密鍵を読み込む $private_key = openssl_pkey_get_private(file_get_contents(CERT_DIR . "/privkey_rsa.pem")); // 復号処理 if (!openssl_open($encrypted_data, $decrypted_data, $env_key[0], $private_key)) { die(openssl_error_string() . "\n"); } // 鍵リソースの解放 openssl_free_key($private_key); echo "decrypted data : " . $decrypted_data . "\n"; echo 'validate : ' . ($data == $decrypted_data ? 'true' : 'false') . "\n";このサンプルの実行結果は以下の通りです。
$ php ./openssl.php data : 小池さんはラーメン大好き encrypted data : zvGd1yvHmkptNOlnwg66NSHjwgjSTfNkuH8q3cesaLku115J env_key : hXVAaC6TmyGld+nAp4F2PJgTmItLZZ1geymEbcBboSyP3PGC/29HDsFCKU833LMNpdPggA3iziR7pp3Voaz9Hg== decrypted data : 小池さんはラーメン大好き validate : true $
まとめ
BlowfishとRSA鍵を使った暗号化・復号のサンプルをそれぞれ挙げてみましたが、いかがでしたでしょうか?本エントリが少しでもお役に立てると幸いです。参考URL・書籍
本エントリは以下のサイト・書籍を参考に書かせていただきました。情報を公開していただいたことに改めて感謝いたします。- PHP: mcrypt - Manual
- PHP: OpenSSL - Manual
- PEAR::Crypt_Blowfish
- local.ch official blog :: Using OpenSSL, RSA and RC4 to exchange encrypted data from PHP to Java
- 暗号技術入門-秘密の国のアリス(結城 浩 (著)、ソフトバンククリエイティブ (2003年)、ISBN:4797322977)
追記(2007/11/06 14:00)
はてなブックマークのコメントで「復号化ではなくstrong>復号く/strong>が正しい」旨の指摘をいただきました。仰る通りです。タイトル・本文とも修正しました。 ありがとうございました。追記2(2007/11/06 14:30)
くけーさんからコメントで「mcrypt_cbcはオンラインマニュアルに「使用すべきではありません」とある関数なので, サンプルとして挙げるのに適切ではありません.」との指摘をいただきました。大変失礼しました。仰る通りでした。。。ありがとうございました。 PHPマニュアルには、「mcrypt_generic() および mdecrypt_generic()を参照」とありますので、この2関数を使ったサンプルを以下に挙げておきます。<?php // 暗号化するデータ $data = '小池さんはラーメン大好き'; $base64_data = base64_encode($data); echo "data : " . $data . "\n"; // 暗号化キー $key = 'the key value for crypting'; /** * 初期化ベクトルを用意する * Windowsの場合、MCRYPT_DEV_URANDOMの代わりにMCRYPT_RANDを使用する */ $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM); // 事前処理 $resource = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, '');; // 暗号化処理 mcrypt_generic_init($resource, $key, $iv); $encrypted_data = mcrypt_generic($resource, $base64_data); mcrypt_generic_deinit($resource); echo "encrypted data : " . base64_encode($encrypted_data)."\n"; // 復号処理 mcrypt_generic_init($resource, $key, $iv); $base64_decrypted_data = mdecrypt_generic($resource, $encrypted_data); mcrypt_generic_deinit($resource); $decrypted_data = base64_decode($base64_decrypted_data); echo "decrypted data : " . $decrypted_data . "\n"; echo 'validate : ' . ($data == $decrypted_data ? 'true' : 'false') . "\n"; // モジュールを閉じる mcrypt_module_close($resource);出力結果は以下の通りです。
$ php crypt.php data : 小池さんはラーメン大好き encrypted data : ICO08auHD0ouWlCYnGXU1YsHzd4r2NEGLH+WmtijEPtyjvJlibeahccyQKs1dz95 decrypted data : 小池さんはラーメン大好き validate : true $