我从身份验证源获取签名有效负载,该负载采用 Base64 编码和 URL 编码格式。我在评估时在某个地方感到困惑,并最终得到不同“格式”的类似数据。
这是我的代码:
//Split the message to payload and signature
string[] split = raw_message.Split('.');
//Payload
string base64_payload = WebUtility.UrlDecode(split[0]);
byte[] payload = Convert.FromBase64String(base64_payload);
//Expected signature
string base64_expected_sig = WebUtility.UrlDecode(split[1]);
byte[] expected_sig = Convert.FromBase64String(base64_expected_sig);
//Signature
byte[] signature = hmacsha256.ComputeHash(payload);
//Output as a string
var foo = System.Text.Encoding.UTF8.GetString(expected_sig);
var bar = BitConverter.ToString(signature);
预期的签名 (foo
) 如下所示:
76eba09fcb54877299dcbd1e1e35717e3bd42e066e7ecdb131c7d0161dec3418
计算出的签名(bar
)如下:
76-EB-A0-9F-CB-54-87-72-99-DC-BD-1E-1E-35-71-7E-3B-D4-2E-06-6E-7E-CD-B1-31-C7-D0-16-1D-EC-34-18
显然,当逐字节比较时,这是行不通的。
我发现我必须以不同的方式转换 expected_sig
和 signature
才能让它们显示为字符串,但我无法弄清楚如何我需要更改预期的签名才能到达可以比较字节的位置。
我显然可以解决这个问题,但只需转换字符串bar
,但这很脏,我就是不喜欢它。
我哪里出错了?我不明白什么?
最佳答案
好消息是哈希计算似乎正在工作。
坏消息是你正在以一种脑死亡的方式接收哈希值。出于某种原因,作者似乎认为以下是个好主意:
- 计算哈希值(精细)
- 将此二进制数据转换为十六进制文本(精细)
- 通过应用 ASCII/UTF-8/anything-ASCII 兼容编码将十六进制转换回二进制数据(为什么?)
- 使用 base64 将结果转换回文本(什么?)
- 对结果进行 URL 编码(对于十六进制甚至不需要......)
在原始二进制文件上使用base64或十六进制是有意义的,但应用两者是疯狂的。
无论如何,你做同样的事情是相当容易的。例如:
string hexSignature = string.Join("", signature.Select(b => b.ToString("x2")));
byte[] hexSignatureUtf8 = Encoding.UTF8.GetBytes(hexSignature);
string finalSignature = Convert.ToBase64String(hexSignatureUtf8);
现在应该匹配 WebUtility.UrlDecode(split[1])
。
或者,您可以从结果中向后工作,但我不会将十六进制解析回字节 - 保留上面的第一行会更简单,但使用:
string expectedHexBase64 = WebUtility.UrlDecode(split[1]);
byte[] expectedHexUtf8 = Convert.FromBase64String(expectedHexBase64);
string expectedHex = Encoding.UTF8.GetString(expectedHexUtf8);
然后将其与hexSignature
进行比较。
理想情况下,你应该与向你提供疯狂格式的人交谈,并用线索打击他们......
关于c# - 为什么在评估 HMAC 时,我的字节中会出现两个不同的十六进制 'formats'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21915451/