====== PHPでお手軽に暗号化、復号する - CodeBook.php ======
コメントと更新履歴は[[http://0-oo.net/log/category/php-tool-box/code-book/|Code Book Archive - ゼロと無限の間のログ]]へどうぞ。
{{php-tool-box:pencil.png|}}
PHPはphp-mcryptさえあればいろんな暗号アルゴリズムを使えるけど、いざやろうとすると意外に面倒。特に、Javaなど他のアプリやツールとやり取りするときとか。\\
IVやパディングについて考えるのは大したことではないと言えばそれまでだが、毎回チョコチョコ書くのはちょっと手間。パディングがPKCS#5の場合なんか特に。
なので手軽に暗号化と復号ができるクラスを作った。(要php-mcrypt。)
クラス名はサイモン・シンの力作、[[http://www.amazon.co.jp/gp/product/410215972X?ie=UTF8&tag=wiki03-22&linkCode=as2&camp=247&creative=7399&creativeASIN=410215972X|暗号解読]]にちなんで。;-)\\
この本によれば、PHPによる暗号化はCODEではなくCIPHERだそうだけれど。
===== ライセンス =====
[[http://0-oo.net/pryn/MIT_license.txt|MITライセンス]]で。\\
===== 使い方の例 =====
$key = '秘密の鍵';
$text = '秘密のメッセージ';
/* AES、CBC、Null文字でPAD */
$c1 = new CodeBook();
list($encrypted, $iv) = $c1->encrypt($key, $text); //暗号化
$decrypted = $c1->decrypt($key, $encrypted, $iv); //復号
echo $text . ' => ' . $decrypted; // => "秘密のメッセージ => 秘密のメッセージ"
echo '
';
echo var_dump($text === $decrypted); // => bool(true)
echo '
';
/* Blowfish、CBC、PKCS#5でPAD */
$c2 = new CodeBook(MCRYPT_BLOWFISH);
$padded = $c2->padPkcs5($text); //パディング
list($encrypted, $iv) = $c2->encrypt($key, $padded); //暗号化
$decryptedAndPadded = $c2->decrypt($key, $encrypted, $iv); //復号
$decrypted = $c2->trimPkcs5($decryptedAndPadded); //PADを除去
echo $text . ' => ' . $decrypted; // => "秘密のメッセージ => 秘密のメッセージ"
echo '
';
echo var_dump($text === $decrypted); // => bool(true)
echo '
';
/* RIJNDAEL256、ECB、スペースでPAD */
$c3 = new CodeBook(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$padded = $c3->pad($text, ' '); //パディング
list($encrypted) = $c3->encrypt($key, $padded); //暗号化
$decrypted = $c3->decrypt($key, $encrypted, null, ' '); //復号&PADを除去
echo $text . ' => ' . $decrypted; // => "秘密のメッセージ => 秘密のメッセージ"
echo '
';
echo var_dump($text === $decrypted); // => bool(true)
===== ソースコード =====
_cipher = $cipher;
$this->_mode = $mode;
}
/**
* 暗号化する
* IVを渡さない場合、ランダムなIVが生成される
* @param string $key 暗号鍵
* @param string $encryptee 暗号化するデータ
* @param string $iv (省略可)初期化ベクトル
* @return array hex化した暗号化済みデータと、hex化したIV
*/
public function encrypt($key, $encryptee, $iv = null) {
if (!$iv) {
$iv = $this->_getRandIV();
}
$bin = mcrypt_encrypt($this->_cipher, $key, $encryptee, $this->_mode, $iv);
return array(bin2hex($bin), bin2hex($iv));
}
/**
* 復号する
* mcrypt_encrypt()のデフォルトのパディング文字は"\0"(Null文字)
* @param string $key 復号鍵
* @param string $encrypted 暗号化されたデータ
* @param string $iv (省略可)hex化した初期化ベクトル(ECBでは不要)
* @param string $trimChar (省略可)除去するパディング文字
* @return string 復号したデータ
*/
public function decrypt($key, $encrypted, $iv = null, $trimChar = "\0") {
$bin = self::hex2bin($encrypted);
if ($iv) {
$iv = self::hex2bin($iv);
} else {
$iv = $this->_getRandIV(); //Warningを出さないためのダミーのIV
}
$decrypted = mcrypt_decrypt($this->_cipher, $key, $bin, $this->_mode, $iv);
if ($trimChar !== false) {
$decrypted = rtrim($decrypted, $trimChar);
}
return $decrypted;
}
/**
* ブロック長に合わせてパディングする
* @param string $data パディング対象のデータ
* @param string $padChar パディング文字
* @return string パディングしたデータ
*/
public function pad($data, $padChar) {
$size = $this->_getBlockSize();
return str_pad($data, ceil(strlen($data) / $size) * $size, $padChar);
}
/**
* PKCS#5でパディングする
* @param string $data パディング対象のデータ
* @return string パディングしたデータ
*/
public function padPkcs5($data) {
$size = $this->_getBlockSize();
$padLen = $size - (strlen($data) % $size);
return $data . str_repeat(chr($padLen), $padLen);
}
/**
* PKCS#5のパディングを除去する
* @param string $data PKCS#5でパディングされたデータ
* @return string パディングしたデータ
*/
public function trimPkcs5($data) {
return substr($data, 0, ord(substr($data, -1, 1)) * -1);
}
/**
* hex化したデータをバイナリに変換する
* @param string $hex hex化されたデータ
* @return string バイナリになったデータ
*/
public static function hex2bin($hex) {
return pack('H*', $hex);
}
private function _getRandIV() {
srand();
return mcrypt_create_iv($this->_getBlockSize(), MCRYPT_RAND);
}
private function _getBlockSize() {
return mcrypt_get_iv_size($this->_cipher, $this->_mode);
}
}