9
$\begingroup$

I'm developing a messenger application with encrypted chats.

In the first version of the app I've used PBKDF2 (10000 iterations, SHA1, random salt) to extend a short user password and generate keys to encrypt (AES256) and sign message (HMAC).

In the current version of the app I generate a random 130-bit key and use it instead of a user password. I think that using PBKDF2 with such a key has some overhead.

I see 2 possible ways to improve the current approach:

  1. Keep using PBKDF2 and decrease iterations to 1 or 10.
  2. Don't use PBKDF2 and use HKDF instead.

What are the advantages and disadvantages of each approach? Are there any other options?

$\endgroup$
13
$\begingroup$

You're right: there is no need for key stretching if your key already has enough entropy to resist brute force attacks without it. A 128-bit keyspace should be plenty for that.

AFAIK, there is no significant difference between HKDF and single-iteration PBKDF2 in practice. Both effectively achieve the goal of expanding the input key to a potentially longer sequence of derived keys, in a way that does not allow the original input key to be efficiently recovered from the derived keys.

Arguably, using HKDF for this purpose is somewhat "tidier", in the sense that it has been explicitly designed for non-password-based key derivation, whereas using PBKDF2 with an iteration count of 1 is formally outside its original design parameters. However, there are several existing schemes, such as scrypt, that do use PBKDF2 in such a way, and there is no apparent structural reason why PBKDF2, used in such a way, would not be a secure non-key-stretching KDF. Also, if you are already using PBKDF2 for password-based key derivation anyway, implementing a second KDF might be seen as needless complexity (however minor).


Personally, my favorite approach, in situations that do call for both key stretching and the generation of more than one hash output block of derived key material, is to use hybrid PBKDF2/HKDF — that is, to use PBKDF2 (or another key-stretching KDF) to generate an intermediate pseudorandom key (of one hash output block size), and then use the HKDF-Expand function to generate the derived keys from the intermediate PRK. This combines the best features of both PBKDF2 and HKDF, and is implicitly permitted by RFC 5869 section 3.3 (which says one may skip the HKDF extract stage if one already has a uniformly distributed pseudorandom key string).

Using this approach could allow you to support both password-based and random-key-based key derivation within a unified framework:

  • For password inputs, derive an intermediate PRK using PBKDF2 with a suitably high iteration count.
  • For random key inputs, derive the PRK using HKDF-Extract (or PBKDF2 with a single iteration), or just use the input key directly as the PRK.
  • In either case, derive the actual encryption and MAC keys from the PRK using HKDF-Expand.

Ps. Just out of curiosity, I searched for earlier answers I'd written mentioning HKDF and PBKDF2. I don't think any of these questions are exact duplicates of yours, but the answers may be somewhat relevant:

$\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.