使用加密模块的流功能获取文件的哈希(即:没有 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.update
和 hash.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)的主要内容,如果未能解决你的问题,请参考以下文章