mcrypt関数でデータを暗号化→復号化した時に、末尾にデータが付加されて元に戻らない場合がある、という事で簡単に実験。
サンプルのテキストファイルを作成する。
$ echo -n 'encrypt-me' > before.txt
中身を確認
$ cat before.txt encrypt-me
サンプルのテキストファイルをmcrypt関数で暗号化して復号化し、別のファイルへ出力するPHPを作成する。
$text = file_get_contents('before.txt'); // 暗号化したいデータ $key = 'secret_key'; $cipher = MCRYPT_RIJNDAEL_128; // 暗号化アルゴリズム:MCRYPT_BLOWFISH | MCRYPT_3DES | MCRYPT_RIJNDAEL_128 etc... $encrypt = mcrypt_encrypt($cipher, $key, $text, MCRYPT_MODE_ECB); $decrypt = mcrypt_decrypt($cipher, $key, $encrypt, MCRYPT_MODE_ECB); file_put_contents('after.txt', $decrypt);
暗号化→復号化して出力されたファイルを確認
$ cat after.txt encrypt-me
ファイルサイズを確認
$ ls -l before.txt after.txt -rw-rw-r-- 1 user user 16 3月 30 19:42 2014 after.txt -rw-rw-r-- 1 user user 10 3月 30 19:42 2014 before.txt
暗号化前は10バイト、暗号化して復号化したファイルは16バイトになっている。
odコマンドで内容を確認する
$ od -tx1 after.txt 0000000 65 6e 63 72 79 70 74 2d 6d 65 00 00 00 00 00 00 0000020
末尾に、6バイト分の \0(ヌル文字)が増えている。
blowfishやDES、AESなどの暗号を使った場合、データはブロックサイズの倍数に丸められる。
MCRYPT_RIJNDAEL_128 の場合、ブロックサイズは128bit=16Byteなので、データが16Byteの倍数に満たない場合にパディングされる。
パディングには、\0(ヌル文字)が使われる。
上記では、テキストファイルを暗号化/復号化してechoで表示したので、パディングされた事を意識しにくい。
docxなどのファイルだと、うまく開けなくなるので気が付く(docxの場合、ファイルを開く際に警告が表示され、修復すると開く事はできる)。
暗号化して保存した後、それを復号化するとファイルが開けなくなった場合、これが原因の可能性がある。
対策としては、復号化したデータの末尾にある「\0」を削除する。
rtrim関数で削除する文字を指定すると良い。
file_put_contents('after.txt', rtrim($decrypt, "\0"));
ここで第二引数を指定しないと、半角スペースも除去してしまうので注意。
なお、OpenSSL関数を利用すると、上記のようなパディングが自動的に処理されるため、trimする必要が無い。