首页 文章

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

提问于
浏览
11

我有以下用例:

  • 从文件中读取n个字节

  • 这些n个字节的计算(MD5)哈希

  • 从文件中读取下一个m字节

  • 最多n m字节的文件的计算(MD5)哈希

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

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

在搜索问题时,我看到Python以及OpenSSL都有一个复制散列对象的选项,正是出于这个目的:

hash.copy()返回哈希对象的副本(“clone”) . 这可以用于有效地计算共享公共初始子字符串的字符串的摘要 .

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

正如我可能搜索的那样,我找不到任何包含C#HashAlgorithm的股票,它可以让我在调用它的 TransformFinalBlock 方法之前有效地复制这样的对象 - 然后继续用克隆散列其余的数据 .

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

(*)实际上,据我所知,任何哈希算法(与加密/解密相反)我都很难检查,因为这种算法所具有的所有状态都是一种摘要形式 .

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


另一个数据点:

微软自己的crypto services原生API有一个函数CryptDuplicateHash,其中的文档状态,引用:

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

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


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

2 回答

  • 4

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

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

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

  • 3

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

    • MD5Managed pure .NET("default" MD5 RSA许可证)

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

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


    既然如此,我自己也编写/改编了一个基于C的解决方案:https://github.com/bilbothebaggins/md5cpp

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

相关问题