对称加密算法是指,数据发信方将明文(原始数据)和密钥一起经过加密处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若要解读原文,则需要使用加密密钥及相同算法的逆算法对密文进行解密,使其恢复成可读明文。对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高,适用于加密大量数据的场合。常用的算法有DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK、AES等。
PHP中如果需要使用对称加密算法,则需要mcrypt扩展的支持。PHP的mcrypt扩展提供了强大的加密解密方法,支持19种加密算法和8种加密模式,具体可以通过函数mcrypt_list_algorithms()和mcrypt_list_modes()来显示。
<?php
$type_list = mcrypt_list_algorithms(); //mcrypt支持的加密算法列表
$mode_list = mcrypt_list_modes(); //mcrypt支持的加密模式列表
print_r($type_list);
print_r($mode_list);
?>
使用DES方式加密的代码如下。
<?php
$auth_key = 'safe_key';
$salt = '!@#$%';
$content = 'Hello World';
$td = mcrypt_module_open(mcrypt_des,'','ecb',''); //使用mcrypt_des算法ecb模式
$iv_size = mcrypt_enc_get_iv_size($td); //设置初始向量大小
$iv = mcrypt_create_iv($iv_size,mcrypt_rand); //创建初始向量
$key_size = mcrypt_enc_get_key_size($td); //返回所支持的最大密钥长度(以字节计算)
$key = substr(md5($auth_key.salt),0,$key_size);
mcrypt_generic_init($td, $key, $iv); //初始化
$secret = mcrypt_generic($td, $content); //加密并返回加密后的内容
echo base64_encode($secret);
mcrypt_generic_deinit($td);
mcrypt_module_close($td); //结束
?>
使用DES方式解密的代码如下。
<?php
$auth_key = 'safe_key';
$salt = '!@#$%';
$secret = 'nzPa0jPaaNca+Yty/HG4PA==';
$td = mcrypt_module_open(mcrypt_des,'','ecb',''); //使用mcrypt_des算法ecb模式
$iv_size = mcrypt_enc_get_iv_size($td); //设置初始向量大小
$iv = mcrypt_create_iv($iv_size,mcrypt_rand); //创建初始向量
$key_size = mcrypt_enc_get_key_size($td); //返回所支持的最大密钥长度(以字节计算)
$key = substr(md5($auth_key.salt),0,$key_size);
mcrypt_generic_init($td, $key, $iv); //初始化
$content = mdecrypt_generic($td, base64_decode($secret)); //解密并返回内容
echo $content;
mcrypt_generic_deinit($td);
mcrypt_module_close($td); //结束
?>
AES是Advanced Encryption Standard(高级加密标准)的缩写,在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(National Institute of Standards and Technology,NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。至2006年,高级加密标准已经成为对称密钥加密中最流行的算法之一。
AES目前有五种加密模式。
(1)电码本(Electronic Codebook,ECB)模式。
(2)密码分组链接(Cipher Block Chaining,CBC)模式。
(3)计数(Counter,CTR)模式。
(4)密码反馈(Cipher FeedBack,CFB)模式。
(5)输出反馈(Output FeedBack,OFB)模式。
在PHP的mcrypt扩展中,rijndael-128、rijndael-192、rijndael-256就是AES加密,三种分别使用不同的数据块和密钥长度进行加密。
在AES的ECB模式中,一般是16字节为一块,然后对这一整块进行加密,如果输入的字符串不够16字节,就需要补位。
使用AES-ECB方式进行加密数据的代码如下。
<?php
$auth_key = 'safe_key';
$salt = '!@#$%';
$content = 'Hello World';
$td= mcrypt_module_open(mcrypt_rijndael_128,'',mcrypt_mode_ecb,'');
$iv_size = mcrypt_enc_get_iv_size($td);
$iv = mcrypt_create_iv($iv_size,mcrypt_rand);
$key_size = mcrypt_enc_get_key_size($td);
$key = substr(md5($auth_key.salt),0,$key_size);
mcrypt_generic_init($td, $key, $iv);
$block=mcrypt_get_block_size(mcrypt_rijndael_128,mcrypt_mode_ecb);
$pad=$block-(strlen($content) % $block);
$content.=str_repeat(chr($pad),$pad); // 补齐不足16字符的位数内容
$secret = mcrypt_generic($td, $content);
echo bin2hex($secret);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
?>
使用AES-ECB方式进行解密数据如下。
<?php
$auth_key = 'safe_key';
$salt = '!@#$%';
$secret = 'd62d9e7e8ad4b0f044e4bd971f695a58';
$td= mcrypt_module_open(mcrypt_rijndael_128,'',mcrypt_mode_ecb,'');
$iv_size = mcrypt_enc_get_iv_size($td);
$iv = mcrypt_create_iv($iv_size,mcrypt_rand);
$key_size = mcrypt_enc_get_key_size($td);
$key = substr(md5($auth_key.salt),0,$key_size);
mcrypt_generic_init($td, $key, $iv);
$content=mdecrypt_generic($td,hex2bin($secret));
$len=strlen($content);
$ch=ord($content[$len-1]);
echo substr($content,0,$len-$ch);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
?>
AES的CBC加密模式,需要添加初始化向量(IV),默认是16个0。由于是分组加密,因此下一组的IV就用前一组的加密的密文来充当。CFB、OFB模式类似,只不过更复杂,从而破解难度更大。
使用AES-CBC方式进行加密解密数据的代码如下。
<?php
$auth_key = 'safe_key';
$salt = '!@#$%';
$content = 'Hello World';
$td= mcrypt_module_open(mcrypt_rijndael_128,'',mcrypt_mode_cbc,'');
$iv_size = mcrypt_enc_get_iv_size($td);
$iv = mcrypt_create_iv($iv_size,mcrypt_rand);
$key_size = mcrypt_enc_get_key_size($td);
$key = substr(md5($auth_key.salt),0,$key_size);
mcrypt_generic_init($td, $key, $iv);
$secret = mcrypt_generic($td, $content); // 加密数据
echo bin2hex($secret);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$td= mcrypt_module_open(mcrypt_rijndael_128,'',mcrypt_mode_cbc,'');
mcrypt_generic_init($td, $key, $iv);
echo mdecrypt_generic($td,$secret); // 解密数据
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
?>