C# 是否可以复制.NET哈希算法(用于重复的增量哈希结果)?

C# 是否可以复制.NET哈希算法(用于重复的增量哈希结果)?,c#,clone,md5,hashalgorithm,C#,Clone,Md5,Hashalgorithm,我有以下用例: 从文件中读取n个字节 为这n个字节计算(MD5)哈希 从文件中读取下一个m字节 为文件计算(MD5)哈希,最多n+m字节 增量散列文件不是问题 问题是,我需要共享起始字节的多个数据哈希,但在调用TransformFinalBlock读取第一个n字节的Hash后,我无法继续使用同一个对象进行哈希,需要一个新的 在搜索问题时,我发现两者都有复制哈希对象的选项,正是为了这个目的: hash.copy() 返回哈希对象的副本(“克隆”)。此可用于有效计算共享公共初始子字符串的字符串摘

我有以下用例:

  • 从文件中读取n个字节
  • 为这n个字节计算(MD5)哈希
  • 从文件中读取下一个m字节
  • 为文件计算(MD5)哈希,最多n+m字节
增量散列文件不是问题

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

在搜索问题时,我发现两者都有复制哈希对象的选项,正是为了这个目的:

hash.copy()

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

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

尽管我在搜索,但我找不到任何有助于我有效地
Clone()
==在调用其
TransformFinalBlock
方法之前复制这样一个对象的股票C#,然后继续用克隆散列其余数据

我发现了一个可以简单地修改以支持克隆(*)的方法,但是我更愿意使用现有的方法,而不是将这样的方法引入到代码库中

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

那么,我是否遗漏了一些东西,或者标准的C#/.NET接口实际上没有提供复制散列对象的方法


另一个数据点:

Microsoft自己的本机API for有一个函数,其中的文档状态为quote:

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

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



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

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

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

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

stock.NET库不允许这样做。悲哀的无论如何,有两种选择:

  • (“默认”MD5 RSA许可证)
  • 通过PInvoke包装MS Crypto API(可能需要一些工作从
    Org.Mentalis
    名称空间中提取,但许可证是允许的)
例如,也可以在C++/CLI包装器中包装a—初步测试表明,这似乎比普通的.NET库快得多,但请不要相信我的话


自从,我还编写了一个基于C++的解决方案:


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

它的一个问题是不容易克隆,一些类可能使用本机资源或调用带有句柄的专用硬件。这些类型的类不容易克隆。@Scott-谢谢。是的,我想有些课可能会。尽管如此,那些没有的,比如MD5,应该是可以克隆的。所以这是不可能的?似乎如果你想要一个肤浅的副本,你就必须迭代整个过程,然后自己创建它。@MartinBa C