C#快速哈希计算

6
我正在寻找一个C#封装的本地MD5或SHA1库,以提高哈希计算性能。
之前我将SharpZipLib切换到zlib,并获得了超过2倍的性能提升。(好吧,你必须确保你有正确的zlib.so或zlib.dll,这取决于操作系统和硬件,但它是值得的)。
对于MD5或SHA1,或者.NET和Mono是否已经依赖于本地实现,这是否值得呢?
(编辑)另外:如果我必须坚持使用MD5CryptoServiceProvider,有没有一种方法可以在读取文件时计算文件的哈希值?我的意思是,分块发送字节,但仍然计算整个哈希值?

1
请记住,MD5是已被破解的哈希算法,不再被认为是安全的。SHA1也存在碰撞问题,虽然不像MD5那样严重,但仍然被视为重大漏洞。如果您需要一个安全的哈希算法,应选择SHA2变体(256/512)。 - jrista
@pablo,你确定哈希而不是IO访问是瓶颈吗? - Sam Saffron
@jrista,我不太担心安全问题,因为我的操作是对文件内容进行哈希处理,以快速检查它们是否发生了更改。同时进行哈希处理和读取可能也会有所帮助。 - pablo
4
@jrista,任何哈希算法都可能发生碰撞,无论它是否被"破解"。但最终你是正确的:SHA256是正确的选择。 - DarkSquid
@jrista,没有机会碰撞,无论是从md5还是sha1,这两种算法都容易受到碰撞攻击的影响,这意味着人们可以在理论上制造碰撞。 - Sam Saffron
显示剩余4条评论
4个回答

17

MD5和SHA1依赖于本地实现,不过可能通过C++解决方案+介入会稍微更快一些,因为你可能可以减少一些方法调用次数并优化本地实现。

请记住,本地实现(SHA1CryptoServiceProvider)可能比托管实现(SHA1Managed)快3倍。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Security.Cryptography;

namespace ConsoleApplication22 {



    class Program {

        static void Profile(string description, int iterations, Action func) {

            // clean up
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            // warm up 
            func();

            var watch = Stopwatch.StartNew();
            for (int i = 0; i < iterations; i++) {
                func();
            }
            watch.Stop();
            Console.Write(description);
            Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
        }

        static void Main() {
            SHA1Managed managed = new SHA1Managed();
            SHA1CryptoServiceProvider unmanaged = new SHA1CryptoServiceProvider();

            Random rnd = new Random();

            var buffer = new byte[100000];
            rnd.NextBytes(buffer);

            Profile("managed", 1000, () => {
                managed.ComputeHash(buffer, 0, buffer.Length);
            });

            Profile("unmanaged", 1000, () =>
            {
                unmanaged.ComputeHash(buffer, 0, buffer.Length);
            });

            Console.ReadKey();
        }
    }
}
托管代码执行时间为891毫秒
非托管代码执行时间为336毫秒

另外需要记住,除非我的计算有误,否则非托管实现在大约300毫秒内对100MB的数据进行哈希处理,这很少会成为瓶颈。

一个Interop解决方案需要进行封送处理,这可能会减轻其他可能实现的任何收益。这只是要记住的一些事情。 - jrista
我的理解是,SHA1加密服务提供程序无论如何都需要封送,它使用外部调用。 - Sam Saffron
1
幸运的是,我检查了一下,我正在使用未托管的MD5CryptoServiceProvider。喜欢你的性能分析示例! - pablo
Sam,你说得对,问题肯定出在别的地方。不过我有一个问题:有没有一种分块哈希的方法?我需要读取文件并进行哈希处理,能否在一次操作中完成? - pablo
1
TransformBlock和TransformFinalBlock函数看一下。 - Sam Saffron

3
SHA1CryptoServiceProvider类使用底层的Windows API实现,然而SHA1Managed速度相当快。
编辑:是的,可以逐步计算哈希值。使用TransformBlockTransformFinalBlock方法来完成此操作。

相当快可以有很多意思...结果相当快意味着慢了3倍....但每300毫秒30MB仍然相当快。 - Sam Saffron

0

谢谢。那是我现在正在使用的,我只是想知道是否有一种方法可以使它更快。我正在对整个文件进行哈希处理。 - pablo

0

根据哈希的应用,MD5可能不适用。MD5仅在错误纠正方面有用,已不再可行用于检查恶意文件篡改。

http://en.wikipedia.org/wiki/Md5#Vulnerability

简而言之,通过更改文件中的16个字节,可以轻松生成MD5碰撞。

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