3
$\begingroup$

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:

  1. Use PBKDF2-HMAC-SHA512. It would provide enough output for both keys. Unfortunatley, .NET doesn't seem to support this.
  2. 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:

  1. Create 160-bit MK through PBKDF2-HMAC-SHA1 using a user-supplied password, a 160-bit salt, and a high numberOfIterations.
  2. Calculate HMAC-SHA256(MK,"e") -> aesKey
  3. 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.
$\endgroup$
  • $\begingroup$ The standard PBKDF2 interface allows you to specify the length of output you want (which need not be limited to the length of the hash function it uses internally). Doesn't .NET implement that parameter? $\endgroup$ – poncho Apr 20 '16 at 2:35
  • $\begingroup$ If you are worried that an attacker might gain a factor of two advantage by only deriving the AES-256 half, then why don't you ask for 512 bits, and use the even bytes for the AES-256 key and the odd bytes for the HMAC key. That way, he'll need to derive both to test either the decryption or the HMAC. $\endgroup$ – poncho Apr 20 '16 at 2:42
  • $\begingroup$ Yes, you can get as much output as you want from PBKDF2-HMAC-SHA1. The issue pointed out by others is that for a given number of iterations it will take twice as long to derive the AES key and the HMAC key together than it will take to derive just the AES key. The function has to increase its workload to give more than 160 bits. If 0-160 bits takes n seconds, then 161-320 bits takes 2n seconds, 321-480 bytes takes 3n seconds, etc. So if I use it to get 512 bytes of data then I am running it twice as much as an attacker would who only needs 256 bits of data to try decrypting the ciphertext. $\endgroup$ – Ralph P Apr 20 '16 at 2:46
  • $\begingroup$ So, did you read my suggestion for using alternative bytes for the two different keys? $\endgroup$ – poncho Apr 20 '16 at 3:12
  • $\begingroup$ Use .NET bindings to libsodium instead $\endgroup$ – Demi Apr 20 '16 at 4:40
2
$\begingroup$

Would these steps result in a suitable pair of keys for AES-encrypt-then-HMAC-authenticate?

Yes. That would be fine. It almost is HKDF-Expand, in fact.

However, as you note, by deriving the two 256-bit keys from a 160-bit key your effective security will "only" be 160 bits, since an attacker could brute force the intermediate key. That is not at all a problem realistically, but if you had strict requirements from e.g. some regulations you would want to fix that.

One way would be to derive 320 bits using PBKDF2 (requiring twice the iterations you pass it) and then deriving the two 256-bit keys from that.


The idea of using every other byte of 512-bit PBKDF2 output that poncho mentioned in comments would also work, but there is a slight weakness in key separation. If one of the final keys – the AES or MAC key (or just a byte of either) – leaks somehow, an attacker can look for the other in less time than expected by only calculating one of the PBKDF2 calls for each password.

Again, that is probably not a real problem, because you will want to keep both keys secret and it is only a factor of four in attack time. It does seem a bit untidy, though, and using HMAC/HKDF for key derivation instead is an easy solution.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.