I am working in .NET and as far as I can tell the only choice for key derivation is PBKDF2-HMAC-SHA1. SHA1's output size is only 160 bits. But I am implementing authenticated encryption and thus need 512 bits of key material (a 256-bit AES key and a 256-bit HMAC key). My original idea was to input the password, salt, and a high numberOfIterations into PBKDF2 to derive both the AES key and the HMAC key.
Several people pointed out that I was making an attacker's job easier. Getting 512 bits of key material from PBKDF2-HMAC-SHA1 would require ceil(512/160) = 4 calls * numberOfIterations. However, an attacker would only need the AES key to decrypt the message, so he/she would only need to perform ceil(256/160) = 2 calls * numberOfIterations.
I've read two suggestions on how to fix this:
- Use PBKDF2-HMAC-SHA512. It would provide enough output for both keys. Unfortunatley, .NET doesn't seem to support this.
- Use PBKDF2-HMAC-SHA1 with the password, salt, and a high numberOfIterations to output a 160-bit master key. Then use HKDF-Expand to expand the master key into two 256-bit keys. Unfortunately .NET doesn't provide HKDF-Expand as far as I can tell.
I have read in other stack exchange posts such as this post and this post that one could derive two keys from a master key (MK) by doing the following:
- Create 160-bit MK through PBKDF2-HMAC-SHA1 using a user-supplied password, a 160-bit salt, and a high numberOfIterations.
- Calculate HMAC-SHA256(MK,"e") -> aesKey
- Calculate HMAC-SHA256(MK,"a") -> hmacKey
Would these steps result in a suitable pair of keys for AES-encrypt-then-HMAC-authenticate?
- Note 1: I realize that the 256-bit aesKey and 256-bit hmacKey would each only have 160 bits of entropy, but that doesn't seem concerning, as the likely attack path would be on the password, not the keys.
- Note 2: Even though .NET does offer HMAC-SHA256, HMAC-SHA512, etc., it does not offer a choice for PBKDF2-HMAC other than PBKDF2-HMAC-SHA1.