代码之家  ›  专栏  ›  技术社区  ›  Casey Flynn

nodejs加密模块,hash.update()将所有输入存储在内存中

  •  3
  • Casey Flynn  · 技术社区  · 9 年前

    我有一个代理文件从浏览器/客户端上传到AWS S3的API路由。

    此API路由尝试在上传文件时对其进行流式传输,以避免将文件的全部内容缓冲在服务器的内存中。

    然而,路由还尝试计算文件正文的MD5校验和。当文件的每个部分被分块时 hash.update() 方法与块一起调用。

    http://nodejs.org/api/crypto.html#crypto_hash_update_data_input_encoding

    var crypto = require('crypto');
    var hash = crypto.createHash('md5');
    function write (chunk) {
      // invoked many times as file is uploaded
      hash.update(chunk);
    }
    function done() {
      // will hash buffer all chunks in memory at this point?
      hash.digest('hex');
    }
    

    Hash的实例是否会缓冲文件的所有内容以执行哈希计算(从而破坏了避免在内存中缓冲整个文件内容的目标)?或者,MD5哈希值是否可以递增计算,而不需要整个输入来执行计算?

    2 回复  |  直到 9 年前
        1
  •  4
  •   Artjom B.    6 年前

    MD5和其他一些哈希函数基于 Merkle–DamgÃ¥rd construction 。它支持数据的增量/渐进/流哈希。在数据被转换为内部状态(其具有固定大小)之后,执行最后一个最终步骤以通过填充和处理最后一个块并随后通过简单地返回最终状态来生成最终散列。

    这可能也是为什么许多哈希库函数都是以这样的方式设计的,包括更新和最终确定步骤。

    要回答您的问题: 不,文件内容不保存在缓冲区中,而是转换为固定大小的内部状态。

        2
  •  4
  •   Maarten Bodewes    6 年前

    所有现代加密哈希函数的创建方式都是可以增量更新的。

    为了允许增量更新,消息的输入数据首先按块排列。这些块按顺序处理。为此,实现通常在内部缓冲输入,直到它有一个完整的块,然后与 当前状态 使用所谓的 压缩函数 初始状态通常简单地由预定的常数值组成。在呼叫期间 digest 最后一个块被填充(通常使用位填充和处理字节量的编码),并计算最终状态;这可能需要没有任何消息数据的附加块。可以执行最终操作,并最终返回结果哈希值。

    对于 MD5 这个 Merkle–DamgÃ¥rd construction 使用。这种常见结构也用于SHA-1和SHA-2。SHA-2是基于SHA-256(SHA-224)和SHA-512(SHA-384、SHA-512/224和SHA-512/256)算法的散列家族。MD5特别使用512位的块大小和128位的内部状态。最后一个块的内部状态(包括填充)只需直接输出,无需对MD5、SHA-1、SHA-256和SHA-512进行任何后处理。

    凯克被选为SHA-3。它是基于海绵的结构,具有特定的压缩功能。这不是MerkleDamgrd哈希-这是一个很大的原因 为什么? 它被选为SHA-3。它仍然具有MerkleDamgrd哈希的所有更新属性 设计 以与SHA-2兼容。它像前面提到的散列一样分割和缓冲块,但它具有更大的内部状态,并对输出执行最终操作,这可以说是更安全的。

    因此,当您使用现代哈希构造(如MD5)时,您在不知不觉中执行了额外的缓冲。幸运的是,512位+128位状态大小的单个块的缓冲不会导致内存耗尽。在计算最终哈希值之前,哈希实现当然不需要缓冲整个消息。


    笔记:

    • MD5和SHA-1被认为是不安全的,不具有抗冲突性, 尤其地 当涉及验证内容时;
    • “压缩函数”是一个特定的密码概念;它不是 LSZIP或任何类似的文件;
    • 可能有专门的、理论上的散列来执行不同的值计算-理论上讲,不需要将输入消息分割成块并按顺序对块进行操作。不用担心,这些不太可能在你正在使用的图书馆中;
    • 类似地,实现可能决定一次缓冲更多的块,但幸运的是,这也非常罕见。通常只使用一个块作为缓冲区-在某些情况下,缓冲几个块可能会更有性能;
    • 出于效率的原因,一些低级实现可能需要您自己提供块。