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

如何向btoa传入正确二进制字符串,实现原生JS替代CryptoJS编码?

解决原生JS中HMAC-SHA1十六进制转Base64的错误问题

问题的核心是你误解了btoa()的输入要求——它需要的是代表原始字节的字符字符串,而不是由0和1组成的二进制位字符串。你的代码把十六进制转成了一串01字符,这相当于把每个字节拆成了8个单独的字符,完全不符合btoa的预期,所以得到了错误的结果。

修正后的完整代码

首先,我们需要把十六进制字符串转换成每个字符对应一个字节的字符串,再传给btoa():

const encrypted_vendor = VENDOR.hmacSHA1("message", "secret"); // 输出十六进制字符串:"0caf649feee4953d87bf903ac1176c45e028df16"

// 拆分十六进制字符串为双字符的字节片段
function splitHex(hexString) {
  const chunks = [];
  for (let i = 0; i < hexString.length; i += 2) {
    chunks.push(hexString.substring(i, i + 2));
  }
  return chunks; // 注意:原函数遗漏了返回值,这也是问题之一
}

// 将单个十六进制字节转换为对应的字符(每个字符代表一个原始字节)
function hexByteToChar(hexByte) {
  return String.fromCharCode(parseInt(hexByte, 16));
}

// 生成符合btoa要求的字节字符串,再编码为Base64
const hexChunks = splitHex(encrypted_vendor);
const byteString = hexChunks.map(hexByteToChar).join('');
const correctB64 = btoa(byteString); // 结果:"DK9kn+7klT2Hv5A6wRdsReAo3xY="

简化版实现

如果不想单独写拆分函数,也可以直接循环处理:

const encrypted_vendor = VENDOR.hmacSHA1("message", "secret");
let byteString = '';

for (let i = 0; i < encrypted_vendor.length; i += 2) {
  // 每次取两位十六进制,转成字节对应的字符
  byteString += String.fromCharCode(parseInt(encrypted_vendor.substring(i, i + 2), 16));
}

const correctB64 = btoa(byteString);

为什么这样能解决问题?

  • parseInt(hexByte, 16) 把两位十六进制字符串转换成0-255之间的字节数值,这就是HMAC-SHA1计算后的原始字节值。
  • String.fromCharCode() 将字节数值转换成对应的Unicode字符(对于0-255的数值,这个字符和ASCII字符完全一致)。
  • 最终生成的byteString完全对应CryptoJS内部的字节序列,所以btoa()能正确编码出和CryptoJS.enc.Base64.stringify()一致的结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:16:53