我正在尝试加密和解密上传到运行
express
的 Node.JS 服务器的文件。文件从 HTML 表单上传并发送到加密传入文件流的函数,将其保存到服务器上的文件中。要下载文件,将从服务器检索加密文件并解密,然后将其发送回客户端。
我能够在服务器上正确地将文件保存为纯文本,无需加密,并通过直接将响应管道传输到
readStream
或 writeStream
(参见代码)来下载它,而不会出现任何损坏。然而,当我传入我的加密函数时,它输出的文件部分损坏。
损坏的示例:
========= input.txt ============
Testing Document!
This is just a testing document!
=================================
========= decrypted.txt =========
@h±²k5øcZxÁ·õ7ÌwBox!
5øcis is just a testing document!
=================================
NodeJS 路线:
app.post('/upload', (req, res) => {
const busboyInstance = busboy({ headers: req.headers });
// Create a write stream to save the uploaded file
let fileName;
let writeStream;
busboyInstance.on('file', (fieldname, file, filename) => {
fileName = 'encrypted_file.txt'; // Modify the filename as needed
const filePath = __dirname + '/' + fileName;
writeStream = fs.createWriteStream(filePath);
// Perform file encryption asynchronously. THIS PARTIALLY CORRUPTS THE FILE
/*
aesEncryptFileStream(file, writeStream, 'TESTESTESTESTESTESTESTESTESTESTE')
.then(() => {
file.resume(); // Consume the remaining stream
})
.catch((error) => {
console.error('Encryption error:', error);
res.status(500).send('Encryption error');
});*/
//For debugging purposes we will just copy the file. THIS WORKS FINE
file.pipe(writeStream);
});
busboyInstance.on('finish', () => {
res.end('Upload complete');
console.log('File upload complete');
});
req.pipe(busboyInstance);
});
// Set up a route for handling file decryption and download
app.get('/download', async (req, res) => {
try {
// Create a read stream from the encrypted file
const fileName = 'encrypted_file.txt'; // Modify the filename as needed
const filePath = __dirname + '/' + fileName;
const readStream = fs.createReadStream(filePath);
// Perform file decryption asynchronously. THIS PARTIALLY CORRUPTS THE FILE
//await aesDecryptFile(readStream, res, "TESTESTESTESTESTESTESTESTESTESTE");
//For debugging purposes we will just copy the file. THIS WORKS FINE
readStream.pipe(res);
console.log('File download complete');
} catch (error) {
console.error('Error:', error);
res.status(500).send('Server error');
}
});
密码学功能:
async function aesEncryptFileStream(inputStream, outputStream, secret) {
const algorithm = 'aes-256-cbc';
const iv = crypto.randomBytes(16); // Initialization vector.
const cipher = crypto.createCipheriv(algorithm, secret, iv);
return new Promise((resolve, reject) => {
inputStream.pipe(cipher).pipe(outputStream);
inputStream.on('end', () => {
resolve();
});
inputStream.on('error', (err) => {
reject(err);
});
});
}
async function aesDecryptFile(inputStream, outputStream, secret) {
const algorithm = 'aes-256-cbc';
const iv = crypto.randomBytes(16); // Initialization vector.
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(secret), iv);
return new Promise((resolve, reject) => {
inputStream.pipe(decipher).pipe(outputStream);
inputStream.on('end', () => {
resolve();
});
inputStream.on('error', (err) => {
reject(err);
});
});
}
我最初认为这是一个标头问题,但经过进一步调查并尝试不同的标头组合,我仍然看到使用
/download
下载文件时返回部分损坏的数据。尝试删除加密功能并直接管道传输文件工作正常,所以我认为这是加密/解密功能的一些问题。
有谁知道如何解决这个问题吗?
加密和解密特定消息时,IV 需要相同。您需要将 IV 与加密数据一起存储,然后在再次解密时使用它。