SOFTELメモ

Softel Inc.

【php】文字列を暗号化したり、元の文字列に戻したりする

問題

phpで文字列を暗号化して、元の文字列に戻せますか。

php-logo

答え

ハッシュを生成するのではなくて(md5,sha)、暗号化、復号化をする場合はMcrypt関数が使える。OpenSSL関数もいいらしい。

Mcrypt関数

mcrypt_cbcやmcrypt_cfbではなく、暗号化に mcrypt_generic()、復号化にmdecrypt_generic() を使えとのことなので、そのようにしてみる。

<?php
/* データ */
$key = '長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵';
$plain_text = '暗号化したいデータ';

/* モジュールをオープンし、IV を作成 */ 
$td = mcrypt_module_open('des', '', 'ecb', '');
$key = substr($key, 0, mcrypt_enc_get_key_size($td));
$iv_size = mcrypt_enc_get_iv_size($td);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

/* 暗号化ハンドルを初期化 */
if (mcrypt_generic_init($td, $key, $iv) != -1) {

	/* データを暗号化 */
	$c_t = mcrypt_generic($td, $plain_text);
	mcrypt_generic_deinit($td);

	/* 復号のため、バッファを再度初期化 */
	mcrypt_generic_init($td, $key, $iv);
	$p_t = mdecrypt_generic($td, $c_t);

	/* 後始末 */
	mcrypt_generic_deinit($td);
	mcrypt_module_close($td);
}

/* 結果 */
var_dump($plain_text, $c_t, $p_t);

/* 元の文字と比較する場合 */
if (strncmp($p_t, $plain_text, strlen($plain_text)) == 0) {
	echo 'ok';
} else {
	echo 'error';
}

結果を確認すると以下のようになっている。

string(27) "暗号化したいデータ"
string(32) mcrypt-result バイナリデータ(読めない)
string(32) "暗号化したいデータ"
ok

マニュアルに「データのパディングが行われるため、返される文字列の長さは暗号化前の文字列よりも長くなる可能性があることに 注意してください。」と書いてあるとおり、復号した文字は元に戻っているように見えて文字数が多いので、0x00でパディングされている場合はtrimしたり、暗号化前の文字列の長さで切って比較するなどが必要。


OpenSSL関数

McryptよりOpenSSLの暗号処理の方がものすごく高速らしい。ソースも短い!

<?php

$key = '長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵長い鍵';
$plain_text = '暗号化したいデータ';

//openssl
$c_t = openssl_encrypt($plain_text, 'AES-128-ECB', $key);
$p_t = openssl_decrypt($c_t, 'AES-128-ECB', $key);
var_dump($plain_text, $c_t, $p_t);

結果は以下のとおり。

string(27) "暗号化したいデータ"
string(44) "iLL7OnzW/wDohKDQmIqNekoseIrcUP2u5T2XctmTnto="
string(27) "暗号化したいデータ"

OpenSSL関数が使える環境ではこちらの方が簡単そう。

関連するメモ

コメント