crypto.pbkdf2导出IV和密钥到crypto.createCipheriv的正确设置是什么?

时间:2015-11-27 19:18:21

标签: node.js encryption cryptography aes pbkdf2

在node.js的应用程序中,我使用crypto module进行对称加密/解密。

我使用的是AES-256-CTR。我最初认为crypto.createCipher将是“正常工作”和“手动”的细节。现在我正在阅读文档:

  

注意:createCipher使用OpenSSL函数EVP_BytesToKey派生密钥,摘要算法设置为MD5,一次迭代,无盐。缺少盐允许字典攻击,因为相同的密码始终创建相同的密钥。低迭代计数和非加密安全散列算法允许非常快速地测试密码。

     

根据OpenSSL建议使用pbkdf2而不是EVP_BytesToKey,建议您使用crypto.pbkdf2派生一个密钥并使用iv来创建密码流。

好吧,我可以自己推导出IV和键。

但是,我不确定,这样做的正确和推荐方法是什么 - 我应该分别对不同的盐进行密钥推导吗?我应该进行一次密钥推导,然后将其减半吗?对于这个特定的用例,我应该使用盐吗?我应该随机生成盐并将其与数据一起保存吗?

1 个答案:

答案 0 :(得分:3)

  

我应该分别用不同的盐进行密钥推导吗?

你当然可以做到这一点,但更快的替代方案具有大致相同的安全性将是使用这样的东西:

var master = crypto.pbkdf2Sync(password, randomSalt, 60000, 256, 'sha256');
var hmac = crypto.createHmac('sha256', master);
hmac.update("key");
var key = hmac.digest();

hmac = crypto.createHmac('sha256', master);
hmac.update("nonce");
var nonce = hmac.digest().slice(0,12); // 96 bit for CTR nonce
  

我应该进行一次密钥推导,然后将其减半吗?

请求比底层散列函数提供更多的输出字节是有问题的。如果您需要AES-256密钥(256位)和64到128位的随机数(IV),那么您需要使用SHA-384(sha384)或SHA-512(sha512)作为基础{{1}这两个都是由node.js。

提供的
  

我应该随机生成盐并将其与数据一起保存吗?

是的,您需要将盐与密文一起发送,以便接收者可以使用他们拥有的密码和盐来生成相同的密钥+随机数。

也许你的意思是nonce本身。这将是第三个选项,您必须随机生成随机数并将其与随机(加密)盐和密文一起存储。

结论

所有上述方法都提供了大致相同的安全性,但它们在密文中包含的内容和额外的计算时间不同。我建议使用最简单的方式,因为......

您还应该实施密文身份验证。如果不这样做,那么您的系统可能容易受到填充oracle攻击。

你可以使用第一个建议和一个额外的密钥用于加密 - 然后 - MAC解决方案,如下:

digest

然后你还需要包含带有密文的身份验证标记,并在解密之前检查它是否在接收方上匹配。

您还可以使用像GCM这样的身份验证模式,node.js支持。