PHP解密CryptoJS-AES CBC加密内容失败(无IV)的问题排查
问题根源
CryptoJS的AES.encrypt(text, key)默认生成的是OpenSSL兼容的加盐格式密文(开头为U2FsdGVkX1/,对应字节Salted__),而你的PHP代码没有解析这个格式,直接传入openssl_decrypt导致解密失败。
具体差异:
- CryptoJS会自动生成随机盐,再通过
EVP_BytesToKey算法,从你传入的密钥字符串+盐生成真正的AES-256密钥和IV(CBC模式必须依赖IV) - 当前PHP代码直接用原始密钥字符串解密,既没解析盐,也没生成匹配的密钥和IV,自然解密失败。
修正后的PHP解密代码
<?php $key = '12345678123456781234567812345678'; $ciphertext = "U2FsdGVkX1/ARpsMWWEdLiOanB67kh2akfCIN5s+RLDsJetSMagGsk444I+F/dbp"; // 1. 解析CryptoJS的加盐格式密文 $decoded = base64_decode($ciphertext); $salt = substr($decoded, 8, 8); // 跳过前8字节的"Salted__"标识,提取8字节盐 $realCiphertext = substr($decoded, 16); // 剩余部分为真正的密文 // 2. 用EVP_BytesToKey算法生成匹配的AES密钥和IV(和CryptoJS逻辑一致) $evpResult = EVP_BytesToKey($salt, $key); $aesKey = substr($evpResult, 0, 32); // AES-256需要32字节密钥 $iv = substr($evpResult, 32, 16); // CBC模式需要16字节IV // 3. 执行解密 $result = openssl_decrypt($realCiphertext, 'AES-256-CBC', $aesKey, OPENSSL_RAW_DATA, $iv); // 输出结果与错误信息 var_dump($result); while ($msg = openssl_error_string()) { echo $msg . "<br />"; } // 实现EVP_BytesToKey算法(和OpenSSL/CryptoJS逻辑对齐) function EVP_BytesToKey($salt, $password) { $key = ''; $data = ''; while (strlen($key) < 48) { // 32字节密钥 + 16字节IV = 共48字节 $data = hash('md5', $data . $password . $salt, true); $key .= $data; } return $key; } ?>
关键说明
- CryptoJS的
AES.encrypt默认行为:传入字符串密钥时,自动使用EVP_BytesToKey生成密钥和IV,同时输出包含盐的格式 - 必须先解析密文中的盐,再用相同算法生成密钥和IV,才能和CryptoJS的加密逻辑匹配
- 必须加上
OPENSSL_RAW_DATA参数,因为我们传入的是原始字节密文,而非base64编码格式
内容的提问来源于stack exchange,提问作者Ahsan
相关产品推荐
相关产品推荐

