PHPで暗号化と復号化

暗号化と復号化の概要

概して復号化が可能な暗号化のアルゴリズムは比較的軟弱でありまして、パスワード認証などは、基本的には不可逆性のアルゴリズムを使った方が懸命です。が、時として可逆性の暗号化が必要になる場合もあるということで、ちょっと紹介。
PHPで可逆性(復号化できる)暗号化では、そもそもの暗号化の関数を、
暗号化で、mcrypt_generic();
復号化で、mdecrypt_generic();
という2つの関数を使うことになります。これらは、/usr/lib/mcrypt-modesとして実装されているので、あるかどうか一応phpinfo()で確認した方がよいかもです。(libmcrypt-2.4.x以降になります。)また、これら一連の文脈の中で使わないと機能しないので、その流れをメモしておきます。
libmcrypt
まず、「暗号化 <=> 復号化」する際の行き来にはkeyを使います。このkeyがないとこれらのやりとりができないというわけです。仮にこの暗号化&復号化のアルゴリズムとkeyが盗まれちゃったら全部解読されてしまうということです。逆にこの時にkeyを変えてしまえば復号化が不可能になってしまうので安全です。というものです。これらのkeyも生で使わないでmd5で暗号化しておく。

mcrypt_module_open()でオープンモードを選択して、mcrypt_module_close()でクローズします。なんかよくある感じではありますが、これらの関数でリソースを取得して作業する感じです。
その次に、keyのサイズを取得してそのサイズと乱数でもってIVを発行(mcrypt_create_iv)します。
リソース、key、IVで一度関数の初期化をエラーチェックをしてから、最後に暗号化(mcrypt_generic)します。こちら暗号化した上にBase64エンコードします。これやらないとテキストにならないのです。

mcrypt_genericで暗号化

Sample
<?php

# Input Password
$password = 'Honehone69';

# Decrypt key
$decrypt_key = 'UNKO';

#-----------
# 暗号化開始
#-----------
print 'Password: '.$password."<br>";
print 'Key: '.$decrypt_key."<br>";

$key = md5($decrypt_key);
print 'md5-key: '.$key."<br>";

# 暗号化モジュール使用開始
//$resource = mcrypt_module_open('des', '', 'ecb', '');
//$resource = mcrypt_module_open('rijndael-256', '', 'ecb', '');
//$resource = mcrypt_module_open(MCRYPT_DES, '',MCRYPT_MODE_ECB, '/usr/lib/mcrypt-modes');
$resource = mcrypt_module_open('tripledes', '', 'ecb', '');

$key = substr($key, 0, mcrypt_enc_get_key_size($resource));
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($resource), MCRYPT_RAND);

# 暗号化モジュール初期化
if (mcrypt_generic_init($resource, $key, $iv) < 0) {
exit('error.');
}

# データを暗号化
//$crypted_password_raw = mcrypt_generic($resource, $password);
$crypted_password = base64_encode(mcrypt_generic($resource, $password));

//print 'Crypted Password_raw: '.$crypted_password_raw."<br>";
print 'Crypted Password: '.$crypted_password."<br>";

# 暗号化モジュール使用終了
mcrypt_generic_deinit($resource);
mcrypt_module_close($resource);

?>
ちょっと私もよくわからないのが、mcrypt_module_open()モードで私のPHP環境ではいろいろなモードでオープンできました。それぞれのモードで暗号化の長さもちょっと違ってくるのでいろいろ試してみてください。任意の文字列を渡すやり方と定数を渡すやり方といろいろあるみたいです。PHPの公式ドキュメントのチュートリアルでは、rijndael-256のecbモードを設定しているようです。こちらでやると暗号化後の文字列が一番長くなりました。コメントアウトしてあるので、これらの中から1つだけ使えばよいです。

//$resource = mcrypt_module_open('des', '', 'ecb', '');
//$resource = mcrypt_module_open('rijndael-256', '', 'ecb', '');
//$resource = mcrypt_module_open(MCRYPT_DES, '',MCRYPT_MODE_ECB, '/usr/lib/mcrypt-modes');
$resource = mcrypt_module_open('tripledes', '', 'ecb', '');

mdecrypt_genericで復号化

復号化も同じ文脈で行います。違うのはmcrypt_generic(暗号化)をmdecrypt_generic(復号化)するところです。Sample
<?php

# Crypted Password
$crypted_password = '1jw5fq4ikSmMJUTBsHi8cEC4gBU3CLXSqewqHKY7WH8=';

# Decrypt key
$decrypt_key = 'UNKO';

#--------
# 復号化
#--------
print 'Crypted Password: '.$crypted_password."<br>";
print 'Key: '.$decrypt_key."<br>";

$hashkey = md5($decrypt_key);
$hashkey2 = md5($decrypt_key);

# 復号化モジュール使用開始
//$resource = mcrypt_module_open('des', '', 'ecb', '');
$resource = mcrypt_module_open('rijndael-256', '', 'ecb', '');
//$resource = mcrypt_module_open(MCRYPT_DES, '',MCRYPT_MODE_ECB, '/usr/lib/mcrypt-modes');
//$resource = mcrypt_module_open('tripledes', '', 'ecb', '');

$hashkey2 = substr($hashkey2, 0, mcrypt_enc_get_key_size($resource));
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($resource), MCRYPT_RAND);

# 復号化モジュール初期化
if (mcrypt_generic_init($resource, $hashkey, $iv) < 0) {
exit('error.');
}

$text = mdecrypt_generic($resource, base64_decode($crypted_password));
mcrypt_generic_deinit($resource);
mcrypt_module_close($resource);

print 'Reversed Password: '.$text."<br>¥n";

?>
Key自体がいわゆるパスワードみたいな感じで機能しているので、そこそこ安全かなと。といいつつも世間では復号化するようなシステムは殆ど見かけないので、プライベートとか小規模なグループで使うのがよいのかなと思います。