I'm writing a simple encryption/decryption library which has the following requirements:

  1. For key derivation functions, support:
    • $SHA256 \rightarrow bcrypt$ (since $bcrypt$ limits input passphrase length, hash it using SHA-256 first, then feed output of SHA-256 into bcrypt)
    • $PBKDF2$
  2. For key derivation functions, allow custom iteration count.
  3. For encryption/decryption support:
    • AES-256
    • AES-128
    • Triple DES
  4. Authenticity using HMAC+SHA256 every $n$ bytes

Since I'm potentially using multiple different symmetric key algorithms for encryption and decryption, I have the following problems:

  1. How do I deal with different output sizes from my KDFs?
  2. How do I deal with different key input requirements from my symmetric key algorithms?
  • $\begingroup$ Don't both bcrypt and PBKDF2 let you choose an arbitrary output length? In that case what's wrong with simply choosing the key length of the block cipher to use next? $\endgroup$
    – Thomas
    May 20 '14 at 23:46
  • $\begingroup$ Bcrypt only has the one output length, AFAICT. It isn't necessarily a very good key-derivation function, since it seems to be designed simply with password storage in mind. With PBKDF2 you can choose a length, and additionally you can truncate a longer PBKDF2 hash to get the same one you would have by calling the function with a shorter output length. That means you can always call PBKDF2 with length=256, then truncate that to match the key length of the cipher. That may be useful if you start key derivation before knowing which algorithms will be used. $\endgroup$
    – otus
    May 21 '14 at 7:49
  • $\begingroup$ IMO the 192 bit output length restriction of bcrypt is a more severe problem, at least it is not appropriate for AES-256. $\endgroup$ May 21 '14 at 8:34
  • $\begingroup$ Are you writing a skin around a library like OpenSSL or are you writing a crypto library from scratch? Any existing library has its own way of dealing with that sort of thing. Additionally, key sizes for symmetric ciphers are "set in stone" so passing a struct with the key and length seems easy. For the output sizes, similarly, return a struct with the output and the length. $\endgroup$
    – rath
    May 22 '14 at 5:53

First, consider dropping bcrypt, because of its output limitations. If you are concerned about GPUs and ASICs, there's always scrypt. If you decide to go with bcrypt, you won't have 256-bit security with AES-256 and will need to pad the key somehow or disallow that combination.

  1. I would simply call the KDF with a constant 256-bit output, which matches the blocksize of SHA-256-HMAC if you use that as PBKDF2 PRF (so it's ~ as fast as shorter outputs).

  2. Then you can truncate the input of AES-128 to 128 bits and 3DES to 168 bits, which is what PBKDF2 would do anyway.

  • $\begingroup$ +1. Also, if you might need more than 256 bits of key material, consider using PBKDF2+HKDF (i.e. use PBKDF2 to derive one hash output block's worth of bits, then feed that into the expansion stage of HKDF as the PRK input). $\endgroup$ May 22 '14 at 20:22
  • $\begingroup$ @IlmariKaronen, what's the advantage of PBKDF2+HKDF compared to simply calling PBKDF2 with a larger output size? $\endgroup$
    – otus
    May 23 '14 at 20:25
  • 1
    $\begingroup$ For some strange reason, if you ask PBKDF2 for more than one hash output block's worth of key material, it repeats the whole key-stretching process several times. This severely slows down the key derivation for legitimate users, whereas attackers typically don't suffer at all (since they only need to derive one output block to confirm their guess). PBKDF2+HKDF doesn't have that issue. $\endgroup$ May 24 '14 at 9:52
  • $\begingroup$ @IlmariKaronen, good point. Then again, using only 256 bits of PBKDF2 output limits you to making use of 256 bits of key material. If you needed a larger key you would presumably want to allow more or you wouldn't be using a cipher with such a large key in the first place. I guess simply going with scrypt (which takes almost the same time regardless of output size) is simplest in that case. $\endgroup$
    – otus
    May 24 '14 at 10:36
  • $\begingroup$ It kind of depends on why you want that much key material. If it's because you think a 256-bit key is too short to be secure, then, indeed, you should not have a 256-bit bottleneck in your KDF. (But if you really think someone could brute-force a 256-bit keyspace, then you obviously know something the rest of us don't. Also, considering that key-stretching rarely adds more than 30 bits of entropy, where are you getting a password with over 226 bits of entropy from?) $\endgroup$ May 24 '14 at 14:50

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.