What are the correct settings for crypto.pbkdf2 to derive IV and key to crypto.createCipheriv?

和自甴很熟 提交于 2019-12-12 10:48:53

问题


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?


回答1:


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.



来源:https://stackoverflow.com/questions/33963624/what-are-the-correct-settings-for-crypto-pbkdf2-to-derive-iv-and-key-to-crypto-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!