PHP项目MCRYPT转OPENSSL遇阻,求加密解密代码适配方案
迁移Mcrypt AES-128-ECB到OpenSSL的正确实现
我来帮你梳理下问题所在,以及给出完全兼容原Mcrypt代码的OpenSSL实现:
核心问题分析
你的OpenSSL版本代码有两个关键错误:
- ECB模式不需要IV:ECB是电子密码本模式,它不使用初始化向量(IV),原Mcrypt代码里虽然传了
$key作为IV参数,但Mcrypt在ECB模式下会直接忽略这个参数。你在OpenSSL代码里生成并传入IV是完全多余的,甚至可能干扰解密过程。 - 自定义填充逻辑未适配:原代码用了自定义的
\x80填充规则(补\x80直到数据长度对齐块大小),而你用了OPENSSL_ZERO_PADDING但没有手动实现这个填充逻辑,导致加密时数据长度不对齐,解密后内容异常。
修正后的兼容代码
下面是完全兼容原Mcrypt加解密逻辑的OpenSSL版本:
解密函数
function decrypt($encryptedText) { $key = pack('H*', 'NOTHINGTOSEEHERE'); $enc = base64_decode($encryptedText); // ECB模式不需要IV,直接解密,用OPENSSL_ZERO_PADDING让OpenSSL不自动处理填充 $decrypted = openssl_decrypt($enc, 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); // 和原代码一致,去掉末尾的\x80填充 return trim($decrypted, "\x80"); }
加密函数
function encrypt($plaintext) { $key = pack('H*', 'NOTHINGTOSEEHERE'); $blockSize = 16; // AES-128的块大小固定是16字节,和MCRYPT_RIJNDAEL_128一致 $inputLength = strlen($plaintext); // 实现原代码的\x80填充逻辑 if ($inputLength % $blockSize !== 0) { $padding = $blockSize - ($inputLength % $blockSize); $paddedPlainText = str_pad($plaintext, $inputLength + $padding, "\x80", STR_PAD_RIGHT); } else { // 如果已经对齐块大小,原代码会再补一个完整块的\x80 $paddedPlainText = $plaintext . str_repeat("\x80", $blockSize); } // ECB模式不需要IV,加密时用OPENSSL_ZERO_PADDING $enc = openssl_encrypt($paddedPlainText, 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); return base64_encode($enc); }
关键改动说明
- 移除IV相关代码:ECB模式下OpenSSL会忽略IV参数,所以直接去掉IV的生成和传入,避免不必要的错误。
- 还原自定义填充逻辑:严格复刻原Mcrypt代码的填充规则:
- 如果数据长度不是块大小的整数倍,补
\x80到块大小; - 如果已经是块大小的整数倍,额外补一个完整块的
\x80(原代码里$blockCount = floor($inputLength / $blockSize); $padding = ($blockCount +1)*$blockSize - $inputLength,当$inputLength是$blockSize倍数时,$padding就是$blockSize)。
- 如果数据长度不是块大小的整数倍,补
- 使用OPENSSL_ZERO_PADDING:告诉OpenSSL不要自动添加/移除PKCS7填充,完全由我们自己处理原有的填充逻辑,保证和旧代码的兼容性。
验证兼容性
你可以测试:
- 用原Mcrypt加密的文本,用新的OpenSSL解密函数可以得到正确内容;
- 用新的OpenSSL加密的文本,用原Mcrypt解密函数也可以得到正确内容。
内容的提问来源于stack exchange,提问作者unu
相关产品推荐
相关产品推荐

