最初に決めておくこと
以下の情報は暗号化においても復号においても必要になる。全てが一致しなければ復号はできない。
- 鍵(以下 KEY)
- 暗号アルゴリズム(以下 CIPHER) … (1)
- ブロック暗号のモード(以下 MODE)… (2)
暗号化
KEY, CIPHER, MODE を用いてメッセージ $msg を暗号化する関数 encrypt は次のようになる(わざと冗長な書き方をしている)。
function encrypt($msg) { //初期化ベクトルを生成 $ivSize = mcrypt_get_iv_size(CIPHER, MODE); $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM); $dummyIV = str_repeat("x", $ivSize); //メッセージの暗号化 ... (3) $cryptMsg = mcrypt_encrypt(CIPHER, KEY, base64_encode($msg), MODE, $iv); //初期化ベクトルの暗号化 ... (4) $cryptIV = mcrypt_encrypt(CIPHER, KEY, base64_encode($iv), MODE, $dummyIV); return array($cryptMsg, $cryptIV); }
戻り値は次の2要素からなる配列である。
- 暗号化されたメッセージ
- 暗号化された初期化ベクトル
この2つが揃っていないと復号できないので、必ずペアで保存・転送すること。
復号
暗号化されたメッセージ $cryptMsg と暗号化された初期化ベクトル $cryptIV を KEY, CIPHER, MODE で復号する関数 decrypt は次のようになる。
function decrypt($cryptMsg, $cryptIV) { //ダミーの初期化ベクトルを生成 $ivSize = mcrypt_get_iv_size(CIPHER, MODE); $dummyIV = str_repeat("x", $ivSize); //初期化ベクトルの復号 $iv = _decryptSupport($cryptIV, $dummyIV); //メッセージの復号 $msg = _decryptSupport($cryptMsg, $iv); return $msg; } function _decryptSupport($cryptMsg, $iv) { //復号してNULLバイトを取り除いてbase64デコード ... (5) return base64_decode(rtrim( mcrypt_decrypt(CIPHER, KEY, $cryptMsg, MODE, $iv), "\0")); }
細かい説明
- (1) 暗号アルゴリズム
- 使用できる暗号アルゴリズムは libmcrypt のバージョンに依存するので、関数 mcrypt_list_algorithms で一覧表示して確認しておくこと。PHP Manual に定数として載っているもの(MCRYPT_RIJNDAEL_128 など)はあまり当てにならないので、文字列で指定した方が良い。どのアルゴリズムを使うべきか分からなければ「AES」を使えば良い(…と『暗号技術入門』に書いてあった)。AES を使用したい場合は rijndael-128 を指定する。rijndael-192 や rijndael-256 はブロック長が異なるため、「AES」の規格には合致しないので注意。
- (2) ブロック暗号のモード
- これも PHP 定数で指定するよりは mcrypt_list_modes で一覧表示して文字列として指定した方が良い。どのモードを使うべきか分からなければ「CBCモード」か「CTRモード」を使えば良い(…とこれまた『暗号技術入門』に書いてあった)。すなわち cbc か ctr を指定する。
- (3) 暗号化の際の base64 エンコード
- 暗号化の際に NULL でパディングされる場合があるので、事前に base64 エンコードしておく。
- (4) 初期化ベクトルの暗号化
- 初期化ベクトルの暗号化については先日のエントリを参照。
- (5) 復号の際の NULL バイト除去
- 暗号化の際にパディングされた NULL は復号後もそのまま残されるので、base64 デコードする前に rtrim で NULL を取り除いていておく。もっとも、少なくとも PHP 5.2.9 の base64_decode 関数は NULL を文字列終端と見なす(いわゆる”バイナリセーフでは無い”関数)ので、今のところは取り除かなくても問題ない。
参考
- PHP: Mcrypt – Manual
- 各ページの User Contributed Notes にも有用な情報がある
- 新版暗号技術入門 秘密の国のアリス (結城浩)
- 暗号についての知識は、ほぼ全てこの書籍から得た
[...] PHP + mcrypt の場合と違って、鍵や初期化ベクトルを直接設定する必要はない(不可能というわけでは無い)。代わりに pkcs5_keyivgen メソッドを使って、パスワードとソルトから鍵と初期化ベクトルを生成する。 [...]
[...] 5.2以前でも使用できるmcryptについてはこちら。 PHP 5.3でopensslモジュールの機能が拡張され、共通鍵暗号による暗号化が利用可能になった。同時に待望の疑似乱数生成器も用意された。これで今までmcryptが使用できなかったWindowsでも、暗号学的強度を持った乱数が生成できる(実際に試していないが、OpenSSLはWindowsのCryptAPIから乱数を得ている)。 まだマニュアルにも詳しい情報が載っていないので、ソースを読みながら使い方を探ってみた。以下はphp-5.3.3のソースに基づく。ただしコミットログを見る限り仕様も機能もまだ安定しているとは言いがたいので、実際に使用するにはもう少し様子を見た方が良いかもしれない。 暗号化する際に決めておくべきこと: [...]