簡體   English   中英

在下載時加密 zip 文件夾,然后用 Node.js 解密?

[英]Encrypt zip folder on download and then decrypt with Node.js?

所以我有一個應用程序可以下載一個 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 無法打開文件夾錯誤)。

我的加密函數非常基本,在 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 無法打開文件夾錯誤”。 我真的不知道我在這些東西方面在做什么,所以任何幫助將不勝感激,我很失落哈哈。

這里的問題是您正在獲取文件的塊,分別加密它們,然后將它們寫入磁盤。 你最終得到的是文件的一堆不同的加密部分,而不是一個加密文件。 您可能希望在這里使用 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. 將密碼的輸出通過管道傳輸到文件

通過利用流,我們可以保持較低的內存占用,甚至可以非常有效地加密和解密大文件。

上面的代碼片段已准備好運行(在 Node v12.18.3 上測試)。

Node 加密 API 仍然足夠低級,很多都可能出錯。 例如,您可能希望向加密數據添加 HMAC 以確保其完整性。

我的建議是使用 libsodium 或類似的 Javascript 綁定,以便您獲得更高級別的 API。 我能找到的原生綁定並沒有給人留下最成熟的印象,也沒有使用過時的 libsodium 版本。

因此,我的建議是使用https://github.com/dchest/tweetnacl-js,因為它已經過專業審核。 API 也非常簡單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM