[英]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);
為了加密,我們:
通過利用流,我們可以保持較低的內存占用,甚至可以非常有效地加密和解密大文件。
上面的代碼片段已准備好運行(在 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.