PBKDF2 allows you to choose an output size as well as the internal hashing function used.

My question is, do these two sizes need to match?

For example, if I'm using PBKDF2 with SHA512, does my output size need to be 512 bits?

I'm a little confused because WebCrypto and CryptoJS allow you to specify SHA512 as the hashing algorithm, but then limit the output key size to the AES max output size, which is 256.

Why is AES even used to generate the final key, and not just a SHA hash of the derived key?

  • $\begingroup$ It makes sense to restrict the PBKDF-2 output to the hash length because IIRC you go through all the n iterations again for each hash length, which doesn't increase security but costs quite a lot $\endgroup$ – SEJPM Dec 17 '16 at 19:48
  • $\begingroup$ But if I use SHA512, how would I use an output size of 512 if AES is limited to 256? $\endgroup$ – Snowman Dec 17 '16 at 19:48
  • $\begingroup$ In general there are applications where you need more than 256 or 512 bit of keying material, I was talking about those and not about the specific details described in your Q when making my comment. $\endgroup$ – SEJPM Dec 17 '16 at 19:50
  • $\begingroup$ Do you know if AES is explicitly tied to PBKDF2 output, or does that depend on the implementation? $\endgroup$ – Snowman Dec 17 '16 at 19:56

My question is, do these two sizes need to match?

Well, officially no, the output of PBKDF2 is only limited by the following definition from PKCS#5:

dkLen      intended length in octets of the derived
           key, a positive integer, at most
           (2^32 - 1) * hLen

There hLen is the length of the internal hash algorithm.

PBKDF1 is actually limited to hLen - unless you are using the horrible Microsoft implementation which is simply completely insecure and unspecified for anything over hLen of output.

It is however strongly recommended to keep to hLen as output. The reason for this is not that the output is somehow dependent. The problem is that the whole work factor (parameterized by the iteration count) is repeated for each additional block that is required. The problem with this is that attackers do often not need to perform all these additional operations to verify correctness of the input while brute forcing or performing a dictionary attack. So additional output put you at a disadvantage over an attacker.

Try to keep to SHA-512 and a maximum output size of 512 bits or use an additional function such as HKDF to increase the amount of output (or use the KDF multiple times to derive multiple keys/secret values).

Why is AES even used to generate the final key, and not just a SHA hash of the derived key?

This is a misconception on your part. AES may take the output of PBKDF2 to be an AES key. No AES key operations are however performed within PBKDF2 (AES has a block size of 128 so expecting 256 bytes of output would be strange anyway).

Directly converting the output to a key means that the user doesn't have to "manually" an AES key type from the output of the KDF. This is more secure as the bytes do not have to be copied into the resulting key - and the original bytes don't need to be destroyed (zeroed) either.

In case of hardware crypto the output of the KDF may be kept in the device as well (instead of first copying it to memory of the host device), although this is usually not an issue for PBKDF2 as password handling is usually not performed in specialized hardware.

| improve this answer | |
  • $\begingroup$ What's throwing me off is the WebCrypto implementation. See here: github.com/diafygi/webcrypto-examples#pbkdf2---derivekey. You'll see that in order to export the final key, it needs to go through AES. However, in CryptoJS, AES is not involved, yet both output the same result. How is this possible? $\endgroup$ – Snowman Dec 17 '16 at 20:37
  • $\begingroup$ No, only the key type is indicated. Usually the API designers do not want to explicitly create the key after deriving it because you don't want to have the PBKDF2 result in unprotected memory and create a copy afterwards. So the output is an object of the correct type. The only strange thing of that API is that it has specific keys for different modes of operation. That's probably some kind of API design decision (which is, in my opinion, wrong, but that's beside the point). $\endgroup$ – Maarten Bodewes Dec 17 '16 at 20:59
  • $\begingroup$ I've found that I can arrive at a 512 bit result by using deriveBits instead of deriveKey. You say "you do not want to explicitly create the key afterwards" — afterwards of what? Do I not want to immediately derive the bits from a key? $\endgroup$ – Snowman Dec 17 '16 at 21:02

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.