如何在C#中进行SHA1文件校验?

65

我如何使用SHA1CryptoServiceProvider()对文件进行操作以创建该文件的SHA1校验和?

4个回答

87
using (FileStream fs = new FileStream(@"C:\file\location", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
{
    using (SHA1Managed sha1 = new SHA1Managed())
    {
        byte[] hash = sha1.ComputeHash(bs);
        StringBuilder formatted = new StringBuilder(2 * hash.Length);
        foreach (byte b in hash)
        {
            formatted.AppendFormat("{0:X2}", b);
        }
    }
}

formatted 包含 SHA-1 哈希的字符串表示。此外,通过使用 FileStream 而不是字节缓冲区,ComputeHash 会分块计算哈希值,因此您无需一次性加载整个文件,这对于大文件非常有用。


3
在构建哈希字符串的过程中,你应该使用StringBuilder而不是生成20个字符串。 - Igor Brejc
3
StringBuilder的初始容量应该是哈希中字节数的两倍。 - Mark Heath
1
根据@MarkHeath的评论进行了编辑,并添加了BufferedStream以提高性能。 - Eric J.
11
我认为您不需要使用BufferedStream。https://dev59.com/nHRB5IYBdhLWcg3w1Kv0#2069317 - Ronnie Overby
1
经过100,000次迭代测试,BufferedStream没有任何区别,因此我将从示例中删除它。我还尝试了一种替代方法来生成哈希字符串,使用BitConverter,它提供了适度的(6%)性能提升(并且代码行数更少),因此也在示例中进行了修改。 - Mason G. Zhwiti
显示剩余4条评论

67

使用ComputeHash方法,参见此处:

ComputeHash

示例代码片段:

using(var cryptoProvider = new SHA1CryptoServiceProvider())
{
    string hash = BitConverter
            .ToString(cryptoProvider.ComputeHash(buffer));

    //do something with hash
}

buffer是您文件的内容。


4
对于在 BitConverter 中使用技巧生成十六进制字符串的建议,给予一个大加赞同(+1)。 - Igor Brejc
1
SHA1CryptoServiceProvider 应该被包裹在 using 块中。 - Mike737
2
BitConverter 使用连字符 AA-F0-CC 分隔字节,不同于 @mgbowen 的解决方案。可能是所需的,也可能不是。 - Eric J.

6
如果您已经将文件作为流读取,则以下技术会在您阅读该文件时计算哈希值。唯一的注意事项是您需要完全消耗整个流。
class Program
    {
        static void Main(string[] args)
        {
            String sourceFileName = "C:\\test.txt";
            Byte[] shaHash;

            //Use Sha1Managed if you really want sha1
            using (var shaForStream = new SHA256Managed())
            using (Stream sourceFileStream = File.Open(sourceFileName, FileMode.Open))
            using (Stream sourceStream = new CryptoStream(sourceFileStream, shaForStream, CryptoStreamMode.Read))
            {
                //Do something with the sourceStream 
                //NOTE You need to read all the bytes, otherwise you'll get an exception ({"Hash must be finalized before the hash value is retrieved."}) 
                while(sourceStream.ReadByte() != -1);                
                shaHash = shaForStream.Hash;
            }

            Console.WriteLine(Convert.ToBase64String(shaHash));
        }
    }

+1 对于 CryptoStream。如果您想从某个地方(例如:从 HTTP 请求)读取文件,将其写入某个位置(例如:磁盘),同时计算哈希值,那么它可能非常有用。 - tigrou
1
在一个大文件的测试中,这段代码的性能比“ComputeHash”解决方案差了几个数量级。也许是因为它使用了“ReadByte”逐字节读取的方式? - Michael Kropat
@MichaelKropat 很有趣。好知道。慢了10倍,100倍? - Daniel James Bryars
@MichaelKropat - 我只是想,如果开销是因为我的示例读取了每个字节,那么如果您已经使用流,这就无关紧要了。 - Daniel James Bryars

4

你也可以尝试以下方法:

FileStream fop = File.OpenRead(@"C:\test.bin");
string chksum = BitConverter.ToString(System.Security.Cryptography.SHA1.Create().ComputeHash(fop));

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