C#中的HMAC SHA256哈希计算

8

我需要使用SHA256哈希函数计算HMAC。我有一个以base64格式编码的秘密密钥。还有一个在线工具可以正确计算HMAC(已验证)。 http://www.freeformatter.com/hmac-generator.html 我编写了以下代码片段:

var signatureHashHexExpected = "559bd871bfd21ab76ad44513ed5d65774f9954d3232ab68dab1806163f806447";
var signature = "123456:some-string:2016-04-12T12:44:16Z";
var key = "AgQGCAoMDhASFAIEBggKDA4QEhQCBAYICgwOEBIUAgQ=";

var shaKeyBytes = Convert.FromBase64String(key);
using (var shaAlgorithm = new System.Security.Cryptography.HMACSHA256(shaKeyBytes))
{
    var signatureBytes = System.Text.Encoding.UTF8.GetBytes(signature);
    var signatureHashBytes = shaAlgorithm.ComputeHash(signatureBytes);
    var signatureHashHex = string.Concat(Array.ConvertAll(signatureHashBytes, b => b.ToString("X2"))).ToLower();

    System.Diagnostics.Debug.Assert(signatureHashHex == signatureHashHexExpected);
}

问题: 我的代码没有生成正确的HMAC。我使用了不同的在线工具和替代C#实现来验证不同的步骤。唯一没有确认的是从base64转换过来的部分。我错过了什么吗?
更新: 通过我的代码计算出的signatureHashHex是“a40e0477a02de1d134a5c55e4befa55d6fca8e29e0aa0a0d8acf7a4370208efc”
答案: 问题是由于一个误导性的文档引起的,该文档说明密钥以Base64格式提供。请参见接受的答案:
var shaKeyBytes = System.Text.Encoding.UTF8.GetBytes(key);

你确定签名是以UTF8编码的吗? - Scott Chamberlain
你试过这个吗:https://dev59.com/mZDea4cB1Zd3GeqPdpZi? - Ivar
没有,但我尝试了许多不同的编码方式,结果都一样。 - kalitsov
1
signatureHashHex 的结果是什么? - Ivar
@Ivar,我已经更新了我的问题,并附上了计算出的值。 - kalitsov
2个回答

8

您的结果是正确的,差异在于您链接到的工具对密钥值进行Base64解码,并将其视为一系列字符。

例如,要复制其结果,请将密钥视为字符串处理:

var shaKeyBytes = System.Text.Encoding.UTF8.GetBytes("AgQGCAoMDhASFAIEBggKDA4QEhQCBAYICgwOEBIUAgQ=");

产生的结果如下:
559bd871bfd21ab76ad44513ed5d65774f9954d3232ab68dab1806163f806447

(显然这不是正确的做法)


费心解释一下,为什么 GetBytes(...) 是“显然错误”的?如果我的关键词是 "This_is_my_secret_keyphrase" 呢? - derpirscher
因为Base64字符串是一系列编码的字节,应该使用这些字节(解码后)而不是字符串本身。你不会订购一个新椅子然后就坐在盒子上。(“This_is_my_secret_keyphrase”不是Base64) - Alex K.
1
一个简单的字符串也是一系列编码的字节。这只是一种解释方式而已。口令短语存储的格式完全无关紧要,只要它可以转换为正确的用于加密/解密的字节向量即可。Convert.FromBase64String("VGhpc19pc19teV9zZWNyZXRfa2V5cGhyYXNl")System.Text.Encoding.UTF8.GetBytes("This_is_my_secret_keyphrase")之间有什么区别?只需要确保双方在相同的输入上使用相同的方法即可。我不记得密钥必须是base64字符串的要求了。 - derpirscher
我不理解参数的意义,*GetBytes(...)明显是错误的*,因为它与旨在进行Base64解码但未被解码的值一起使用。 - Alex K.
伙计们,问题是由误导性文档引起的,文档声称密钥以Base64格式提供。 - kalitsov

0

HMAC:它是一种消息认证码。用于验证发送者的数据完整性,是一种单向算法。它基于由发送者和接收者共同知道的共享密钥工作。在生成哈希值之前,我们必须对密钥和消息进行编码。我们可以使用UTF8ASCIIEncoding中的任何一种编码。

UTF8编码:

var signature = "123456:some-string:2016-04-12T12:44:16Z";
var key = "AgQGCAoMDhASFAIEBggKDA4QEhQCBAYICgwOEBIUAgQ=";


var signatureBytes = System.Text.Encoding.UTF8.GetBytes(signature);
var shaKeyBytes = System.Text.Encoding.UTF8.GetBytes(key);

ASCIIEncoding编码:

var signature = "123456:some-string:2016-04-12T12:44:16Z";
var key = "AgQGCAoMDhASFAIEBggKDA4QEhQCBAYICgwOEBIUAgQ=";

var signatureBytes = System.Text.ASCIIEncoding.GetBytes(signature);
var shaKeyBytes = System.Text.ASCIIEncoding.GetBytes(key);

现在我们可以在上面的代码中使用这个编码消息和密钥。

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