What is the default IV when encrypting with aes_256_cbc cipher?
Asked Answered
Q

2

15

I've generated a random 256 bit symmetric key, in a file, to use for encrypting some data using the OpenSSL command line which I need to decrypt later programmatically using the OpenSSL library. I'm not having success, and I think the problem might be in the initialization vector I'm using (or not using).

I encrypt the data using this command:

/usr/bin/openssl enc -aes-256-cbc -salt -in input_filename -out output_filename -pass file:keyfile

I'm using the following call to initialize the decrypting of the data:

EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, keyfile.data(), nullptr))

keyfile is a vector<unsigned char> that holds the 32 bytes of the key. My question is regarding that last parameter. It's supposed to be an initialization vector to the cipher algorithm. I didn't specify an IV when encrypting, so some default must have been used.

Does passing nullptr for that parameter mean "use the default"? Is the default null, and nothing is added to the first cipher block?

I should mention that I'm able to decrypt from the command line without supplying an IV.

Quadrature answered 30/6, 2016 at 13:54 Comment(5)
Wouldn't using no IV (or a fixed default) severely undermine the strength of the encryption? As I understand it, the point of the IV is to ensure that identical plaintext does not generate identical ciphertext. So there needs to be an IV, it does not need to be secret, it just needs to be unique for everything you encrypt. Not using one (or a fixed one) sounds like a very bad idea.Unused
I am not a cryptographer, nor do I play one on TV, so I'm really not qualified to answer (hence why the above was just a comment). As a non-expert I would guess that as long as the key is unique every time then it's probably OK, but then as a pragmatist who knows he knows too little about encryption I'd probably use a random IV as well, anyway, and store it along with the encrypted data.Unused
I found some information about that: Answer on crypto.stackexchange.com Regarding using the same IV with different keys for each plaintext.Quadrature
The accepted answer there seems to agree with my initial gut feeling that using a fixed IV will reduce the strength (in the situation where the attacker is attempting to brute-force the key). So I'd go with using a (truely) random IV every time, even when the key is unique.Unused
@JesperJuhl - Each mode usually has different requirements. CBC usually requires a non-predicatble IV. I updated my answer to provide the references.Hartwig
H
11

What is the default IV when encrypting with EVP_aes_256_cbc() [sic] cipher...

Does passing nullptr for that parameter mean "use the default"? Is the default null, and nothing is added to the first cipher block?

There is none. You have to supply it. For completeness, the IV should be non-predictable.

Non-Predictable is slightly different than both Unique and Random. For example, SSLv3 used to use the last block of ciphertext for the next block's IV. It was Unique, but it was neither Random nor Non-Predictable, and it made SSLv3 vulnerable to chosen plaintext attacks.

Other libraries do clever things like provide a null vector (a string of 0's). Their attackers thank them for it. Also see Why is using a Non-Random IV with CBC Mode a vulnerability? on Stack Overflow and Is AES in CBC mode secure if a known and/or fixed IV is used? on Crypto.SE.


/usr/bin/openssl enc -aes-256-cbc...

I should mention that I'm able to decrypt from the command line without supplying an IV.

OpenSSL uses an internal mashup/key derivation function which takes the password, and derives a key and iv. Its called EVP_BytesToKey, and you can read about it in the man pages. The man pages also say:

If the total key and IV length is less than the digest length and MD5 is used then the derivation algorithm is compatible with PKCS#5 v1.5 otherwise a non standard extension is used to derive the extra data.

There are plenty of examples of EVP_BytesToKey once you know what to look for. Openssl password to key is one in C. How to decrypt file in Java encrypted with openssl command using AES in one in Java.


EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, keyfile.data(), nullptr))

I didn't specify an IV when encrypting, so some default must have been used.

Check your return values. A call should have failed somewhere along the path. Maybe not at EVP_DecryptInit_ex, but surely before EVP_DecryptFinal.

If its not failing, then please file a bug report.

Hartwig answered 30/6, 2016 at 15:43 Comment(1)
It's not failing until EVP_DecryptFinal. This is a lot of good information, thank you!Quadrature
E
8

EVP_DecryptInit_ex is an interface to the AES decryption primitive. That is just one piece of what you need to decrypt the OpenSSL encryption format. The OpenSSL encryption format is not well documented, but you can work it backwards from the code and some of the docs. The key and IV computation is explained in the EVP_BytesToKey documentation:

   The key and IV is derived by concatenating D_1, D_2, etc until enough
   data is available for the key and IV. D_i is defined as:

           D_i = HASH^count(D_(i-1) || data || salt)

   where || denotes concatentaion, D_0 is empty, HASH is the digest
   algorithm in use, HASH^1(data) is simply HASH(data), HASH^2(data) is
   HASH(HASH(data)) and so on.

   The initial bytes are used for the key and the subsequent bytes for the
   IV.

"HASH" here is MD5. In practice, this means you compute hashes like this:

Hash0 = ''
Hash1 = MD5(Hash0 + Password + Salt)
Hash2 = MD5(Hash1 + Password + Salt)
Hash3 = MD5(Hash2 + Password + Salt)
...

Then you pull of the bytes you need for the key, and then pull the bytes you need for the IV. For AES-128 that means Hash1 is the key and Hash2 is the IV. For AES-256, the key is Hash1+Hash2 (concatenated, not added) and Hash3 is the IV.

You need to strip off the leading Salted___ header, then use the salt to compute the key and IV. Then you'll have the pieces to feed into EVP_DecryptInit_ex.

Since you're doing this in C++, though, you can probably just dig through the enc code and reuse it (after verifying its license is compatible with your use).

Note that the OpenSSL IV is randomly generated, since it's the output of a hashing process involving a random salt. The security of the first block doesn't depend on the IV being random per se; it just requires that a particular IV+Key pair never be repeated. The OpenSSL process ensures that as long as the random salt is never repeated.

It is possible that using MD5 this way entangles the key and IV in a way that leaks information, but I've never seen an analysis that claims that. If you have to use the OpenSSL format, I wouldn't have any hesitations over its IV generation. The big problems with the OpenSSL format is that it's fast to brute force (4 rounds of MD5 is not enough stretching) and it lacks any authentication.

Eneidaenema answered 30/6, 2016 at 14:37 Comment(3)
Uh dude, you have the source code and you call that reverse engineering?Galba
Any idea how aes 256 works here with a 256 bit IV? My understanding is that the IV needs be 128 bit and the key 256 bit. In the pseudo above both are 256 bit correct.Frazzle
@Frazzle Updated. The 256-bit IV was wrong. It worked fine because of the libraries I was working with, but only the first 128-bits were actually being used.Eneidaenema

© 2022 - 2024 — McMap. All rights reserved.