由于 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");
PHP加解密算法使用 openssl 替换 mcrypt 扩展的一个小坑 by 桔子小窝 is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.