C# 哈希多个字节数组块

3
我正在尝试通过循环从FileStream中读取1024字节并使用TransformBlock函数对文件进行哈希处理。我需要这样做来理解将多个字节数组哈希到一个哈希值的机制。这将使我不仅可以哈希文件,还可以哈希文件夹。我使用了这个stackoverflow问题: Hashing multiple byte[]'s together into a single hash with C#?和这个msdn示例:http://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm.transformblock.aspx 这是我现在的代码:
public static byte[] createFileMD5(string path){
    MD5 md5 = MD5.Create();
    FileStream fs = File.OpenRead(path);
    byte[] buf = new byte[1024];
    byte[] newbuf = new byte[1024];

    int num; int newnum;

    num = fs.Read(buf,0,buf.Length);
    while ((newnum = fs.Read(newbuf, 0, newbuf.Length))>0)
    {
        md5.TransformBlock(buf, 0, buf.Length, buf, 0);
        num = newnum;
        buf = newbuf;
    }

    md5.TransformFinalBlock(buf, 0, num);

    return md5.Hash;
}

很不幸,它计算出来的哈希值与我使用fciv计算出来的哈希值不相符。

为了确保:我在返回的字节数组上使用的十六进制算法:

    public static string byteArrayToString(byte[] ba)
    {
        StringBuilder hex = new StringBuilder(ba.Length * 2);
        foreach (byte b in ba)
            hex.AppendFormat("{0:x2}", b);
        return hex.ToString();
    }
1个回答

4

如果文件大小不是缓冲区大小的倍数,那么传递给TransformBlock的长度在最后一个块中可能会出错。您需要传递从文件中实际读取的字节数:

md5.TransformBlock(buf, 0, newnum, buf, 0);

此外,我不确定为什么您使用newbuf...原始缓冲区仅用于第一个块,然后您使用newbuf处理所有后续块。在这里使用第二个缓冲区没有任何理由。供参考,以下是我用于计算文件哈希值的代码:
            using (var stream = File.OpenRead(path))
            {
                var md5 = MD5.Create();
                var buffer = new byte[8192];
                int read;
                while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    md5.TransformBlock(buffer, 0, read, buffer, 0);
                }
                md5.TransformFinalBlock(buffer, 0, 0);

                ...
            }

1
我曾认为除了最后一个块外,每个块都必须使用TransformBlock,并在最后一个块上使用TransformFinalBlock。但在其他stackoverflow问题中并不清楚: // 对于每个块: md5.TransformBlock(block, 0, block.Length, block, 0);// 对于最后一个块: md5.TransformFinalBlock(block, 0, block.Length); - black
@black,实际上我不确定我所做的方式是否适用于所有哈希算法... 我知道它适用于MD5和SHA1,但其他算法可能要求传递到TransformBlock的所有块具有相同的大小。 - Thomas Levesque
2
@black: 通常情况下,您会对除最后一个块之外的每个块进行TransformBlock。然后,您会在最后一个块上调用 TransformFinalBlock。然而,在未知长度的流中,直到太晚您才可能知道是否已处理了最后一个块。因此,一个正确实现的算法被期望在以空数组调用TransformFinalBlock时,完成哈希处理。然而,在理想情况下,TransformFinalBlock应该被期望使用来自流的最后一个数据块进行调用。 附言: 我使用了MD5和SHA256测试了这两种方法,并确认它们有效。 - Alex Essilfie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接