我需要保护电子应用程序的用户输入密码,以创建用于加密 AES 加密的密钥。正如此处所建议的那样,我已将
createHash
函数替换为 scryptSync
函数。我不确定盐的分量。
// this is the old method I've used to hash the password to obtain the correct lenght for aes-256-gcm
// let key = crypto.createHash('sha256')
// .update(data.password)
// .digest();
// salt creation
let salt = crypto.randomBytes(64);
let key = crypto.scryptSync(data.password, salt, 32);
是否需要传递给
randomBytes
函数以实现aes-256-gcm
加密算法的预定义大小?
此外,当我将盐附加到加密输出时,我正在使用此代码
let encryptedData = Buffer.concat([cipher.update(base64, 'utf8'), cipher.final()]);
let payload = `${salt.toString('base64')}:${iv.toString('base64')}:${encryptedData.toString('base64')}`;
由于我使用
join()
函数来合并多个编码字符串,因此当需要对加密的输出文件进行解码时,我需要一种方法来拆分它们。目前我正在使用这种方式,但我发现我需要提取盐来检查密码。有没有办法做得更好?
const decryptData = (data) => {
let output = [];
// I need the salt here but the file needs to be splitted before
let key = crypto.scryptSync(data.password, 'salt', 32);
return new Promise( (resolve, reject) => {
fs.readFile(data.path, 'utf8', (err, content) => {
if(err) return reject(err);
let fileContents = content.split(' ');
output = fileContents.map( (file) => {
let [salt, iv, content] = file.split(':');
let cipher = crypto.createDecipheriv('aes-256-gcm', key, Buffer.from(iv, 'base64'));
let decrypted = cipher.update(content, 'base64', 'utf8');
return decryptedData;
});
resolve(output);
});
});
}
正如 Node.js 所示,哈希值至少需要 128 位或 16 字节。 64 字节确实太多了,我最多可以使用 256 位,但对于密码来说 128 位确实足够了。由于您的目标似乎是最大安全性,因此请尝试 32 字节。不要忘记,要求强密码至少同样重要,甚至更重要。
当前您正在使用
scryptSync
的默认成本参数。这可能不是一个好主意,因为它默认设置为 16384。越高越好,因此请尝试看看什么最适合您的特定目标平台。
请注意,你们都知道 salt 和 IV 大小(以字节为单位)。这意味着在将二进制字符串编码为 Base 64 之前,从二进制字符串中获取它们同样容易。这也有一些优点:如果将二进制数据加载到
Buffer
中,那么您可以简单地使用 之类的方法from
获得不同的视图,然后可以表示 IV 或盐,而无需复制数据。
这当然对于明文来说是最重要的。您希望尽可能少地复制该内容。