使用节点加密 scryptSync 哈希密码
hash password using node crypto scryptSync
我需要保护电子应用程序的用户输入密码,以创建用于加密 AES 加密的密钥。正如这里建议的那样,我已经用 scryptSync
函数替换了 createHash
函数。我不确定盐。
// 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 或盐。
当然这对密文来说是最重要的。您希望尽可能少地复制它。
我需要保护电子应用程序的用户输入密码,以创建用于加密 AES 加密的密钥。正如这里建议的那样,我已经用 scryptSync
函数替换了 createHash
函数。我不确定盐。
// 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 或盐。
当然这对密文来说是最重要的。您希望尽可能少地复制它。