What is an openssl iv, and why do I need a key and an iv?

The Initialization Vector is part of what makes AES in CBC (Cipher Block Chaining) mode work - IVs are not unique to OpenSSL. CBC works by XORing the previous block with the current block. The very first block has no previous block, so the IV serves that purpose.

Why this is necessary requires a bit of understanding of how block ciphers work. Without this chaining and IV, we're left with a mode of AES called ECB, or Electronic Code Book. ECB has weaknesses that allow a chosen plaintext attack, among many other problems.

I would recommend spending a bit of time with best practices for CBC initialization vectors. Using them incorrectly can weaken the overall security of AES. The short explanation is:

  • IVs should be random and generated by a CSPRNG.
  • IVs should not be reused. That is, don't encrypt plaintext "A" and plaintext "B" with the same IV. Every record should have its own IV.
  • The IV is not a secret like the key. It can be stored in plaintext along with the cipher text.

Also keep in mind that this advice only applies to AES-CBC. If you ever investigate other modes of AES, such as GCM, this does not apply.


Let's say two users have the password "princess", and you encode them with the key "some-key", they will both have the same encrypted result:

| User       | Encrypted password    |
|------------|-----------------------|
| a          | sN7vIFg=              |
| b          | sN7vIFg=              |

Which means that if someone figures out using a different means that user a's real password is "princess" and their encrypted password is "sN7vIFg=", then any user with the encrypted password "sN7vIFg=" can be deemed to have the password "princess".

However if you use a random IV for each, then it is harder to guess the underlying passwords if you have access to the encrypted data.

| User       | Encrypted password    | IV             |
|------------|-----------------------|----------------|
| a          | sN7vIFg=              | h²ÓIF8]h%L     |
| b          | BjZAzrA=              | VÂøíiøÚØò▓     |

Now, even if someone has access to the above data, they can't figure out that users a and b have the same password.

See also Is “real salt” the same as “initialization vectors”? .


I think you maybe mixed up "hashed key" and "iv" (God knows I did when starting crypto). hashed key is exactly what you did. For iv you should use different random data each time encryption is made with the same key. (my background: I had to build a pdo secure session handler which encrypts/decrypts the session data so I ended up implementing AES-256-CBC using openssl extension)

just a small tip if anyone gets here.

// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);

is not the right way of generating iv + no need for secret_iv because iv has to be as random as it gets. Don't treat it (or understand it) the same as hashing.

As you have access to openssl extension there is a better/safer way of generating iv for the chosen cipher, openssl can also tell you the right length of the iv for the cipher:

$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-256-CBC'));

It will be in binary format so if you need it in hex use bin2hex($iv). If you need to store the generated iv in mysql I store it in raw format (field type varbinary, binary also works).

One more thing. You have $options tag set to 0 in both openssl_encrypt and _decrypt which means "if set to true will return as raw output data, otherwise the return value is base64 encoded".


I'd like to offer a simple explanation with reference to the quesion in the topic- why do you need a key as well as IV? In other words, why a mere key is not enough for the encryption? (general answer, not referring to a specific algorithm)

First lets describe what's happening in block cipher- A block cipher get a key and text as input. Then it divides the text into same sized blocks and encrypts each one of them seperately. Problem with this approach is that given a key K- same plaintext blocks generates same ciphertext blocks. This obviously is undesirable since it makes patterns which are easier to identify by an attacker.

To avoid those patterns a solution would be to use previous ciphertext block and concatenate it to the current block when encrypting current block. This way there are no patterns.

However- what do you concatenate to the first block? here comes the IV- Initialization vector. This servers as a initial value which can be used as the missing ciphertext block you concatenate to the first block of plaintext.