php:AES加密

常用的加密分为对称加密和非对称加密,对称加密就是发送方和接收方都用同一个秘钥进行加密解密,而非对称加密则使用一对公钥和私钥来进行加密,发送发只需要用接收方的公钥将数据加密即可。

AES是一种常见的对称加密算法,英语:Advanced Encryption Standard,又称Rijndael加密,它是一种分块加密方法,换句话说就是将明文块分成一组组小部分然后进行加密再组合,而根据分组大小可分为:AES-128,AES-196,AES-256三种,对应的分组大小分别是128bit,196bit,256bit。在网上转来的一张图:

而如何将这些明文块进行加密组合,又分为四种模式:ECB、CBC、CFB、OFB,除了第一种模式,后面三种模式都需要一个初始向量iv来辅助加密。初始向量的大小也是同区块大小保持一致,是个固定长度的随机字串,初始向量只是为了给加密算法提供一个可用的种子。

还有一点是,如果需要加密的源数据长度不是分组大小的整数倍,那么就需要对数据进行填充,一般的填充算法有PKSC5PKSC7填充算法。举个例子,如果源数据大小是10bytes,如果进行分组,还需要6bytes才能满足分组的要求。那么只需要在后面补上6个6即可:

x x x x x x x x x x 6 6 6 6 6 6

如果刚好不用填充,还需要再补齐区块大小个字节,这么做是为了在去除填充数据时,可以准确无误。

php中有一个mcrypt扩展,使用它提供的加密函数即可进行我们需要的对称加密。

mcrypt_encrypt(): 该方法接受5个参数,分别是算法名称,密钥,待加密源数据,加密模式,以及初始向量。最后一个参数,如果是ECB模式则不是必须的。需要注意的是如果密钥和初始向量的长度不是区块大小的长度,php会返回false。
mcrypt_decrypt(): 参数同加密方法一样,只不过源数据改成已加密后的数据。

php会使用 ‘\0 自动填充数据,你也可以使用自己的填充算法。

下面有一个简单的加密类,是参考网上的代码稍微修改的。使用的是PKSC7填充。

class Aes {
	private $init_key;

	private $auto_padding;

	private $aes_bytes;

	private $block_size;

	private $key;

	private $iv;

	private $map = [
		'128' => MCRYPT_RIJNDAEL_128,
		'196' => MCRYPT_RIJNDAEL_192,
		'256' => MCRYPT_RIJNDAEL_256,
	];

	public function __construct($init_key, $aes_bytes, $auto_padding){
		$this->init_key = $init_key;
		$this->auto_padding = $auto_padding;
		$this->aes_bytes = $aes_bytes;
		$this->block_size = mcrypt_get_block_size($this->map[$this->aes_bytes], MCRYPT_MODE_CBC);

		$this->key = substr( hash('sha256',$this->init_key), 0, $this->block_size );
		$this->iv  = mcrypt_create_iv( mcrypt_get_iv_size($this->map[$this->aes_bytes], MCRYPT_MODE_CBC) );
	}

	//CBC mode
	public function encrypt($data){
		$data = trim($data);
		if(!$this->auto_padding) {
			$data = $this->addPKCS7Padding($data);
		}
		$encrypt = mcrypt_encrypt($this->map[$this->aes_bytes], $this->key, $data, MCRYPT_MODE_CBC, $this->iv);
		return base64_encode( $encrypt );
	}

	public function decrypt($aes_data){
		$aes_data = base64_decode($aes_data);	
		$decrypt =  mcrypt_decrypt($this->map[$this->aes_bytes], $this->key, $aes_data, MCRYPT_MODE_CBC, $this->iv);
		return $this->stripPKCS7Padding( trim($decrypt) );
	}

	// padding
	public function addPKCS7Padding($data){
		$data = trim($data);
		$pad = $this->block_size - (strlen($data) % $this->block_size);
		if( $pad <= $this->block_size ) {
			$padStr = chr($pad) ;
			$data .= str_repeat($padStr, $pad);
		}
		return $data;
	}

	public function stripPKCS7Padding($data){
		$num = ord(substr($data,-1));
		return substr($data,0,-$num);
	}
}
$aes = new Aes('sama','128',false);
$en = $aes->encrypt('helloworldmydear');
$de = $aes->decrypt($en);

测试可行。

Leave a comment

电子邮件地址不会被公开。 必填项已用*标注