在JavaScript中计算签名/哈希,并与C#具有相同的结果

7

我有以下的C#代码:

var apiKey = "SBB3aWxsIG1ha2UgbXbcQVBJIHN|Y3VyZQ==";
var apiSecret = "QaTW3xlf1U5ljdlAJSdltzT71fFF+eZ=";

var key = Convert.FromBase64String(apiSecret);
var provider = new System.Security.Cryptography.HMACSHA256(key);

var hash = provider.ComputeHash(Encoding.UTF8.GetBytes(apiKey));
var signature = Convert.ToBase64String(hash);

我正在尝试使用CryptJS库在JavaScript中获得相同的结果,但据我所知,我没有将密钥和秘密转换为字节数组,并且编码不正确。第一次尝试看起来像:

var apiKey = "SBB3aWxsIG1ha2UgbXbcQVBJIHN|Y3VyZQ==";
var apiSecret = "QaTW3xlf1U5ljdlAJSdltzT71fFF+eZ=";
var hash = CryptoJS.HmacSHA256(apiKey, apiSecret);
var sig = hash.toString(CryptoJS.enc.Base64);

2
请再次阅读您在此处发布的代码。您忘记解析 CryptoJS 中的Base64编码的 apiSecret。更糟糕的是,您完全忘记将 apiKeyapiSecret 传递给 CryptoJS.HmacSHA256 - Artjom B.
1
是的,我有实际的见解,我已经与你分享了。你应该已经拥有使其工作的工具了。你是否在使用CryptoJS解析Base64编码的字符串时遇到了问题?如果没有,你是否交换了CryptoJS.HmacSHA256的参数顺序? - Artjom B.
目前,您正在将字面字符串“apiKey”传递给HmacSHA256函数,而不是变量 apiKey。 - Heretic Monkey
抱歉,已更新。该示例JS与正确答案相差甚远。最终我希望有人能够提供一个完整的JS解决方案,该方案在JS中产生与所提供的C#相同的签名值。 - billy jean
@billyjean,你的JavaScript代码实际上非常接近了,唯一缺少的是编码部分。 - John Siu
显示剩余2条评论
1个回答

21

https://dev59.com/6WvXa4cB1Zd3GeqPOfGQ#13837543 的启发

Javascript

var CryptoJS = require('crypto-js');

var apiKey = "SBB3aWxsIG1ha2UgbXbcQVBJIHN|Y3VyZQ==";
var apiSecret = "QaTW3xlf1U5ljdlAJSdltzT71fFF+eZ=";

// var key = Convert.FromBase64String(apiSecret);
var key = CryptoJS.enc.Base64.parse(apiSecret);
console.log('key:' + key);

// var prehash = Encoding.UTF8.GetBytes(apiKey);
var prehash = CryptoJS.enc.Utf8.parse(apiKey);
console.log('Pre-hash:' + prehash);

// var provider = new System.Security.Cryptography.HMACSHA256(key);
// var hash = provider.ComputeHash(prehash);
var hash = CryptoJS.HmacSHA256(prehash, key);
console.log('hash:' + hash);

//var signature = Convert.ToBase64String(hash);
var signature = hash.toString(CryptoJS.enc.Base64);
console.log('signature:' + signature);

Javascript输出

key:41a4d6df195fd54e658dd940252765b734fbd5f145f9e6
Pre-hash:53424233615778734947316861325567625862635156424a49484e7c593356795a513d3d
hash:ecb6cdf5dd39872bb2cbce4321e2725e11b99c01af9c2a620ebbaf3d8d8607e7
signature:7LbN9d05hyuyy85DIeJyXhG5nAGvnCpiDruvPY2GB+c= 

C#

using System;
using System.Text;

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var apiKey = "SBB3aWxsIG1ha2UgbXbcQVBJIHN|Y3VyZQ==";
            var apiSecret = "QaTW3xlf1U5ljdlAJSdltzT71fFF+eZ=";
            var key = Convert.FromBase64String(apiSecret);
            Console.Write("key:");
            prtByte(key);

            Console.Write("Pre-hash:");
            prtByte(Encoding.UTF8.GetBytes(apiKey));
            var provider = new System.Security.Cryptography.HMACSHA256(key);
            var hash = provider.ComputeHash(Encoding.UTF8.GetBytes(apiKey));
            Console.Write("hash:");
            prtByte(hash);

            var signature = Convert.ToBase64String(hash);
            Console.WriteLine("signature:" + signature);
        }
        public static void prtByte(byte[] b)
        {
            for (var i = 0; i < b.Length; i++)
            {
                Console.Write(b[i].ToString("x2"));
            }
            Console.WriteLine();
        }
    }
}

C# 输出

key:41a4d6df195fd54e658dd940252765b734fbd5f145f9e6
Pre-hash:53424233615778734947316861325567625862635156424a49484e7c593356795a513d3d
hash:ecb6cdf5dd39872bb2cbce4321e2725e11b99c01af9c2a620ebbaf3d8d8607e7
signature:7LbN9d05hyuyy85DIeJyXhG5nAGvnCpiDruvPY2GB+c=

嗨John,非常感谢你抽出时间。我真的很感激。这里的问题是我的原始C#代码是正确的,我需要JS计算与我提供的C#相同的签名。签名看起来像UufyTxE87/MsjPkLVBBm39G5H1O4bnMj17qSXqyO2/0=。也许你接近了?再次感谢你抽出时间。不确定为什么人们会对此进行负投票。 - billy jean
1
@billyjean 我的 C# 实际上就是你的代码,唯一的更改都在于 Console.Write。我在 Windows 10 和 OS X 上进行了测试,C# 和 JS 都给出了相同的结果。你是否使用了你在问题中发布的相同的 apiKeyapiSecret - John Siu
John,你说得完全正确。对于混淆感到抱歉。我再次查看了你的代码,将其实现到我的解决方案中并进行了重试,一切都正常工作了。非常感谢。希望我有更多可以发送的东西来回报你。再次不确定为什么会被downvote。这是唯一完整的解决方案,对于每个尝试使用此安全方案连接到 .Net API 的人来说都是一个问题。 - billy jean
1
@billyjean 我只能帮你投一票,哈哈。我同意使用不同加密包在不同语言上的问题,并尝试使它们协同工作。我尝试了许多不同的方法和JS包,但直到看到别人的例子才能做对。开源很好,只是很多时候文档不足,好的示例很难找到。 - John Siu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接