I came across an encryption scheme to encrypt files with AES-256. You can see the initialization of the decryption routine below:

salt = scrambled_file.read(16)

key_and_iv = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, 50000, 48, OpenSSL::Digest::SHA512.new)
key = key_and_iv.byteslice(0,32)
iv = key_and_iv.byteslice(32,16)

cipher= OpenSSL::Cipher::AES256.new(:CBC)
cipher.key = key
cipher.iv = iv

decrypted_data = cipher.update(scrambled_file.read(...))

It basically takes a password and a 16-bytes random salt and pushes it through PBKDF2 (SHA512). Afterwards, the key is taken from the first 32 bytes and the IV from the 16 bytes following it.

Is it secure to derive the IV from the same hash as the key?

  • 1
    $\begingroup$ The Bear said so although I would add only if one PBKDF 'chunk' is sufficient, as it is here (32+16 < 64). If you need multiple chunks and the key is first, it reduces the defender's cost advantage some, and an extract-expand (PBKDF-KBKDF) scheme is better. Although today you probably want more than 50k iterations, and even better allow for future increase. $\endgroup$ – dave_thompson_085 Nov 12 '16 at 9:46

Yes, it is. PBKDF2 derives a DK, a "derived key", which is indistinguishable from random. This is mainly because function within PBKDF2 is HMAC, and HMAC is a PRF. Let's see the definition from Wikipedia:

In cryptography, a pseudorandom function family, abbreviated PRF, is a collection of efficiently-computable functions which emulate a random oracle in the following way: no efficient algorithm can distinguish (with significant advantage) between a function chosen randomly from the PRF family and a random oracle (a function whose outputs are fixed completely at random).

This also means that the bytes of the derived key are independent, even from each other. So that means that as long as separate bytes from the output are used, we can split the DK value into a key and an IV.

Now fortunately the scheme provided uses SHA-512 as underlying hash function. This means that no additional calculations need to be performed if we require 256 bit key material and 128 bit IV material.

If the SHA-256 hash would have been used the PBKDF2 function would require an additional run. Unfortunately, in the scheme above, an attacker would not have to perform such an additional run. This is because the attacker only has to verify the key; it can calculate the IV when it finds the key. So using a smaller hash function requires a lot more operations for the legit user, while not giving any security advantage. This is a bad property for a PBKDF - which unfortunately is present for PBKDF2.

So as long as your key and IV stay below the output size of the hash the scheme above is secure.

If you'd ever require more output than the single hash requires then it is possible to perform additional calculations using a key based key derivation function (KBKDF) such as HKDF. In that case a good scheme would be:

derivedKey = PBKDF2(Password, Salt)
key = HKDF(DerivedKey, "Key")
iv = HKDF(DerivedKey, "IV")

That the scheme is secure doesn't mean that it is optimal. You could think of using a memory hard PBKDF such as scrypt or one of the newer Argon2 variants instead of PBKDF2. You might also have a look at authenticated ciphers such as GCM to add integrity and authenticity to your ciphertext.

Of course the scheme does depend on the salt being a secure random value. Please make sure this is the case, otherwise you may end up with a repeating key, IV for identical passwords, destroying security.

A high number of iterations (the "work factor") for PBKDF2 makes it harder to attack relatively weak passwords (and most passwords are relatively weak).


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.