According to the official doc https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.hashalgorithm.transformblock?view=net-8.0, if I provide outputBuffer, it has to the same as the inputBuffer:
Calling the TransformBlock method with different input and output arrays results in an IOException.
However, the source code here (https://github.com/dotnet/runtime/blob/main/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithm.cs) is quite the opposite:
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[]? outputBuffer, int outputOffset)
{
ValidateTransformBlock(inputBuffer, inputOffset, inputCount);
// Change the State value
State = 1;
HashCore(inputBuffer, inputOffset, inputCount);
if ((outputBuffer != null) && ((inputBuffer != outputBuffer) || (inputOffset != outputOffset)))
{
// We let BlockCopy do the destination array validation
Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
}
return inputCount;
}
Apparently, the source code expects inputBuffer != outputBuffer.
My test shows the docs are wrong:
var file = args.Length > 1 ? args[1] : @"c:\windows\explorer.exe";
using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
var md5 = MD5.Create();
var buf = new byte[100];
var buf2 = new byte[100];
var n = fs.Read(buf, 0, buf.Length);
WriteLine(n);
File.WriteAllBytes(@"c:\temp\test.bin", buf);
md5.TransformBlock(buf, 0, n, buf2, 0);
var hash = md5.TransformFinalBlock(buf, 0, 0);
WriteLine(md5.Hash.ToHexString());
}
And another puzzle:
You must call the TransformBlock method before calling the TransformFinalBlock method. You must call both methods before you retrieve the final hash value.
The docs are wrong again. The following code yields same hash as the code above:
//md5.TransformBlock(buf, 0, n, buf2, 0);
var hash = md5.TransformFinalBlock(buf, 0, n);
And, what confuses me more is that what's the purpose of BlockCopy
?