You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP与CryptoJS的HMAC-SHA512因特殊字符输出不一致,如何修改JS代码?

问题原因分析

PHP里的chr(253)生成的是Latin-1(ISO-8859-1)编码的单字节字符(十六进制值0xFD),而JavaScript默认以UTF-16处理字符串,当直接使用String.fromCharCode(253)生成字符时,后续如果用常规的HMAC库(比如Node.js crypto或crypto-js)处理,库会默认把字符串转成UTF-8编码——但0xFD在UTF-8中属于无效的单字节序列,会被转成错误的字节,导致和PHP的输入字节序列不一致,最终HMAC+Base64的结果自然不同。

解决方案:统一字节编码为Latin-1

要让JS的输出和PHP匹配,关键是让JS使用和PHP完全一致的字节序列参与HMAC计算,也就是把字符串转成Latin-1编码的字节数组。下面分两种常见场景给出代码:

场景1:Node.js环境(使用内置crypto模块)

直接用Buffer.from()指定latin1编码,就能生成和PHP一致的字节序列:

const crypto = require('crypto');

const test = 'test' + String.fromCharCode(253);
const key = 'key';

// 转换为Latin-1编码的Buffer,和PHP的字节序列完全对齐
const testBuffer = Buffer.from(test, 'latin1');
const sign = crypto.createHmac('sha512', key)
                   .update(testBuffer)
                   .digest('base64');

console.log(sign); // 输出会和PHP的var_dump结果一致

场景2:浏览器环境(使用crypto-js库)

需要手动将字符串转换为Latin-1字节数组,再传给crypto-js处理:

// 先确保已引入crypto-js(比如通过CDN或本地引入)
// <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

const test = 'test' + String.fromCharCode(253);
const key = 'key';

// 自定义函数:将字符串转为Latin-1字节数组
function strToLatin1Bytes(str) {
  const byteArray = [];
  for (let i = 0; i < str.length; i++) {
    // 取字符的低8位,对应Latin-1的单字节编码逻辑,和PHP chr()行为一致
    byteArray.push(str.charCodeAt(i) & 0xFF);
  }
  return CryptoJS.lib.WordArray.create(new Uint8Array(byteArray));
}

// 计算HMAC-SHA512并转Base64
const sign = CryptoJS.HmacSHA512(strToLatin1Bytes(test), key).toString(CryptoJS.enc.Base64);

console.log(sign); // 结果和PHP完全匹配

内容的提问来源于stack exchange,提问作者Luker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:56:15