【问题标题】:Encrypt zip folder on download and then decrypt with Node.js?下载时加密 zip 文件夹,然后使用 Node.js 解密?
【发布时间】:2020-06-18 15:12:18
【问题描述】:

所以我有一个应用程序可以下载一个包含一堆音频文件的 zip 文件夹。我想在下载时加密该 zip 文件,然后能够在应用程序中的某个其他位置解密该 zip 文件,以便将其提取。我有使用 Node 的 Crypto 包和 CTR 模式的 AES-256 进行加密和解密的基本逻辑,但在过程结束时我似乎无法获得可用的 zip 文件。

这是我用来下载 zip 文件的 http.get 请求

http.get(fileURI).on('response', function(res) {
    res.on('data', function(chunk) {
        let encryptedChunk = encrypt(chunk);
        writeStream.write(encryptedChunk);
    }).on('end', function() {
        writeStream.end();
    })
})

因此,get 请求会在下载数据时对其进行加密,并将其发送到对特定文件打开的 writeStream,然后在 zip 完成下载时结束 writestream。这似乎加密正确,因为我无法打开 zip 文件(弹出 Windows 无法打开文件夹错误)。

我的 encrypt 函数非常基本,在 http 请求中调用如下所示:

function encrypt(data) {
    try {
        let cipher = crypto.createCipher('aes-256-ctr', key); // key is a random string
        let encrypted = Buffer.concat([cipher.update(new Buffer(data, "utf8")), cipher.final()]);
        return encrypted;
    } catch (exception) {
        console.error(exception);
    }
}

然后我有一个函数会创建一个尝试解密此文件的 readStream,它看起来像这样:

function decryptzip() {
    // assume there are a bunch of necessary filepaths up here

    let readStream = fs.createReadStream(downloadedZipFilePath);
    let writeStream = fs.createWriteStream(newDecryptedZipFilePath);
    readStream.on('data', (chunk) => {
        let decryptedChunk = decrypt(chunk);
        writeStream.write(decryptedChunk); // the goal of this write stream is to have a usable zip file once it closes
    }).on('finish', () => {
        writeStream.end();
    })
}

然后我的实际解密函数如下所示:

function decrypt(data) {
    try {
        let decipher = crypto.createDecipher('aes-256-ctr', key); // same key used in encrypt
        let decrypted = Buffer.concat([decipher.update(data), decipher.final()]);
        return decrypted;
    } catch (exception) {
        console.error(exception);
    }
}

这些加密和解密函数都可以使用纯文本查找,但“解密”的 zip 文件仍然无法使用,当我尝试查看里面的内容时,会出现“Windows 无法打开文件夹错误”。我真的不知道我在这方面做什么,所以任何帮助都将不胜感激,我很迷茫哈哈。

【问题讨论】:

    标签: javascript node.js encryption cryptography node-crypto


    【解决方案1】:

    这里的问题是您正在获取文件的块,分别加密它们,然后将它们写入磁盘。你最终得到的是文件的一堆不同的加密部分,而不是一个加密文件。您可能希望在这里使用 Node 的流功能:

    const http = require('http');
    const { createWriteStream, createReadStream } = require('fs');
    const { createCipheriv, createDecipheriv, randomBytes } = require('crypto');
    const { pipeline } = require('stream');
    const { promisify } = require('util');
    
    const pipelineAsync = promisify(pipeline);
    
    const downloadAndEncryptFile = async (uri, path) => {
      const response = await new Promise((resolve, reject) => {
        http.get(uri).on('response', resolve).on('error', reject);
      });
    
      const secret = randomBytes(32);
      const iv = randomBytes(16);
    
      await pipelineAsync(
        response,
        createCipheriv('aes-256-ctr', secret, iv),
        createWriteStream(path),
      );
    
      return { secret: secret.toString('base64'), iv: iv.toString('base64'), path };
    };
    
    const decryptFile = async ({ path, secret, iv }) => {
      const secretBuf = Buffer.from(secret, 'base64');
      const ivBuf = Buffer.from(iv, 'base64');
    
      await pipelineAsync(
        createReadStream(path),
        createDecipheriv('aes-256-ctr', secretBuf, ivBuf),
        createWriteStream(`${path}-decrypted`),
      );
    };
    
    downloadAndEncryptFile('http://www.google.com/', 'encrypted-path')
      .then(decryptFile);
    

    为了加密,我们:

    1. 发出请求并接收响应对象,这是一个可读流,
    2. 通过一个密码传送整个响应,
    3. 将密码的输出通过管道传输到文件

    通过利用流,我们可以减少内存占用,甚至可以非常有效地加密和解密大文件。

    上面的 sn-p 已经可以运行了(在 Node v12.18.3 上测试过)。

    【讨论】:

      【解决方案2】:

      Node 加密 API 仍然足够低级,可能会出现很多问题。例如,您可能希望向加密数据添加 HMAC 以确保其完整性。

      我的建议是使用 libsodium 或类似的 Javascript 绑定,以便获得更高级别的 API。我能找到的本机绑定没有给人留下最成熟的印象,也没有使用过时的 libsodium 版本。

      因此,我的建议是使用https://github.com/dchest/tweetnacl-js,因为它已经过专业审核。 API 也非常简单。

      【讨论】:

      • 我同意你的建议,但这根本不能回答问题!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-26
      • 2021-10-20
      • 1970-01-01
      • 2015-04-15
      相关资源
      最近更新 更多