C# HMACSHA512在使用CryptoStream重用实例时使用不同的哈希

C# HMACSHA512在使用CryptoStream重用实例时使用不同的哈希,c#,.net,cryptography,hmac,C#,.net,Cryptography,Hmac,我有一个用例,我想创建第二个HMAC,其中第一个HMAC和一些数据被组合在一起 我想理解为什么测试用例3创建了一个错误的hmac,这让人困惑,因为1和2创建了相同的散列 代码: 输出: 0. - J0x6KRHzGh1nTLL+a+pL8H9PJyl1b9/rL7D0j3S1DBpMduct37uMi0mBFEOdkfrLs2Ipn39yoV6GaRoEK+hU7A== The following MACs should be all equal! 1. - mVd7YQ7AbmRfH57A

我有一个用例,我想创建第二个HMAC,其中第一个HMAC和一些数据被组合在一起

我想理解为什么测试用例3创建了一个错误的hmac,这让人困惑,因为1和2创建了相同的散列

代码:

输出:

0. - J0x6KRHzGh1nTLL+a+pL8H9PJyl1b9/rL7D0j3S1DBpMduct37uMi0mBFEOdkfrLs2Ipn39yoV6GaRoEK+hU7A==

The following MACs should be all equal!

1. - mVd7YQ7AbmRfH57AprAuU1vlSuOucvg+NbUFl7eNurPuvGS/Xrko2Kz3d9vUGXr0P287dOgEKQJDNfMkN2xi5Q==
2. - mVd7YQ7AbmRfH57AprAuU1vlSuOucvg+NbUFl7eNurPuvGS/Xrko2Kz3d9vUGXr0P287dOgEKQJDNfMkN2xi5Q==
3. - DVncxk/dEYhmmpK5qEnVg0Pc0/MUe8APbAiyZrh+ba35oGv2TGCkFco3gFVZ2gl+h3DpcqP7VbmuthBmCvSKlg==
4. - mVd7YQ7AbmRfH57AprAuU1vlSuOucvg+NbUFl7eNurPuvGS/Xrko2Kz3d9vUGXr0P287dOgEKQJDNfMkN2xi5Q==

这是因为在除3之外的所有方法中,都会在第一次散列计算和第二次散列计算之间重新初始化hmac。要在3中执行相同操作,请尝试以下操作:

{
    // 3. Create a HMAC from a stream than add a byte to the result and create a second HMAC
    byte[] keyHmac = new byte[] {255};
    var hmac = new HMACSHA512(keyHmac);
    using (var resultStream = new MemoryStream()) {
       using (var hmacStream = new CryptoStream(resultStream, hmac, CryptoStreamMode.Write)) {
           new MemoryStream(new byte[] {1, 2, 3}).CopyTo(hmacStream);
        }
    }

    var result = hmac.Hash;
    hmac = new HMACSHA512(keyHmac);
    result = hmac.ComputeHash(result.Concat(new byte[] {7}).ToArray());

    Console.Out.WriteLine($"{Convert.ToBase64String(result)}");
}

在第三种情况下,您将对
TransformBlock
/
TransformFinalBlock
(由
CryptoStream
使用)的调用与对
ComputeHash
的调用混合在一起。这两种方法似乎都干扰了另一种方法对状态机的假设

使用一种或另一种方法是可以的,但是混合它们不会那么热


如果您没有使用CryptoStream,而是使用了
HashAlgorithm.ComputeHash(Stream)
您的第三种情况应该可以使用。

在(1)中,我只调用了一次ctor HMACSHA512,因此我没有在那里重新初始化hmac。或者我遗漏了什么?这是一个关于CryptoStream的链接问题,如果我处于无效状态,状态机不应该抛出异常吗?好吧,最大的问题是TransformFinalBlock不调用Initialize(),因此哈希不会重置为无数据状态。另一个方向也有类似的问题,计算哈希之前的TransformBlock将被视为假装TransformBlock中的数据。虽然您认为这是应用程序的一个bug,但依赖于这些行为的应用程序将“修复”它视为他们的bug。(您可以通过调用ComputeHash(Array.Empty)重置您的状态)我可以阻止TransformFinalBlock的调用并稍后添加一些数据吗?
{
    // 3. Create a HMAC from a stream than add a byte to the result and create a second HMAC
    byte[] keyHmac = new byte[] {255};
    var hmac = new HMACSHA512(keyHmac);
    using (var resultStream = new MemoryStream()) {
       using (var hmacStream = new CryptoStream(resultStream, hmac, CryptoStreamMode.Write)) {
           new MemoryStream(new byte[] {1, 2, 3}).CopyTo(hmacStream);
        }
    }

    var result = hmac.Hash;
    hmac = new HMACSHA512(keyHmac);
    result = hmac.ComputeHash(result.Concat(new byte[] {7}).ToArray());

    Console.Out.WriteLine($"{Convert.ToBase64String(result)}");
}