在node.js的应用程序中,我使用crypto module进行对称加密/解密。
我使用的是AES-256-CTR。我最初认为crypto.createCipher将是“正常工作”和“手动”的细节。现在我正在阅读文档:
注意:createCipher使用OpenSSL函数EVP_BytesToKey派生密钥,摘要算法设置为MD5,一次迭代,无盐。缺少盐允许字典攻击,因为相同的密码始终创建相同的密钥。低迭代计数和非加密安全散列算法允许非常快速地测试密码。
根据OpenSSL建议使用pbkdf2而不是EVP_BytesToKey,建议您使用crypto.pbkdf2派生一个密钥并使用iv来创建密码流。
好吧,我可以自己推导出IV和键。
但是,我不确定,这样做的正确和推荐方法是什么 - 我应该分别对不同的盐进行密钥推导吗?我应该进行一次密钥推导,然后将其减半吗?对于这个特定的用例,我应该使用盐吗?我应该随机生成盐并将其与数据一起保存吗?
答案 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支持。