关于mcrypt_encrypt和openssl_encrypt加密结果不一致的解决
最近想将php5.6
升级到php7.2
,翻阅兼容性文档,发现mcrypt
已被移除,官方建议用openssl
代替,原先项目用到mcrypt,于是进行替换测试。
$key = '1234567890123456'; //16字节
$iv = '1234567890123456'; //16字节
$str = 'abcdefg测试密文......';
原加密代码:
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_CBC, $iv);
var_dump(base64_encode($encrypted)) ;
替换代码
$encrypted = openssl_encrypt($str, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $iv);
var_dump(base64_encode($encrypted)) ;
同样的key和iv结果竟然不同
string(44) "iOjsba+z8aP9JBLGzl5qyby3doyqLbgmggExPt6Z8Go="
string(44) "iOjsba+z8aP9JBLGzl5qyZAa7Usw/KSBWndy+ypyPDs="
翻阅大量文档,得出点结论
1.mcrypt加密前默认对原文进行padding,padding方式是用0填充
2.openssl的option有三个选项:
OPENSSL_RAW_DATA
会用PKCS#7进行补位
OPENSSL_ZERO_PADDING
看字面意思,是用0填充,但是测试并不起作用,有了解的希望解答一下
OPENSSL_NO_PADDING
不填充,需要手动填充
3.如果要让openssl的加密结果和原先的mcrypt一样,必须要手动用0填充,然后再用openssl加密
再次测试,在openssl_encrypt前加上填充过程
$str_padded = $str;
if (strlen($str_padded) % 16) {
$str_padded = str_pad($str_padded,strlen($str_padded) + 16 - strlen($str_padded) % 16, "\0");
}
$encrypted = openssl_encrypt($str_padded, 'aes-128-cbc', $key, OPENSSL_NO_PADDING , $iv);
var_dump( base64_encode($encrypted));
结果一致,如下
string(44) "iOjsba+z8aP9JBLGzl5qyby3doyqLbgmggExPt6Z8Go="
解密就简单的多了,直接把openssl的option设为OPENSSL_NO_PADDING
就可以了
$decrypted =openssl_decrypt( base64_decode($str) , 'aes-128-cbc', $key, OPENSSL_NO_PADDING, $iv);
var_dump( rtrim( rtrim( $decrypted,chr(0) ), chr(7) ) );
结尾要去除填充字符'\0'
和'\a'
。
'\a'
是为了兼容用OPENSSL_RAW_DATA
加密的结果。