JavaScript CryptoJS加密数据无法被PHP Mcrypt正确解密
解密乱码问题的根源与修复方案
嘿,我看你遇到了JS CryptoJS加密后,PHP mcrypt解密开头乱码的问题,这大概率是两边的参数处理不一致导致的,我帮你一步步排查修复:
1. 最关键的错误:IV处理不匹配
你JS代码里的IV处理逻辑错了!看这段:
var base64Iv = "0123456789abcdef"; var iv = CryptoJS.enc.Base64.parse(base64Iv);
这里你把普通的UTF8字符串"0123456789abcdef"当成Base64编码去解析了,但这个字符串本身根本不是Base64格式的内容啊!而PHP里你直接用了原始字符串$iv = "0123456789abcdef"作为IV的字节,这就导致两边的IV完全不一样,解密开头自然会乱码。
修复JS的IV处理,改成和PHP一致的UTF8字节解析:
var iv = CryptoJS.enc.Utf8.parse("0123456789abcdef");
2. PHP端填充处理的小问题
你的PHP解密函数里有两个小bug:
- 字符串拼接用了
+号,PHP里应该用.,不然会输出错误内容; - Pkcs7填充的校验逻辑不够严谨,容易误判。
修复后的PHP解密函数如下:
function decrypt($crypt, $key, $type){ $enc = MCRYPT_RIJNDAEL_128; $mode = MCRYPT_MODE_CBC; $iv = "0123456789abcdef"; // 解码Base64密文 $crypt = base64_decode($crypt); // 执行解密,mcrypt_decrypt返回原始字节流 $padtext = mcrypt_decrypt($enc, base64_decode($key), $crypt, $mode, $iv); // 处理Pkcs7填充 $pad = ord(substr($padtext, -1)); // 校验填充长度是否合法(AES块大小是16字节) if ($pad < 1 || $pad > 16) { return false; } // 校验填充内容是否符合Pkcs7规则 $lastChars = substr($padtext, -$pad); $isValidPad = true; foreach (str_split($lastChars) as $char) { if (ord($char) !== $pad) { $isValidPad = false; break; } } if (!$isValidPad) { return "Error"; } // 去除填充得到明文 $text = substr($padtext, 0, -$pad); return $text; }
3. 额外建议:替换废弃的mcrypt
提醒一下,mcrypt扩展在PHP 7.1之后就被官方废弃了,后续版本可能会移除,推荐你换成openssl_decrypt,兼容性更好也更稳定,给你补一个openssl版本的解密函数:
function decrypt_openssl($crypt, $key){ $iv = "0123456789abcdef"; return openssl_decrypt( $crypt, 'AES-128-CBC', // MCRYPT_RIJNDAEL_128对应AES-128(块大小128位) base64_decode($key), OPENSSL_RAW_DATA, // 对应原始字节解密,自动处理Pkcs7填充 $iv ); }
最后验证
修改JS的IV处理后,用相同密钥加密你的测试字符串,再用修复后的PHP函数解密,就能得到完全匹配的预期结果啦。
内容的提问来源于stack exchange,提问作者Mukhammad Ali
相关产品推荐
相关产品推荐

