crypto.pbkdf2导出IV和crypto.createCipheriv的密钥的正确设置是什么? [英] What are the correct settings for crypto.pbkdf2 to derive IV and key to crypto.createCipheriv?

查看:294
本文介绍了crypto.pbkdf2导出IV和crypto.createCipheriv的密钥的正确设置是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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




我应该进行一次密钥推导和然后将其切成两半?


请求比基础哈希函数提供的输出字节更多的问题。如果您想要AES-256密钥(256位)和64至128位的随机数(IV),则需要使用SHA-384(sha384)或SHA-512(sha512)作为基础 digest 都由node.js提供。


我是否应该随机生成盐并将其保存是吗?


是的,您需要将盐和密文一起发送,以便接收者可以使用他们拥有的密码和

也许您是指随机数本身。那是第三种选择,您必须随机生成随机数,并将其与随机(加密)盐和密文一起存储。



结论



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



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



您可以将第一个建议与附加密钥结合使用,然后使用as作为附加的MAC解决方案:

  hmac = crypto.createHmac('sha256',master); 
hmac.update( hmac);
var hmacKey = hmac.digest();

// TODO加密

hmac = crypto.createHmac(’sha256’,hmacKey);
hmac.update(密文);
var authenticationTag = hmac.digest();

然后,您还需要在密文中包含身份验证标签,并在接收方检查其是否匹配 解密之前。



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


In an application in node.js, I am using crypto module for symmetric encryption/decryption.

I am using AES-256-CTR. I originally assumed the crypto.createCipher will be "just working" and "handwaved" the details. Now I am reading in the documentation:

Note: createCipher derives keys with the OpenSSL function EVP_BytesToKey with the digest algorithm set to MD5, one iteration, and no salt. The lack of salt allows dictionary attacks as the same password always creates the same key. The low iteration count and non-cryptographically secure hash algorithm allow passwords to be tested very rapidly.

In line with OpenSSL's recommendation to use pbkdf2 instead of EVP_BytesToKey it is recommended you derive a key and iv yourself with crypto.pbkdf2 and to then use createCipheriv() to create the cipher stream.

All right, I can derive the IV and key myself.

But, I am not sure, what is the correct and recommended way of doing that - should I do key derivation separately for both, with different salts? Should I do one key derivation and then cut it in half? Should I use salt at all for this specific use-case? Should I randomly generate the salt and save it with the data?

解决方案

should I do key derivation separately for both, with different salts?

You can certainly do that, but a faster alternative with roughly the same security would be to use something like this:

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

Should I do one key derivation and then cut it in half?

Requesting more output bytes than the underlying hash function provides is problematic. If you want an AES-256 key (256 bits) and a nonce (IV) of 64 to 128 bit then you would need to use either SHA-384 (sha384) or SHA-512 (sha512) as the underlying digest which are both provided by node.js.

Should I randomly generate the salt and save it with the data?

Yes, you need to send the salt along with the ciphertext so that the receiver can use the password they have and the salt in order to generate the same key+nonce.

Perhaps you meant the nonce itself. That would be a third option that you have to generate the nonce randomly and store it alongside of the random (encryption) salt and the ciphertext.

Conclusion

All of the above ways provide roughly the same security, but they differ in what is included in the ciphertext and the additional computation time. I would suggest to use the way that is the easiest, because ...

You also should implement ciphertext authentication. If you don't then your system might be vulnerable to a padding oracle attack.

You could either use the first suggestion with an additional key for an encrypt-then-MAC solution with as:

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();

then you also need to include the authentication tag with the ciphertext and check that it matches on the receiver side before decryption.

You can also use an authenticated mode like GCM which node.js supports.

这篇关于crypto.pbkdf2导出IV和crypto.createCipheriv的密钥的正确设置是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