由于 PHP 7.2 不再支持 mcrypt,因此需要将 mcrypt 替换为 openssl。
但是在替换发现,php 的 openssl 和 mcrypt 实现有一些不同,有几个坑需要注意。
mcrypt 中的 RIJNDAEL_128 算法是 AES 算法的超集,RIJNDAEL_128 的 128 指的是 Block Size,而 AES-128 中的 128 是 Key Size。因此,同是 RIJNDAEL_128 算法,如果你使用的 Key 是 128 位的(16 个字符)那就等同 AES-128。如果 Key 是 192 位的(24 个字符),那就等同与 AES-192。如果 Key 是 256 位的(32 个字符),则等同与 AES-256
如果使用 RIJNDAEL_256,则无法对应到 AES 算法。因为 AES 固定了 Block Size 是 128,没有 256 的选择
php 的 openssl 实现的 AES 算法,只有 PKCS#7 padding 和 no padding 两个选择,而 mcrypt 默认是 zero padding。因此,如果原先没有手动处理 padding,则切换到 openssl 的时候需要启用 no padding 并手动处理 padding。
一些函数的替换:mcrypt_get_iv_size 替换为 openssl_cipher_iv_length ,mcrypt_create_iv 替换为 openssl_random_pseudo_bytes 。
修改前后代码如下:<?php
define('ENCRYPT_METHOD', 'AES-256-CBC');
define('IV_SIZE', openssl_cipher_iv_length(ENCRYPT_METHOD));
function encrypt_mcrypt($payload, $key)
{
// 初始化 IV
$iv = openssl_random_pseudo_bytes(IV_SIZE);
// 调用加密
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $payload, MCRYPT_MODE_CBC, $iv);
// 拼接 IV 和 密文
$combo = $iv . $crypt;
// 编码拼接后的密文
$garble = base64_encode($combo);
return $garble;
}
function decrypt_mcrypt($garble, $key)
{
// 解码密文
$combo = base64_decode($garble);
// 根据 IV SIZE 提取 IV
$iv = substr($combo, 0, IV_SIZE);
// 获取剩余密文
$crypt = substr($combo, IV_SIZE);
// 解密
$payload = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypt, MCRYPT_MODE_CBC, $iv);
return $payload;
}
function encrypt_openssl($payload, $key)
{
// 初始化 IV
$iv = openssl_random_pseudo_bytes(IV_SIZE);
// 对密文进行 padding, 16 = 128 / 8
if (strlen($payload) % 16) {
$payload = str_pad(
$payload,
strlen($payload) + 16 - strlen($payload) % 16,
"\0"
);
}
// 加密
$encryptedMessage = openssl_encrypt($payload, ENCRYPT_METHOD, $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
// 编码,拼接 IV
return base64_encode($iv . $encryptedMessage);
}
function decrypt_openssl($garble, $key)
{
// 解码密文
$raw = base64_decode($garble);
// 根据 IV SIZE 提取 IV
$iv = substr($raw, 0, IV_SIZE);
// 获取剩余密文
$data = substr($raw, IV_SIZE);
// 解密
return openssl_decrypt($data, ENCRYPT_METHOD, $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
}
$key = md5("password");
echo (decrypt_openssl(encrypt_mcrypt("4db8c44de8f16b4f0c39ef3b38d47c6bdd000082b3b628ee25c20b308d02cf29", $key), $key) . "\n");
echo (decrypt_mcrypt(encrypt_openssl("4db8c44de8f16b4f0c39ef3b38d47c6bdd000082b3b628ee25c20b308d02cf29", $key), $key) . "\n");