ゼロと無限の間に

フリーでオープンソースなJavaScriptとかPHPとか。

ユーザ用ツール

サイト用ツール


サイドバー

何かありましたら、メールで連絡いただくか、ブログのどこかにコメント入れてくださいね ^_^

Menu

ゼロと無限の間に

はじめに

作った主なサイト

作った主な便利ツール(無料)

ログ (Blog)

php-tool-box:code-book

PHPでお手軽に暗号化、復号する - CodeBook.php

コメントと更新履歴はCode Book Archive - ゼロと無限の間のログへどうぞ。

PHPはphp-mcryptさえあればいろんな暗号アルゴリズムを使えるけど、いざやろうとすると意外に面倒。特に、Javaなど他のアプリやツールとやり取りするときとか。
IVやパディングについて考えるのは大したことではないと言えばそれまでだが、毎回チョコチョコ書くのはちょっと手間。パディングがPKCS#5の場合なんか特に。

なので手軽に暗号化と復号ができるクラスを作った。(要php-mcrypt。)

クラス名はサイモン・シンの力作、暗号解読にちなんで。;-)
この本によれば、PHPによる暗号化はCODEではなくCIPHERだそうだけれど。

ライセンス

使い方の例

<?php
require('CodeBook.php');
 
$key = '秘密の鍵128b';
$text = '秘密のメッセージ';
 
 
/* AES(RIJNDAEL128)、CBC、PKCS#5でPAD */
$codeBook = new CodeBook();
list($encrypted, $iv) = $codeBook->encrypt($key, $text);	//暗号化
$decrypted = $codeBook->decrypt($key, $encrypted, $iv);	//復号
 
// => "秘密のメッセージ => (略) => 秘密のメッセージ"
echo $text . ' => ' . $encrypted . ' => ' . $decrypted;
echo '<br />';
echo var_dump($text === $decrypted);	// => bool(true)
 
echo '<hr />';
 
 
/* RIJNDAEL256、ECB、Null文字でPAD */
$codeBook = new CodeBook(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB, CodeBook::PAD_NULL);
list($encrypted) = $codeBook->encrypt($key, $text);	//暗号化(ECBはIV不要)
$decrypted = $codeBook->decrypt($key, $encrypted);	//復号
 
// => "秘密のメッセージ => (略) => 秘密のメッセージ"
echo $text . ' => ' . $encrypted . ' => ' . $decrypted;
echo '<br />';
echo var_dump($text === $decrypted);	// => bool(true)
 
echo '<hr />';
 
 
/* Blowfish、CBC、スペースでPAD */
$codeBook = new CodeBook(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC, CodeBook::PAD_SPACE);
list($encrypted, $iv) = $codeBook->encrypt($key, $text);	//暗号化
$decrypted = $codeBook->decrypt($key, $encrypted, $iv);	//復号
 
// => "秘密のメッセージ => (略) => 秘密のメッセージ"
echo $text . ' => ' . $encrypted . ' => ' . $decrypted;
echo '<br />';
echo var_dump($text === $decrypted);	// => bool(true)

ソースコード

<?php
/**
 *  CodeBook.php
 *  @version   0.2.1
 *  @see       http://0-oo.net/sbox/php-tool-box/code-book
 *  @copyright 2009-2011 dgbadmin@gmail.com
 *  @license   http://0-oo.net/pryn/MIT_license.txt (The MIT license)
 */
class CodeBook {
	/** PKCS#5でパディング */
	const PAD_PKCS5 = 'PAD_PKCS5';
	/** Null文字でパディング */
	const PAD_NULL = "\0";
	/** スペースでパディング */
	const PAD_SPACE = ' ';
 
	private $_cipher;
	private $_mode;
	private $_padding;
 
