如何在 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);