Node.js使用AES加密大文件

18

我尝试使用以下代码对一个1 GB的文件进行加密。但是Node.js会因为"致命错误:JS分配内存失败 - 进程内存不足"而中止。我该怎么处理?

var fs = require('fs');
var crypto = require('crypto');
var key = "14189dc35ae35e75ff31d7502e245cd9bc7803838fbfd5c773cdcd79b8a28bbd";
var cipher = crypto.createCipher('aes-256-cbc', key);
var file_cipher = "";
var f = fs.ReadStream("test.txt");
f.on('data', function(d) {
    file_cipher = file_cipher + cipher.update(d, 'utf8', 'hex');
});
f.on('end', function() {  
    file_cipher = file_cipher + cipher.final('hex');
});   
3个回答

48

你可以将加密的文件直接写入磁盘,而不是将整个文件缓存在内存中:

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

var key = '14189dc35ae35e75ff31d7502e245cd9bc7803838fbfd5c773cdcd79b8a28bbd';
var cipher = crypto.createCipher('aes-256-cbc', key);
var input = fs.createReadStream('test.txt');
var output = fs.createWriteStream('test.txt.enc');

input.pipe(cipher).pipe(output);

output.on('finish', function() {
  console.log('Encrypted file written to disk!');
});

谢谢!顺便问一下,我怎么知道加密什么时候完成? - Jan Leo
5
你可以在 output 上监听 finish 事件。 - mscdex
3
你可以使用 crypto.createDecipher 替代 crypto.createCipher 来以完全相同的方式进行解密。 - Ryan Plant
3
createCipher已被弃用。 - SamB
有关使用最新方法的类似程序,请参见此回答 - AirOne
显示剩余3条评论

12

crypto.createCipher() 不带初始化向量已经自 NodeJS v10.0.0 起被废弃,请改用crypto.createCipheriv()

你也可以使用stream.pipeline() 来代替使用pipe方法并将其转换为promise或async/await流程中的操作(使代码更加易于使用promise或async/await编写)。

const {createReadStream, createWriteStream} = require('fs');
const {pipeline} = require('stream');
const {randomBytes, createCipheriv} = require('crypto');
const {promisify} = require('util');

const key = randomBytes(32); // ... replace with your key
const iv = randomBytes(16); // ... replace with your initialization vector

promisify(pipeline)(
        createReadStream('./text.txt'),
        createCipheriv('aes-256-cbc', key, iv),
        createWriteStream('./text.txt.enc')
)
.then(() => {/* ... */})
.catch(err => {/* ... */});

使用NodeJS 15+,您可以简化它(跳过promisify部分)

const {createReadStream, createWriteStream} = require('fs');
const {pipeline} = require('stream/promises');
const {randomBytes, createCipheriv} = require('crypto');

const key = randomBytes(32); // ... replace with your key
const iv = randomBytes(16); // ... replace with your initialization vector

pipeline(
  createReadStream('./text.txt'),
  createCipheriv('aes-256-cbc', key, iv),
  createWriteStream('./text.txt.enc')
)
.then(() => {/* ... */})
.catch(err => {/* ... */});

我在解密文件时遇到了以下错误:Error: Unsupported state or unable to authenticate data - Prathamesh More
1
@PrathameshMore 如果没有看到文件解密的代码,很难确定问题出在哪里。请注意,您应该将密钥和初始化向量存储在某个地方(例如文件),randomBytes 仅用于演示目的。 - Ihor Sakailiuk
1
自 Node 版本 15 开始,Stream Promises API 已经可用(文档)。 - Felix Lechenbauer

3

我会简单地使用Fileger来完成它。这是一个基于Promise的包,也是NodeJS文件系统的一个干净的替代品。

const fileger = require("fileger")
const file = new fileger.File("./your-file-path.txt");

file.encrypt("your-password") // this will encrypt the file
   .then(() => {
      file.decrypt("your-password") // this will decrypt the file
   })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接