如何在 C# 中计算 HMAC SHA256
How to compute a HMAC SHA256 in c#
编辑:我已经修复了 @DavidG 指出的 ascii 编码
我正在创建面向供应商的集成,该集成要求我使用 HMAC-SHA256 算法对消息进行签名。
我从供应商那里得到的简单测试是我们将使用这些数据:
key: "1234567890ABCDEF1234567890ABCDEF" (hex)
data: "00000000" (ascii)
expected output (only first 32 chars): FF365893D899291C3BF505FB3175E880 (hex)
我检查了一些在线 hmac 生成器,发现它们对我来说 return 不同的结果,有些正确,有些不正确。
Correct reply: https://www.liavaag.org/English/SHA-Generator/HMAC/
Correct reply: https://cryptii.com/pipes/hmac
Incorrect reply: https://codebeautify.org/hmac-generator
Incorrect reply: http://billatnapier.com/security01.aspx
任何人都可以帮助我或为我指明正确的方向吗?这让我很快就秃顶了...
[TestClass()]
public class AutogiroConcentFileWriterTests
{
[TestMethod()]
public void ManualKVVTest()
{
String key = "1234567890ABCDEF1234567890ABCDEF";
String message = "00000000";
String expected = "FF365893D899291C3BF505FB3175E880";
Encoding ascii = Encoding.ASCII;
Byte[] key_bytes = this.KeyData(key);
Byte[] message_bytes = ascii.GetBytes(message);
System.Security.Cryptography.HMACSHA256 hmacSHA256 = new System.Security.Cryptography.HMACSHA256(key_bytes);
Byte[] hash = hmacSHA256.ComputeHash(message_bytes);
String data = this.ByteToString(hash);
// only compare first 32 chars of the hash
Assert.AreEqual(expected, data.Substring(0, 32));
//Assert.AreEqual failed.
//Expected:<FF365893D899291C3BF505FB3175E880>.
//Actual:<997BBD8C79F0D98FCA6470723CDB65D3>.
}
private Byte[] KeyData(String key)
{
if (key.Length % 2 == 1)
throw new Exception("The binary key cannot have an odd number of digits");
byte[] arr = new byte[key.Length >> 1];
Int32 pos = 0;
for (int i = 0; i < key.Length; i += 2)
{
Int32 b1 = key[i] - (key[i] < 58 ? 48 : 55);
Int32 b2 = key[i + 1] - (key[i + 1] < 58 ? 48 : 55);
arr[pos++] = (byte)((b1 << 4) + b2);
}
return arr;
}
private String ByteToString(Byte[] buff)
{
Char[] retval = new char[buff.Length * 2];
for (int i = 0; i < buff.Length; i++)
{
String t = buff[i].ToString("X2");
retval[i * 2] = t[0];
retval[i * 2 + 1] = t[1];
}
return new String(retval);
}
}
您正在将密钥直接转换为字节,而不是将其解释为十六进制字符串。使用来自 here:
的 string-to-bytes 函数
public static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
将您的代码更改为:
Byte[] key_bytes = StringToByteArray(key);
编辑:我已经修复了 @DavidG 指出的 ascii 编码
我正在创建面向供应商的集成,该集成要求我使用 HMAC-SHA256 算法对消息进行签名。
我从供应商那里得到的简单测试是我们将使用这些数据:
key: "1234567890ABCDEF1234567890ABCDEF" (hex)
data: "00000000" (ascii)
expected output (only first 32 chars): FF365893D899291C3BF505FB3175E880 (hex)
我检查了一些在线 hmac 生成器,发现它们对我来说 return 不同的结果,有些正确,有些不正确。
Correct reply: https://www.liavaag.org/English/SHA-Generator/HMAC/
Correct reply: https://cryptii.com/pipes/hmac
Incorrect reply: https://codebeautify.org/hmac-generator
Incorrect reply: http://billatnapier.com/security01.aspx
任何人都可以帮助我或为我指明正确的方向吗?这让我很快就秃顶了...
[TestClass()]
public class AutogiroConcentFileWriterTests
{
[TestMethod()]
public void ManualKVVTest()
{
String key = "1234567890ABCDEF1234567890ABCDEF";
String message = "00000000";
String expected = "FF365893D899291C3BF505FB3175E880";
Encoding ascii = Encoding.ASCII;
Byte[] key_bytes = this.KeyData(key);
Byte[] message_bytes = ascii.GetBytes(message);
System.Security.Cryptography.HMACSHA256 hmacSHA256 = new System.Security.Cryptography.HMACSHA256(key_bytes);
Byte[] hash = hmacSHA256.ComputeHash(message_bytes);
String data = this.ByteToString(hash);
// only compare first 32 chars of the hash
Assert.AreEqual(expected, data.Substring(0, 32));
//Assert.AreEqual failed.
//Expected:<FF365893D899291C3BF505FB3175E880>.
//Actual:<997BBD8C79F0D98FCA6470723CDB65D3>.
}
private Byte[] KeyData(String key)
{
if (key.Length % 2 == 1)
throw new Exception("The binary key cannot have an odd number of digits");
byte[] arr = new byte[key.Length >> 1];
Int32 pos = 0;
for (int i = 0; i < key.Length; i += 2)
{
Int32 b1 = key[i] - (key[i] < 58 ? 48 : 55);
Int32 b2 = key[i + 1] - (key[i + 1] < 58 ? 48 : 55);
arr[pos++] = (byte)((b1 << 4) + b2);
}
return arr;
}
private String ByteToString(Byte[] buff)
{
Char[] retval = new char[buff.Length * 2];
for (int i = 0; i < buff.Length; i++)
{
String t = buff[i].ToString("X2");
retval[i * 2] = t[0];
retval[i * 2 + 1] = t[1];
}
return new String(retval);
}
}
您正在将密钥直接转换为字节,而不是将其解释为十六进制字符串。使用来自 here:
的 string-to-bytes 函数public static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
将您的代码更改为:
Byte[] key_bytes = StringToByteArray(key);