PHP转TypeScript:OpenSSL AES-CBC加密结果不一致问题排查
问题排查与解决方案
核心问题分析
你的TypeScript代码和PHP代码的关键差异有两点:
- PHP的
md5()返回值类型:PHP中md5($str)默认返回32位十六进制字符串,而你的TS代码里直接用createHash('md5').update(...).digest()得到的是16字节二进制Buffer,这导致密钥完全不匹配。 - 加密数据的拼接方式:用
binary编码拼接加密片段可能引入编码转换问题,直接操作Buffer更可靠。
修正后的TypeScript代码
import { createHash, createCipheriv } from 'node:crypto' // 生成IV:和PHP逻辑一致,SHA256二进制结果取前16字节 const secretIV = createHash('sha256') .update(this.ApiKey) .digest() .subarray(0, 16) // 生成密钥:先将ApiSecret的MD5转为十六进制字符串,再转成32字节(补0) const md5Hex = createHash('md5') .update(this.ApiSecret) .digest('hex') // 对应PHP的md5默认返回十六进制字符串 const key = Buffer.alloc(32) key.write(md5Hex, 0, 'utf8') // 将十六进制字符串写入Buffer,不足部分自动补0 // 加密过程:直接操作Buffer,避免编码转换问题 const cipher = createCipheriv('aes-256-cbc', key, secretIV) const encryptedBuffer = Buffer.concat([ cipher.update(data, 'utf8'), cipher.final() ]) // 返回Base64URL字符串 return encryptedBuffer.toString('base64url')
关键修正点说明
- 密钥生成:PHP的
md5($this->ApiSecret)返回32字符的十六进制字符串,TS中必须用digest('hex')得到相同字符串,再写入32字节Buffer,和PHP的自动补0逻辑完全对齐。 - 加密数据处理:用
Buffer.concat直接拼接update和final的Buffer结果,避免binary编码带来的字符转换错误,和PHPOPENSSL_RAW_DATA输出的二进制数据完全匹配。 - IV生成:原代码逻辑正确,SHA256二进制结果取前16字节,和PHP的
substr(hash("SHA256", $this->ApiKey, true), 0, 16)一致。
验证建议
使用相同的ApiKey、ApiSecret和测试data分别运行PHP和修正后的TS代码,对比输出的Base64URL字符串,即可确认结果一致。
内容的提问来源于stack exchange,提问作者thim24
相关产品推荐
相关产品推荐

