HMAC - C# 和 JavaScript 给出不同的结果

HMAC - C# and JavaScript give different result

我的问题与 类似,但由于问题缺少一些细节并且答案不是很有帮助,我再次提问但提供了更多细节。

我已经实施了基于 this tutorial.

的基于 HMAC 的安全性

我有可以创建正确 header 的工作 C# 应用程序(我有意设置了静态时间戳和随机数 - 仅用于测试):

private string CreateHeader(string url)
{
    string appId = "test";
    string apiKey = "A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc=";

    string requestTimeStamp = "1521622403";
    string nonce = "715de35a4bfd4912baaa16daef21992d";

    url = Uri.EscapeUriString(url.ToLower());

    string signatureRawData = String.Format("{0}{1}{2}{3}", appId, url, requestTimeStamp, nonce);

    byte[]secretKeyByteArray = Convert.FromBase64String(apiKey);
    byte[] signature = Encoding.UTF8.GetBytes(signatureRawData);

    using (HMACSHA256 hmac = new HMACSHA256(secretKeyByteArray))
    {
        byte[] signatureBytes = hmac.ComputeHash(signature);
        string requestSignatureBase64String = Convert.ToBase64String(signatureBytes);
        return string.Format("{0}:{1}:{2}:{3}", appId, requestSignatureBase64String, nonce, requestTimeStamp);
    }
}

计算这个header:test:fhqxcZll+3ZRQi3vRexbNyoT00Yqdoyq3CrAdGQ+4kE=:715de35a4bfd4912baaa16daef21992d:1521622403

不是我正在尝试创建将生成相同 header 的 Postman pre-request 脚本。这是我的脚本:

function getAuthHeader(httpMethod, requestUrl, requestBody) {
    var CLIENT_KEY = 'test';
    var SECRET_KEY = 'A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc=';

    var requestTimeStamp = "1521622403";
    var nonce  = "715de35a4bfd4912baaa16daef21992d"
    requestUrl = requestUrl.toLowerCase();

    var signatureRawData = CLIENT_KEY+requestUrl+requestTimeStamp+nonce;
    console.log("signatureRawData: "+signatureRawData);

    var x = CryptoJS.enc.Utf8.parse(SECRET_KEY);

    var hash = CryptoJS.HmacSHA256(signatureRawData, x);
    var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);

    var header = [CLIENT_KEY, hashInBase64, nonce, requestTimeStamp].join(":");
    console.log("header: "+ header);

    return header;
}

postman.setEnvironmentVariable('hmacAuthHeader', getAuthHeader(request['method'], request['url'], request['data']));

但我得到不同的 header 值: test:2ITrhVxr1/4BOxNVNcECnaSh0cW36LiMZWVQ0DaFncY=:715de35a4bfd4912baaa16daef21992d:1521622403

在 C# 中,我正在将键和数据转换为散列到 byte[],可能这就是问题所在。我怎样才能在 JavaScript 中做同样的事情?
C# 需要 byte[] 作为 HMACSHA256ComputeHash.

中的参数

我正在寻找一种从 C# 和 JavaScript(Postman pre-request 脚本)生成相同 HMACSHA256 的方法

在JS中修正hash的解决方案是关键。在 C# 中,我调用:

byte[]secretKeyByteArray = Convert.FromBase64String(apiKey);

在我使用那个密钥之前,在 JS 中我传递了原始的 base64 编码值。

这里更正了pre-request脚本:

function S4() {
    return (((1+Math.random())*0x10000)|0).toString(16).substring(1); 
}

function GetNonce() {
    return (S4() + S4() + S4()+ S4() + S4() + S4() + S4()+ S4()).toLowerCase();
}

function GetTimeStamp() {
    var d = new Date();
    return Math.round(d.getTime() / 1000);
}

function getAuthHeader(httpMethod, requestUrl, requestBody) {
    var CLIENT_KEY = postman.getEnvironmentVariable('api_user');
    var SECRET_KEY = postman.getEnvironmentVariable('api_key');
    var AUTH_TYPE = 'HMAC';

    var requestTimeStamp = GetTimeStamp();
    var nonce = GetNonce();
    requestUrl = requestUrl.toLowerCase();

    var signatureRawData = [CLIENT_KEY,requestUrl,requestTimeStamp,nonce].join("");
    var key = CryptoJS.enc.Base64.parse(SECRET_KEY);

    var hash = CryptoJS.HmacSHA256(signatureRawData, key);
    var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);

    var header = [CLIENT_KEY, hashInBase64, nonce, requestTimeStamp].join(":");
    console.log("header: "+ header);

    return AUTH_TYPE+" "+header;
}

postman.setEnvironmentVariable('hmacAuthHeader', getAuthHeader(request['method'], request['url'], request['data']));

在寻找解决方案时,我发现了多种语言的 hmac sha256 实现列表:https://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/