是否可以复制.NET HashAlgorithm(用于重复的增量散列结果)?

时间:2014-09-30 14:44:58

标签: c# clone md5 hashalgorithm

我有以下用例:

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

增量散列文件不是问题,just call TransformBlock and TransformFinalBlock

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

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

  

hash.copy()

     

返回哈希对象的副本(“clone”)。此可用于有效计算共享共同初始子字符串的字符串摘要

  

EVP_MD_CTX_copy_ex()可用于从中复制消息摘要状态   进去如果要散列大量数据,这非常有用   只在最后几个字节中有所不同。 out必须初始化   在调用此函数之前。

尽可能搜索,我找不到任何包含C#HashAlgorithm的库存,这样我就可以在调用它之前有效地Clone() ==复制这样的对象 TransformFinalBlock方法 - 然后继续使用克隆散列其余数据。

我发现C# reference implementation for MD5可能很容易适应克隆(*),但我更倾向于使用那些而不是将这样的东西引入代码库。

(*)实际上,据我所知,任何哈希算法(与加密/解密相反)我讨厌检查是可以轻易复制的,因为这样的算法所具有的所有状态都是一种形式的摘要。

所以我在这里遗漏了一些东西,或者标准的C#/ .NET接口实际上是不是提供了复制哈希对象的方法?


另一个数据点:

Microsoft为crypto services提供的自己的原生API有一个函数CryptDuplicateHash,其状态为doc,引用文档:

  

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

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


请注意。 MD5:用例不具有加密敏感性。只是可靠的文件校验和。

2 个答案:

答案 0 :(得分:4)

我意识到这并不是你所要求的,但是如果这与你解决的问题相符,那么另一种方法就是给你相同的保证&类似的流性能特征。我过去曾将此用于服务器到服务器文件传输协议,其中发送方/接收方始终不可用/可靠。当然,我控制了电线两侧的代码,我意识到你可能没有。在这种情况下,请忽略; - )

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

它将计划发送给接收方,接收方为新文件分配空间(文件长度%块大小告诉它最后一个块小于32MB)或打开现有文件。如果文件已经存在,则它运行相同的算法来计算相同大小的块的哈希值。与计划的任何不匹配导致它仅向发送方询问这些块(这将考虑尚未转移的块/所有0和损坏的块)。它做了这个(验证,请求块)在一个循环中工作,直到没有任何东西要求。然后它检查了计划的文件级哈希。如果文件级哈希是无效的,但块级哈希都是有效的,那么它可能意味着哈希委托或坏RAM(两者都非常罕见......我使用的是SHA-512)。这允许接收器从不完整的块或损坏的块中恢复,最坏情况下必须再次下载1个坏块,这可以通过调整块大小来抵消。

答案 1 :(得分:3)

SIGH

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

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

也可以将C++ implementation包装在C ++ / CLI包装器中 - 初步测试表明这似乎比普通的.NET库更快,但是不要接受我的话它


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

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