11

我有以下用例:

  • 从文件中读取 n 个字节
  • 计算这 n 个字节的 (MD5) 哈希
  • 从文件中读取接下来的 m 个字节
  • 为文件计算 (MD5) 哈希,最多 n+m 个字节

增量散列文件不是问题,只需调用TransformBlockandTransformFinalBlock

问题是我需要多个共享其开始字节的数据散列,但是在我调用TransformFinalBlock读取Hash第一个n字节后,我无法继续使用同一个对象进行散列并且需要一个新的对象。

搜索问题时,我发现PythonOpenSSL都可以选择复制散列对象来实现此目的:

hash.copy()

返回散列对象的副本(“克隆”)。这可以用来有效地计算共享一个公共初始子串的字符串的摘要

 

EVP_MD_CTX_copy_ex() 可用于将消息摘要状态从输入复制到输出。如果要散列仅在最后几个字节中不同的大量数据,这很有用。out 必须在调用此函数之前进行初始化。

尽我所能搜索,我找不到任何可以让我在调用其方法之前有效== 复制这样一个对象的股票 C# HashAlgorithm的东西——然后继续用克隆对其余数据进行哈希处理。Clone()TransformFinalBlock

我发现了一个MD5 的 C# 参考实现,它可以很容易地适应支持克隆(*),但强烈希望使用现有的东西而不是将这样的东西引入代码库。

(*) 事实上,据我所知,我费心检查的任何散列算法(与加密/解密相反)都是可以复制的,因为这种算法的所有状态都是摘要的一种形式。

那么我在这里遗漏了什么还是标准 C#/.NET 接口实际上没有提供复制哈希对象的方法?


另一个数据点:

微软自己的加密服务本机 API有一个函数CryptDuplicateHash,其状态的文档引用:

CryptDuplicateHash 函数可用于创建以相同内容开头的两个不同内容的单独哈希。

自 Windows XP 以来一直存在。:-|


请注意。MD5:用例对密码不敏感。只是可靠的文件校验和。

4

2 回答 2

4

我意识到这并不完全是您所要求的,但如果这与您尝试解决的问题相匹配,那么它是一种替代方法,可以为您提供相同的保证和类似的流媒体性能特征。我过去曾将其用于服务器到服务器的文件传输协议,其中发送方/接收方并不总是可用/可靠。当然,我可以控制电线两侧的代码,我意识到你可能无法控制。在这种情况下,请忽略;-)

我的方法是设置 1 个处理整个文件的 HashAlgorithm 和另一个用于散列固定大小的文件块的方法——不是滚动散列(避免你的问题),而是独立的散列。所以想象一个 1034MB (1 GB + 10 MB) 的文件在逻辑上分成 32MB 的块。发送方加载文件,同时在文件级和块级 HashAlgorithm 上调用 TransformBlock。当它到达 32MB 的末尾时,它在块级别调用 TransformFinalBlock,记录该块的哈希,并为下一个块重置/创建一个新的 HashAlgorithm。当它到达文件末尾时,它在文件和块级散列器上调用 TransformFinalBlock。现在,发送者有一个传输“计划”,包括文件名、文件大小、文件哈希以及每个块的偏移量、长度和哈希。

它将计划发送给接收方,接收方要么为新文件分配空间(文件长度% 块大小告诉它最后一个块小于 32MB),要么打开现有文件。如果文件已经存在,它会运行相同的算法来计算相同大小块的哈希值。与计划的任何不匹配都会导致它仅向发送者询问这些块(这将解释尚未传输的块/全 0 和损坏的块)。它这样做(验证,请求块)循环工作,直到没有任何东西可以请求。然后它根据计划检查文件级哈希。如果文件级散列无效但块级散列全部有效,则可能意味着散列冲突或 RAM 损坏(两者都极为罕见……我使用了 SHA-512)。

于 2014-10-17T20:25:52.403 回答
3

库存 .NET 库不允许这样做。伤心。无论如何,有几个选择:

  • MD5Managed纯 .NET(“默认”MD5 RSA 许可证)
  • ClonableHash通过 PInvoke 包装 MS Crypto API(可能需要一些工作从Org.Mentalis命名空间中提取它,但许可证是允许的)

例如,也可以在 C++/CLI 包装器中包装C++ 实现- 初步测试表明这似乎比普通的 .NET 库要快得多,但不要相信我的话。


因为,我自己也编写/改编了一个基于 C++ 的解决方案:https ://github.com/bilbothebaggins/md5cpp

它还没有投入生产,因为需求发生了变化,但这是一个很好的练习,我认为它工作得很好。(除了它不是纯 C# 实现。)

于 2014-11-21T20:26:32.647 回答