Kar*_*lek 5 encryption cryptography aes pbkdf2 node.js
在node.js的应用程序中,我使用crypto模块进行对称加密/解密.
我使用的是AES-256-CTR.我最初假设crypto.createCipher将"正常工作"和"手动"的细节.现在我正在阅读文档:
注意:createCipher使用OpenSSL函数EVP_BytesToKey派生密钥,摘要算法设置为MD5,一次迭代,无盐.缺少盐允许字典攻击,因为相同的密码始终创建相同的密钥.低迭代计数和非加密安全散列算法允许非常快速地测试密码.
根据OpenSSL建议使用pbkdf2而不是EVP_BytesToKey,建议您使用crypto.pbkdf2派生密钥并自行定义,然后使用createCipheriv()创建密码流.
好吧,我可以自己推导出IV和键.
但是,我不确定,这样做的正确和推荐方法是什么 - 我应该分别对不同的盐进行密钥推导吗?我应该进行一次密钥推导,然后将其减半吗?对于这个特定的用例,我应该使用盐吗?我应该随机生成盐并将其与数据一起保存吗?
我应该使用不同的盐分别对两者进行密钥推导吗?
您当然可以这样做,但是具有大致相同安全性的更快替代方案是使用如下内容:
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
Run Code Online (Sandbox Code Playgroud)
我应该进行一次密钥推导然后将其减半吗?
请求比底层哈希函数提供的输出字节更多的输出字节是有问题的。如果您想要 AES-256 密钥(256 位)和 64 至 128 位的随机数 (IV),那么您需要使用 SHA-384 (sha384) 或 SHA-512 (sha512) 作为基础,两者均digest提供通过node.js。
我应该随机生成盐并将其与数据一起保存吗?
是的,您需要将盐与密文一起发送,以便接收者可以使用他们拥有的密码和盐来生成相同的密钥+随机数。
也许你指的是随机数本身。这是第三个选项,您必须随机生成随机数并将其与随机(加密)盐和密文一起存储。
所有上述方法都提供大致相同的安全性,但它们在密文中包含的内容和额外的计算时间方面有所不同。我建议使用最简单的方式,因为......
您还应该实施密文身份验证。如果您不这样做,那么您的系统可能容易受到 padding oracle 攻击。
您可以将第一个建议与附加密钥一起用于加密然后 MAC 解决方案,如下所示:
hmac = crypto.createHmac('sha256', master);
hmac.update("hmac");
var hmacKey = hmac.digest();
// TODO encrypt
hmac = crypto.createHmac('sha256', hmacKey);
hmac.update(ciphertext);
var authenticationTag = hmac.digest();
Run Code Online (Sandbox Code Playgroud)
那么您还需要在密文中包含身份验证标签,并在解密之前检查它在接收方是否匹配。
您还可以使用 Node.js 支持的身份验证模式,例如 GCM。