使用 CryptoStream 重用实例时 HMACSHA512 不同的哈希值
HMACSHA512 different hashes when reuse instance with CryptoStream
我有一个用例,我想在第一个 HMAC 和一些数据组合的地方创建第二个 HMAC。
我想了解为什么测试用例 3 正在创建一个 错误的 hmac, 这令人困惑,因为 1 和 2 正在创建相同的哈希值。
代码:
void Main()
{
{ // 0. Create a HMAC
byte[] keyHmac = new byte[] { 255 };
var hmac = new HMACSHA512(keyHmac); // 1st HMACSHA512 ctor
var result = hmac.ComputeHash(new byte[] { 1, 2, 3 });
Console.Out.WriteLine($"0. - {Convert.ToBase64String(result)}");
}
Console.Out.WriteLine("\r\nThe following MACs should be all equal!\r\n");
{ // 1. Create a HMAC than add a byte to the result and create a second HMAC
byte[] keyHmac = new byte[] { 255 };
var hmac = new HMACSHA512(keyHmac); // 1st HMACSHA512 ctor
var result = hmac.ComputeHash(new byte[] { 1, 2, 3 });
result = hmac.ComputeHash(result.Concat(new byte[] { 7 }).ToArray());
Console.Out.WriteLine($"1. - {Convert.ToBase64String(result)}");
}
{ // 2. Create a HMAC than add a byte to the result and create a second HMAC with a new instance
byte[] keyHmac = new byte[] { 255 };
var hmac = new HMACSHA512(keyHmac); // 1st HMACSHA512 ctor
var result = hmac.ComputeHash(new byte[] { 1, 2, 3 });
hmac = new HMACSHA512(keyHmac); // 2nd HMACSHA512 ctor
result = hmac.ComputeHash(result.Concat(new byte[] { 7 }).ToArray());
Console.Out.WriteLine($"2. - {Convert.ToBase64String(result)}");
}
{ // 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;
result = hmac.ComputeHash(result.Concat(new byte[] { 7 }).ToArray());
Console.Out.WriteLine($"3. - {Convert.ToBase64String(result)}");
}
{ // 4. Create a HMAC from a stream than add a byte to the result and create a second HMAC with a new instance
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($"4. - {Convert.ToBase64String(result)}");
}
}
输出:
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)}");
}
在第 3 种情况下,您混合调用 TransformBlock
/TransformFinalBlock
(由 CryptoStream
使用)和调用 ComputeHash
。这两种方法似乎都干扰了对方所拥有的状态机的假设。
使用一种或另一种方法都很好,但将它们混合使用不会太热。
如果您使用的不是 CryptoStream,而是 HashAlgorithm.ComputeHash(Stream)
您的第三种情况应该有效。
我有一个用例,我想在第一个 HMAC 和一些数据组合的地方创建第二个 HMAC。
我想了解为什么测试用例 3 正在创建一个 错误的 hmac, 这令人困惑,因为 1 和 2 正在创建相同的哈希值。
代码:
void Main()
{
{ // 0. Create a HMAC
byte[] keyHmac = new byte[] { 255 };
var hmac = new HMACSHA512(keyHmac); // 1st HMACSHA512 ctor
var result = hmac.ComputeHash(new byte[] { 1, 2, 3 });
Console.Out.WriteLine($"0. - {Convert.ToBase64String(result)}");
}
Console.Out.WriteLine("\r\nThe following MACs should be all equal!\r\n");
{ // 1. Create a HMAC than add a byte to the result and create a second HMAC
byte[] keyHmac = new byte[] { 255 };
var hmac = new HMACSHA512(keyHmac); // 1st HMACSHA512 ctor
var result = hmac.ComputeHash(new byte[] { 1, 2, 3 });
result = hmac.ComputeHash(result.Concat(new byte[] { 7 }).ToArray());
Console.Out.WriteLine($"1. - {Convert.ToBase64String(result)}");
}
{ // 2. Create a HMAC than add a byte to the result and create a second HMAC with a new instance
byte[] keyHmac = new byte[] { 255 };
var hmac = new HMACSHA512(keyHmac); // 1st HMACSHA512 ctor
var result = hmac.ComputeHash(new byte[] { 1, 2, 3 });
hmac = new HMACSHA512(keyHmac); // 2nd HMACSHA512 ctor
result = hmac.ComputeHash(result.Concat(new byte[] { 7 }).ToArray());
Console.Out.WriteLine($"2. - {Convert.ToBase64String(result)}");
}
{ // 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;
result = hmac.ComputeHash(result.Concat(new byte[] { 7 }).ToArray());
Console.Out.WriteLine($"3. - {Convert.ToBase64String(result)}");
}
{ // 4. Create a HMAC from a stream than add a byte to the result and create a second HMAC with a new instance
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($"4. - {Convert.ToBase64String(result)}");
}
}
输出:
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)}");
}
在第 3 种情况下,您混合调用 TransformBlock
/TransformFinalBlock
(由 CryptoStream
使用)和调用 ComputeHash
。这两种方法似乎都干扰了对方所拥有的状态机的假设。
使用一种或另一种方法都很好,但将它们混合使用不会太热。
如果您使用的不是 CryptoStream,而是 HashAlgorithm.ComputeHash(Stream)
您的第三种情况应该有效。