javascript - nodejs - 包含带有加密文件数据的 iv
问题描述
我正在重构此代码以加密文件以将其放入类中。
async encryptData(file, password){
this.salt = crypto.randomBytes(32);
this.key = crypto.scryptSync(password, this.salt, 32);
//this.buffer = await fs.readFile(file.tempFilePath);
this.base64 = dataURI.getBase64DataURI(file.data, file.mimetype);
this.iv = crypto.randomBytes(16);
this.cipher = crypto.createCipheriv('aes-256-gcm', this.key, this.iv);
this.encryptedData = Buffer.concat([this.cipher.update(this.base64, 'utf8'), this.cipher.final()]);
this.output = `${this.iv.toString('hex')}:${this.encryptedData.toString('hex')}`;
//fs.writeFile(...)
}
目标是在将文件转换为 base64 后使用一个库加密文件,该库将保留稍后用于解密并将文件保存为原始格式的 mime 类型。在我的最后一行代码中,我有一个“输出”变量,它将创建一个包含iv
加密数据的字符串。有没有更好的方法来包含iv
数据,这样我就可以避免使用该toString()
功能?如果可能的话,当我需要解密文件时如何获取 iv 和数据?
更新:
经过一些测试并在答案中删除base64文件编码的建议之后,我以这种方式重构了代码。似乎工作正常,但任何改进它的建议将不胜感激。
async runServer(){
this.app.post('/encrypt', async (req, res) => {
let password = req.body.password;
for(let file in req.files){
await this.encryptData(req.files[file], password);
}
//res.send({});
});
this.app.post('/decrypt', async (req, res) => {
let password = req.body.password;
for(let file in req.files){
await this.decryptData(req.files[file], password);
}
//res.send({});
});
}
async encryptData(file, password){
this.salt = crypto.randomBytes(32);
this.key = crypto.scryptSync(password, this.salt, 32);
this.iv = crypto.randomBytes(16);
this.cipher = crypto.createCipheriv('aes-256-gcm', this.key, this.iv);
this.encryptedData = Buffer.concat([this.salt, this.iv, this.cipher.update(file.data), this.cipher.final()]);
this.output = path.format({dir: this.tmpDir, base: file.name});
await fs.writeFile(this.output, this.encryptedData);
}
async decryptData(file, password){
this.salt = file.data.slice(0, 32);
this.key = crypto.scryptSync(password, Buffer.from(this.salt, 'binary'), 32);
this.iv = file.data.slice(32, 48);
this.encryptedData = file.data.slice(48);
this.decipher = crypto.createDecipheriv('aes-256-gcm', this.key, this.iv);
this.decryptedData = this.decipher.update(this.encryptedData);
this.output = path.format({dir: this.tmpDir, base: file.name});
await fs.writeFile(this.output, this.decryptedData);
}
更新 1:
正如建议的那样,我已经实现了 GCM required 标签。如果我没记错的话,它将有 16 个字节的长度。我不确定我需要在哪里将它传递到解密过程以及如何提取它。
//file encryption
this.encryptedData = Buffer.concat([this.salt, this.iv, this.cipher.update(file.data), this.cipher.final(), this.cipher.getAuthTag()]);
//file decryption
this.salt = file.data.slice(0, 32);
this.key = crypto.scryptSync(password, Buffer.from(this.salt, 'binary'), 32);
this.iv = file.data.slice(32, 48);
//How I extract the GCM tag at the end of the data?
//this.tag = file.data.slice(48, 64);
this.encryptedData = file.data.slice(48);
//Where I should pass the extracted GCM tag?
this.decipher = crypto.createDecipheriv('aes-256-gcm', this.key, this.iv);
this.decryptedData = Buffer.concat([this.decipher.update(this.encryptedData), this.decipher.final()]);
解决方案
通常,IV 和密文在二进制级别连接。如果需要转换为字符串,请使用合适的二进制到文本编码,例如 Base64:
var encryptedData = Buffer.concat([iv, encryptedData]).toString('base64')
console.log(encryptedData)
IV 不是秘密的,因此可以在未加密的情况下发送。此外,:
不需要分隔符(如 ),因为 IV 具有块大小的长度(AES 为 16 字节),因此分隔标准已知:
var encryptedDataBuffer = Buffer.from(encryptedData, 'base64')
var iv = encryptedDataBuffer.slice(0, 16)
var ciphertext = encryptedDataBuffer.slice(16)
十六进制也可以用作二进制到文本的编码(但这在 50% 时的效率低于 Base64 在 75% 时的效率)。如果密文必须是 URL 安全的,则可以应用Base64url而不是 Base64,或者可以执行URL 编码。
由于您使用的是 GCM,因此还必须考虑(非秘密)身份验证标签。您的代码中似乎缺少这点。该标签由 确定cipher.getAuthTag()
,是解密所需的(更准确地说是在解密期间进行身份验证),通常附加到密文:iv|ciphertext|tag
。标签的分离是可行的,因为标签的长度是已知的(默认为 16 字节)。
此外,对于每个密钥生成,都应生成一个新的随机(非秘密)盐,并将其类似地连接起来:salt|iv|ciphertext|tag
.
顺便说一句,加密前文件的Base64编码一般是不需要的,实际上二进制数据是可以加密的。Base64 编码只会增加数据量。
推荐阅读
- clojure - 如何过滤地图并将其与另一个集合进行比较
- vue.js - VuePress 使用无效的资产地址构建损坏的 html
- firebase - Firebase/Google Cloud Storage 如何存储图片
- azure - 如何在使用 Azure 服务总线队列功能时使用更新的信息重新排队消息?
- excel - Excel VBA:如何将特定工作表合并到同一个工作簿中?
- tensorflow - 在所有架构中,验证损失的减少不小于 0.4
- javascript - 使用 JSON 的最快方法是什么?
- node.js - 希伯来文文本呈现为随机符号
- css - 为什么媒体查询不适用于移动设备?
- c# - 替换用户在句子中输入的单词,然后输出句子,但使用删失/替换的单词