请注意,根据您链接的文档:
HMAC(key, data) 表示以二进制格式返回输出的 HMAC-SHA256 函数。每个哈希函数的结果成为下一个哈希函数的输入。
即 HMAC() 返回 byte[] 而不是十六进制字符串。它还期望其输入为byte[]。如果您的 hmac 函数在返回结果之前将散列转换为十六进制字符串,则必须确保在将其用作下一步的键时将其正确转换回 byte[]。或者 - 最好 - 不要将中间结果转换为字符串,而只需将 byte[] 传递给下一步,仅将最终结果转换为字符串。
例如考虑以下内容:
一些散列函数hash(key, value) 返回[255, 255] 作为结果(即byte[] 有两个字节)。当您将 byte[] 转换为十六进制字符串时,您将获得字符串 "ffff"。但是如果你把这个字符串作为key传递到下一步,大多数在线工具不会把这个字符串当作十六进制表示,而只是把字符串的每个字符当作一个字节。即你的字符串"ffff"会变成字节数组[102, 102, 102, 102],这显然是错误的,会导致不同的哈希结果。
对于 JS:
var secret = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";
var date = "20150830";
var region = "us-east-1";
var service = "iam";
var kdate = CryptoJS.HmacSHA256(date, "AWS4"+secret);
var kregion = CryptoJS.HmacSHA256(region, kdate);
var kservice = CryptoJS.HmacSHA256(service, kregion);
var ksigning = CryptoJS.HmacSHA256("aws4_request", kservice);
var hashInHex = CryptoJS.enc.Hex.stringify(ksigning);
console.log(hashInHex);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js"></script>
CryptoJS.HmacSHA256(data, key) 也按上述方式处理其输入。即如果key 是string,则在转换为字节数组时,键中的每个字符都被视为单个字节。当key 已经是byte[] 时,它按原样使用。而HmacSHA256 将哈希返回为byte[] 而不是字符串。
对于 C#
using System;
using System.Text;
using System.Security.Cryptography;
public class Program
{
public static void Main()
{
var secret = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";
var date = "20150830";
var region = "us-east-1";
var service = "iam";
var kdate = h(Encoding.UTF8.GetBytes("AWS4"+ secret), Encoding.UTF8.GetBytes(date));
var kregion = h(kdate, Encoding.UTF8.GetBytes(region));
var kservice = h(kregion, Encoding.UTF8.GetBytes(service));
var ksigning = h(kservice, Encoding.UTF8.GetBytes("aws4_request"));
Console.WriteLine(BitConverter.ToString(ksigning).Replace("-","").ToLower());
}
public static byte[] h(byte[] key, byte[] buffer) {
var hmacsha256 = new HMACSHA256(key);
return hmacsha256.ComputeHash(buffer);
}
}
两种变体都提供了预期的输出。