使用加密模块的流功能获取文件的哈希(即:没有 hash.update 和 hash.digest)

Posted

技术标签:

【中文标题】使用加密模块的流功能获取文件的哈希(即:没有 hash.update 和 hash.digest)【英文标题】:Obtaining the hash of a file using the stream capabilities of crypto module (ie: without hash.update and hash.digest) 【发布时间】:2013-09-10 14:28:49 【问题描述】:

node.js 的 crypto 模块(至少在撰写本文时)仍被认为不稳定,因此 API 可能会发生变化。事实上,互联网上每个人用来获取文件哈希(md5,sha1,...)的方法都被认为是遗留的(来自Hash class的文档)(注意:强调我的):

类:哈希

用于创建数据哈希摘要的类。

它是一个可读可写的流。写入的数据是 用于计算哈希。一旦流的可写侧是 结束后,使用 read() 方法获取计算的哈希摘要。这 旧版更新和摘要方法也受支持。

由 crypto.createHash 返回。

尽管 hash.updatehash.digest 被认为是旧版,但引用的 sn-p 上方显示的示例正在使用它们。

在不使用那些遗留方法的情况下获取哈希的正确方法是什么?

【问题讨论】:

【参考方案1】:

来自问题中引用的 sn-p:

[Hash 类] 它是一个可读可写的流。写入的数据是 用于计算哈希。一旦流的可写侧是 结束,使用 read() 方法获取计算得到的哈希摘要。

所以你需要散列一些文本是:

var crypto = require('crypto');

// change to 'md5' if you want an MD5 hash
var hash = crypto.createHash('sha1');

// change to 'binary' if you want a binary hash.
hash.setEncoding('hex');

// the text that you want to hash
hash.write('hello world');

// very important! You cannot read from the stream until you have called end()
hash.end();

// and now you get the resulting hash
var sha1sum = hash.read();

如果要获取文件的哈希,最好的方法是从文件中创建一个 ReadStream 并将其通过管道传输到哈希中:

var fs = require('fs');
var crypto = require('crypto');

// the file you want to get the hash    
var fd = fs.createReadStream('/some/file/name.txt');
var hash = crypto.createHash('sha1');
hash.setEncoding('hex');

fd.on('end', function() 
    hash.end();
    console.log(hash.read()); // the desired sha1sum
);

// read all file and pipe it (write it) to the hash object
fd.pipe(hash);

【讨论】:

是否可以从哈希对象中获取数据内容? @sunnycmf 你的意思是什么数据?如果您的意思是您正在散列的原始数据,那么我不这么认为。如果您指的是计算的哈希值,那么只需使用hash.read() 是的,我的意思是原始数据,因为想读取文件一次并获取数据和 sha1 哈希。 而不是fd.on('end'),最好处理hash.on('finish'),这不需要调用hash.end() 在我看来,管道到哈希对象的方法比老式的stream.on('data', data => hash.update(data)) 和后来的digest('hex') 变化无常。当我按照上面的方式进行确切的实验但忽略了hash.read() 时,因为我想在写流的finish 事件上这样做,我什么也没得到,没有任何价值。只有当我在上面的end 事件处理程序中(或@HermanKan 建议的finish)中调用hash.read() 时,我才能得到哈希。在data 事件处理程序中调用hash.update(...) 没有这样的问题,然后我可以随时随地获取哈希输出。【参考方案2】:

卡洛斯回答的简短版本:

var fs = require('fs')
var crypto = require('crypto')

fs.createReadStream('/some/file/name.txt').
  pipe(crypto.createHash('sha1').setEncoding('hex')).
  on('finish', function () 
    console.log(this.read()) //the hash
  )

【讨论】:

【参考方案3】:

一个为哈希摘要返回 Promise 的 ES6 版本:

function checksumFile(hashName, path) 
  return new Promise((resolve, reject) => 
    const hash = crypto.createHash(hashName);
    const stream = fs.createReadStream(path);
    stream.on('error', err => reject(err));
    stream.on('data', chunk => hash.update(chunk));
    stream.on('end', () => resolve(hash.digest('hex')));
  );

【讨论】:

我喜欢这个。这里可能的改进:gist.github.com/F1LT3R/2e4347a6609c3d0105afce68cd101561【参考方案4】:

进一步润色,ECMAScript 2015

hash.js:

'use strict';

function checksumFile(algorithm, path) 
  return new Promise(function (resolve, reject) 
    let fs = require('fs');
    let crypto = require('crypto');

    let hash = crypto.createHash(algorithm).setEncoding('hex');
    fs.createReadStream(path)
      .once('error', reject)
      .pipe(hash)
      .once('finish', function () 
        resolve(hash.read());
      );
  );


checksumFile('sha1', process.argv[2]).then(function (hash) 
  console.log('hash:', hash);
);
node hash.js hash.js
hash: 9c92ec7acf75f943aac66ca17427a4f038b059da

至少早在 v10.x 就可以工作:

node --version
v10.24.1

【讨论】:

对我不起作用 - 需要在 this.read() 之前添加 this.end() 你的意思可能是.once('end', ...【参考方案5】:
var fs = require('fs');
var crypto = require('crypto');
var fd = fs.createReadStream('data.txt');
var hash = crypto.createHash('md5');
hash.setEncoding('hex');
fd.pipe(hash);
hash.on('data', function (data) 
    console.log('# ',data);
);

【讨论】:

你应该解释你的代码,以便其他人能够理解它【参考方案6】:

我成功使用Node模块hash,代码变得非常简洁和简短。它返回一个 Promise,因此您可以将它与 await 一起使用:

const hasha = require('hasha');

const fileHash = await hasha.fromFile(yourFilePath, algorithm: 'md5');

【讨论】:

以上是关于使用加密模块的流功能获取文件的哈希(即:没有 hash.update 和 hash.digest)的主要内容,如果未能解决你的问题,请参考以下文章

初试hashlib加密模块

#yyds干货盘点#哈希算法和多种加密算法综合使用

Python3-hashlib模块-加密算法之安全哈希

哈希加密算法

node.js密码加密实践

入门学习|哈希函数与哈希算法