【问题标题】:Node.js crypto: too short encryption keyNode.js 加密:加密密钥太短
【发布时间】:2020-08-09 14:50:03
【问题描述】:

我想使用 AES-256 加密用户的数据,以便将其安全地存储在我的数据库中。但是,我的问题是密钥必须是 32 个字符长。但是我的用户的密码通常要短得多。有没有办法“延长”密码的长度?

我还想到了人造密码通常很弱的事实。所以我需要某种将密码“链接”到加密密钥的功能?

这是我用来加密和解密的代码:

const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const key; //Here I would get the password of the user

function encrypt(text) {
   const iv = crypto.randomBytes(16);
   let cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
   let encrypted = cipher.update(text);
   encrypted = Buffer.concat([encrypted, cipher.final()]);
   return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex') };
}

function decrypt(text) {
   let iv = Buffer.from(text.iv, 'hex');
   let encryptedText = Buffer.from(text.encryptedData, 'hex');
   let decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
   let decrypted = decipher.update(encryptedText);
   decrypted = Buffer.concat([decrypted, decipher.final()]);
   return decrypted.toString();
}

非常感谢您提前回答。

更新 1.0:

经过一番研究,我发现了以下代码:(Source)

const crypto = require('crypto');

// Uses the PBKDF2 algorithm to stretch the string 's' to an arbitrary size,
// in a way that is completely deterministic yet impossible to guess without
// knowing the original string
function stretchString(s, outputLength) {
  var salt = crypto.randomBytes(16);
  return crypto.pbkdf2Sync(s, salt, 100000, outputLength, 'sha512');
}

// Stretches the password in order to generate a key (for encrypting)
// and a large salt (for hashing)
function keyFromPassword(password) {
  // We need 32 bytes for the key
  const keyPlusHashingSalt = stretchString(password, 32 + 16);
  return {
    cipherKey: keyPlusHashingSalt.slice(0, 32),
    hashingSalt: keyPlusHashingSalt.slice(16)
  };
}

如果一切正常,这应该可以解决我的问题:从任何密码中,我都可以使用上述函数生成具有给定长度的安全加密密钥。同一个密码总是用函数keyFromPassword(password)生成同一个加密密钥吧?

更新 2.0:

感谢@President James K. Polk,他给了我一些重要的提示,我现在更新了我的代码。我希望现在一切都好。

【问题讨论】:

  • stretchString(password, 'salt', 24 + 48); 盐应该是不可预测的并且至少 16 个字节。它可以附加/附加到密文中,不需要是秘密。 keyPlusHashingSalt.slice(0, 24)AES-256 需要一个 32 字节的密钥; 24 字节为您提供 AES-192。最好坚持使用 AES-128 或 AES-256。 AES-192 没有任何问题,但一些实现不支持它,因此它是最不便携的。 hashingSalt: keyPlusHashingSalt.slice(24) 这应该是静脉注射吗? IV 必须是 16 个字节。

标签: node.js encryption aes cryptojs


【解决方案1】:

您不应将用户密码直接用作密钥。相反,您可以将它们用作pkbdf2 等密钥派生算法的输入。

正如this paper on PKBDF2 解释的那样:

不幸的是,用户选择的密码通常很短且 缺乏足够的熵 [11]、[21]、[18]。由于这些原因,他们不能 直接用作实现安全密码系统的密钥。这个问题的一个可能的解决方案是采用密钥派生 函数(KDF),这是一个函数,它采用初始源 密钥材料并从中派生一个或多个伪随机密钥。

为 Node.js 计算 pkbdf2 的库,例如 found here

【讨论】:

  • PKDBF2 和 SHA 在现代 GPU/RAM 暴力攻击中比 bcrypt security.stackexchange.com/questions/133239/… 弱得多
  • stackoverflow.com/questions/44797213/… 正在谈论加密用户密码。这与此处的 OP 所要求的问题不同,即使用用户密码作为加密密钥。
  • @frozen security.stackexchange.com/questions/133239/… 正在谈论散列密码,这又是一个与 OP 寻求帮助的问题不同的问题。
  • @auspicious99:该链接中描述的完全相同的注意事项适用于此用途,因此此处给出的建议在这里适用。但是,我认为将 PBKDF2 称为“弱得多”是夸大了这种情况。 bcrypt 肯定更好,但 PBKDF2 还可以。 PBKDF2 足够好 并且 受节点加密模块支持,而 bcrypt 不支持。
  • @PresidentJamesK.Polk 我认为加密哈希的安全要求可能不一定与加密密钥派生的安全要求相同。请参阅security.stackexchange.com/questions/95410/…)。讨论差异。
【解决方案2】:

始终在文本中添加salt,并将其附加到文本的末尾。 salt 可以是随机生成的任意长度的字符串,并且可以轻松满足 32 字符的长度限制。此外,在加密之前添加盐可以加强加密。

【讨论】:

  • 您可以查看stackoverflow.com/questions/44797213/…,它使用bcrypt,这是一种很好的散列算法。
  • 我认为 OP 说它是关于使用用户密码作为密钥,而不是作为文本。这也是他们的代码 sn-p 正在做的事情。我认为这个答案正在解决一个不同的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-23
  • 2012-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多