	/**
	 *  コンストラクタ
	 *  デフォルトは、AES(ブロック長128bit)、CBCモード、PKCS#5でパディング
	 *  @param  string  $cipher     (省略可)暗号アルゴリズム
	 *  @param  string  $mode       (省略可)暗号モード
	 *  @param  string  $padding    (省略可)パディング方法(このクラスの定数 or 文字)
	 *  @see http://www.php.net/manual/ja/mcrypt.ciphers.php
	 *  @see http://www.php.net/manual/ja/mcrypt.constants.php
	 */
	public function __construct($cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC, $padding = self::PAD_PKCS5) {
		$this->_cipher = $cipher;
		$this->_mode = $mode;
		$this->_padding = $padding;
	}
	/**
	 *  暗号化する
	 *  初期化ベクトル(IV)を渡さない場合、ランダムな初期化ベクトルを生成する
	 *  @param  string  $key        暗号鍵
	 *  @param  string  $encryptee  暗号化するデータ
	 *  @param  string  $iv         (省略可)初期化ベクトル(ECBでは不要)
	 *  @return array   hex化した暗号化済みデータと、hex化した初期化ベクトル(IV)
	 */
	public function encrypt($key, $encryptee, $iv = null) {
		$this->_checkKeySize($key);
 
		if (!$iv) {
			$iv = $this->_getRandIv();
		}
 
		if ($this->_padding === self::PAD_PKCS5) {
			$encryptee = $this->padPkcs5($encryptee);
		} else {
			$encryptee = $this->pad($encryptee, $this->_padding);
		}
 
		$bin = mcrypt_encrypt($this->_cipher, $key, $encryptee, $this->_mode, $iv);
		return array(bin2hex($bin), bin2hex($iv));
	}
	/**
	 *  復号する
	 *  @param  string  $key        暗号鍵
	 *  @param  string  $encrypted  暗号化されてhex化されたデータ
	 *  @param  string  $iv         (省略可)hex化した初期化ベクトル(ECBでは不要)
	 *  @return string  復号したデータ
	 */
	public function decrypt($key, $encrypted, $iv = null) {
		$this->_checkKeySize($key);
		$bin = $this->hex2bin($encrypted);
 
		if ($iv) {
			$iv = $this->hex2bin($iv);
		} else {
			$iv = $this->_getRandIv();  //Warningを出さないためのダミーのIV
		}
 
		$decrypted = mcrypt_decrypt($this->_cipher, $key, $bin, $this->_mode, $iv);
 
		if ($this->_padding === self::PAD_PKCS5) {
			$decrypted = $this->trimPkcs5($decrypted);
		} else {
			$decrypted = rtrim($decrypted, $this->_padding);
		}
 
		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化したデータをバイナリに変換する(bin2hex()の反対)
	 *  @param  string  $hex    hex化されたデータ
	 *  @return string  バイナリになったデータ
	 */
	public function hex2bin($hex) {
		return pack('H*', $hex);
	}
	/**
	 *  暗号鍵の長さをチェックする
	 *  @param  string  $key    暗号鍵
	 *  @throws Exception   長さが不正な場合に例外を投げる
	 */
	private function _checkKeySize($key) {
		$sizes = mcrypt_module_get_supported_key_sizes($this->_cipher);
 
		//可変の場合は空なのでチェックしない
		if ($sizes && !in_array(strlen($key), $sizes)) {
			throw new Exception("Invalid key length ($key)");
		}
	}
	/**
	 *  ランダムな初期化ベクトル(IV)を生成する
	 *  @return string  生成した初期化ベクトル
	 */
	private function _getRandIv() {
		srand();
		return mcrypt_create_iv($this->_getBlockSize(), MCRYPT_RAND);
	}
	/**
	 *  暗号アルゴリズムと暗号モードに応じたブロックサイズを取得する
	 *  @return integer ブロックサイズ
	 */
	private function _getBlockSize() {
		return mcrypt_get_iv_size($this->_cipher, $this->_mode);
	}
}
php-tool-box/code-book.txt · 最終更新: 2011/09/16 03:56 by dgbadmin