CryptoJS.AES.encrypt对应AES/CBC/PKCS7的PHP实现问题求助
PHP适配CryptoJS AES-128-CBC签名的修正方案
现有代码核心错误点
- IV处理错误:CryptoJS中使用的IV是32位16进制0转换得到的16字节二进制值,当前代码使用
bin2hex('00000000000000000000000000000000')得到的是64位十六进制字符串,长度不符合AES-CBC要求的16字节,且传入openssl_encrypt的IV应为原始二进制而非十六进制格式 - 结果拼接逻辑错误:CryptoJS加密输出没有拼接IV(双方约定固定IV无需传输),当前代码将IV和密文拼接后做Base64编码的逻辑和目标逻辑完全不符
- 最终输出格式错误:目标要求输出密文原始二进制的十六进制格式,当前代码返回的是IV+密文的Base64编码
修正后的完整代码
常量定义
// 确认API密钥长度为128位对应32字符十六进制时,使用AES-128-CBC const CIPHER = 'AES-128-CBC'; // 固定IV对应十六进制字符串 const FIXED_IV_HEX = '00000000000000000000000000000000';
加密方法
public static function encrypt($apiKeyHex, $plainText) { try { // 密钥十六进制转二进制 $secretKey = hex2bin($apiKeyHex); // 验证密钥长度对应AES-128要求的16字节 if (strlen($secretKey) !== 16) { throw new \InvalidArgumentException("API密钥为128位时,十六进制格式长度必须为32字符"); } // 固定IV转二进制 $iv = hex2bin(self::FIXED_IV_HEX); // 加密得到原始二进制密文 $rawCipher = openssl_encrypt( $plainText, self::CIPHER, $secretKey, OPENSSL_RAW_DATA, $iv ); if ($rawCipher === false) { throw new \Exception(openssl_error_string()); } // 原始密文转十六进制 对应CryptoJS最后一步输出 return bin2hex($rawCipher); } catch (\Exception $e) { return $e->getMessage(); } }
调用示例(对应CryptoJS的明文构造逻辑)
// 示例参数 替换为实际值 $apiKey = '你的32字符十六进制API密钥'; $requestUrl = 'https://example.com/api/order?a=1'; $requestMethod = 'POST'; // 构造明文 必须和JS逻辑完全一致 $urlWithoutQuery = explode('?', $requestUrl)[0]; $subUrl = substr($urlWithoutQuery, strpos($urlWithoutQuery, '/')); $plainSignature = $subUrl . '##' . $requestMethod . '#' . $apiKey; // 生成签名 $signature = self::encrypt($apiKey, $plainSignature);
验证注意事项
- 确保明文拼接逻辑和JS完全一致,包括大小写、分隔符数量、请求方法大小写
- 确认API密钥为合法32字符十六进制字符串,对应AES-128的128位密钥长度,如果密钥长度为64字符十六进制,需将常量CIPHER改为
AES-256-CBC
内容的提问来源于stack exchange,提问作者SaeedSoltani
相关产品推荐
相关产品推荐

