PHP 7中mcrypt加解密函数无法运行,IV生成代码疑有误怎么办?
解决PHP 7中Blowfish加解密函数失效的问题
首先,你的代码最大的问题是**mcrypt扩展在PHP 7.1及以上版本已经被官方弃用,PHP 7.2直接移除了这个扩展**——这就是函数无法正常运行的核心原因,哪怕没有抛出警告,底层的加密解密逻辑已经无法执行。另外你怀疑的IV生成部分确实也存在细节问题,下面给你两种可行的解决方案:
方案一:迁移到OpenSSL扩展(推荐,符合PHP现代标准)
OpenSSL是PHP官方主推的加密扩展,稳定性、安全性和兼容性都远优于已废弃的mcrypt。下面是适配Blowfish(对应OpenSSL的BF-CFB模式)的加解密实现:
function encrypt_data($key, $plain_text) { $plain_text = trim($plain_text); // 获取Blowfish CFB模式下的标准IV长度(固定8字节) $iv_length = openssl_cipher_iv_length('BF-CFB'); // 生成安全的随机IV(不要从key的哈希值生成,避免IV可预测的风险) $iv = openssl_random_pseudo_bytes($iv_length); // 执行加密,使用RAW_DATA模式保证输出是二进制原始内容 $cipher_text = openssl_encrypt( $plain_text, 'BF-CFB', $key, OPENSSL_RAW_DATA, $iv ); // 将IV和密文拼接后再base64编码(IV不需要保密,但解密时必须和加密时一致) return base64_encode($iv . $cipher_text); } function decrypt_data($key, $cipher_text_base64) { $cipher_text_raw = base64_decode($cipher_text_base64); $iv_length = openssl_cipher_iv_length('BF-CFB'); // 从编码内容中拆分出IV和实际密文 $iv = substr($cipher_text_raw, 0, $iv_length); $cipher_text = substr($cipher_text_raw, $iv_length); // 执行解密,参数和加密时保持一致 $plain_text = openssl_decrypt( $cipher_text, 'BF-CFB', $key, OPENSSL_RAW_DATA, $iv ); return trim($plain_text); }
关键改进点:
- 用
openssl_random_pseudo_bytes生成安全的随机IV,避免原方案中IV可预测的安全隐患 - 将IV与密文一起存储,解密时再拆分,确保加密解密使用完全一致的IV
- 采用PHP官方长期支持的OpenSSL扩展,兼容PHP7+及所有后续版本
方案二:修复原mcrypt代码(仅兼容PHP7.0及以下,不推荐)
如果你暂时只能在PHP7.0环境下运行代码,可以调整IV的生成逻辑来修复问题:
function encrypt_data($key, $plain_text) { $plain_text = trim($plain_text); $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CFB); // 注意md5的第二个参数设为true,返回二进制原始哈希值(而非十六进制字符串) $iv = substr(md5($key, true), 0, $iv_size); $c_t = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $plain_text, MCRYPT_MODE_CFB, $iv); return base64_encode($c_t); } function decrypt_data($key, $c_t) { $c_t = base64_decode($c_t); $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CFB); $iv = substr(md5($key, true), 0, $iv_size); $p_t = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $c_t, MCRYPT_MODE_CFB, $iv); return trim($p_t); }
原代码的问题:
你之前的md5($key)返回的是32位十六进制字符串,而mcrypt需要的是二进制格式的IV。直接截取字符串的字符数,会导致IV的实际二进制长度不符合要求;加上md5($key, true)后,返回的是16字节的二进制原始哈希值,这样截取的IV长度才完全匹配mcrypt的要求。
但必须强调:mcrypt已经被PHP官方彻底废弃,这个方案只是临时过渡方案,强烈建议尽快迁移到OpenSSL实现。
内容的提问来源于stack exchange,提问作者Matti Kiviharju
相关产品推荐
相关产品推荐

