理解PHP的AES加密
这是一篇翻译的文章,原文在这里。为排版效果,有改动。
理解PHP的AES加密
这一段PHP代码给出了PHP的AES加密的一个基本轮廓
首先要了解的东西是下面几个常量:
MCRYPT_RIJNDAEL_128
MCRYPT_RIJNDAEL_192
MCRYPT_RIJNDAEL_256
你可能认为MCRYPT_RIJNDAEL_256意味着256位加密技术,但其实不是的。这三个选项定义的是Rijndael加密过程中所使用的块尺寸(block-size),而与密钥长度(即所谓的加密强度)完全无关。(后面会解释AES加密中的加密强度如何设置。)
Rijndael是一种块加密算法,它在一系列互不相关的数据块上分别进行操作。所以必须对数据进行补位操作,以保证被加密的数据长度正好是块尺寸的整数倍。(PHP使用NULL字节进行补位) 因此,如果你指定了MCRYPT_RIJNDAEL_256,你加密输出的数据长度一定是32字节(256位)的整数倍;如果你指定了MCRYPT_RIJNDAEL_128,你的加密输出则一定是16字节的整数倍。
注意:严格地说,AES和Rijndael并不完全等价(尽管实践中它们经常互换使用),因为Rijndael支持更大范围的块尺寸和密钥长度;AES使用固定的128位块尺寸,而密钥长度可以是128位、192位或者256位。Rijndael的块尺寸和密钥长度只要求使用32位的整数倍,最小128位,最大256位。
简而言之:如果你想和AES兼容,请永远使用MCRYPT_RIJNDAEL_128。
那么,第一步自然是初始化加密器对象
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
我们使用CBC模式(cipher-block chaining)进行加密。块加密模式详见这里。要使用CBC模式,需要提供一个初始向量(IV)。初始向量的长度必须和块尺寸相当(不一定等于密钥长度)。既然我们的块尺寸是128位,所以IV也应该是128位(16字节)。也就是说,对于AES加密方法,初始向量总是16字节,不论加密强度如何。
这里是验证初始向量长度的代码:
$iv_size = mcrypt_enc_get_iv_size($cipher);
printf("iv_size = %d\n",$iv_size);
那么在PHP中,如何进行256位而不是128位的AES加密?答案是使用32字节长的密钥。
譬如:
$key256 = '12345678901234561234567890123456';
$key128 = '1234567890123456';
我们的128位初始向量既可以用于128位加密,又可以用于256位加密。
$iv = '1234567890123456';
printf("iv: %s\n",bin2hex($iv));
printf("key256: %s\n",bin2hex($key256));
printf("key128: %s\n",bin2hex($key128));
这是要加密的原文:
$cleartext = 'The quick brown fox jumped over the lazy dog';
printf("plainText: %s\n\n",$cleartext);
mcrypt_generic_init
函数初始化的时候,需要同时提供密钥和初始向量。密钥的长度决定了我们是在进行128位、192位还是256位加密。这里我们先进行256位加密:
if (mcrypt_generic_init($cipher, $key256, $iv) != -1)
{
// 如果$cleartext的长度并非恰好是块尺寸的整数倍,PHP会用NULL字符进行补位
$cipherText = mcrypt_generic($cipher,$cleartext );
mcrypt_generic_deinit($cipher);
// 以十六进制显示最终结果:
printf("256-bit encrypted result:\n%s\n\n",bin2hex($cipherText));
}
这次我们进行128位加密:
if (mcrypt_generic_init($cipher, $key128, $iv) != -1)
{
// 如果$cleartext的长度并非恰好是块尺寸的整数倍,PHP会用NULL字符进行补位
$cipherText = mcrypt_generic($cipher,$cleartext );
mcrypt_generic_deinit($cipher);
// 以十六进制显示最终结果:
printf("128-bit encrypted result:\n%s\n\n",bin2hex($cipherText));
}
结果
你可以用下列测试来指导针对你自己的AES实现进行的测试
256位密钥CBC模式
IV = '1234567890123456'
(hex: 31323334353637383930313233343536)
Key = '12345678901234561234567890123456'
(hex: 3132333435363738393031323334353631323334353637383930313233343536)
PlainText:
'The quick brown fox jumped over the lazy dog'
CipherText(hex):
2fddc3abec692e1572d9b7d629172a05caf230bc7c8fd2d26ccfd65f9c54526984f7cb1c4326ef058cd7bee3967299e3
128位密钥CBC模式
IV = '1234567890123456'
(hex: 31323334353637383930313233343536)
Key = '1234567890123456'
(hex: 31323334353637383930313233343536)
PlainText:
'The quick brown fox jumped over the lazy dog'
CipherText(hex):
f78176ae8dfe84578529208d30f446bbb29a64dc388b5c0b63140a4f316b3f341fe7d3b1a3cc5113c81ef8dd714a1c99
谢谢分享,一直搞不懂aes256加密算法,看了文章终于明白了!