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

5

26

I am about to use the following script to encrypt and decrypt some data. I am using it because my current encryption does not work on our new server. We are currently using mcrypt so I want to change to openssl.

In our database we use aes encryption which uses a 128bit key so I know what a key is, but I do not know what an openssl iv is? And why would I need a key and an iv.

The code I am about to use is this, which I found on a website because I don't understand encryption very well.

Obviously I will modify it so that the key is kept somewhere else.

function encrypt_decrypt($action, $string) {
    $output = false;

    $encrypt_method = "AES-256-CBC";
    $secret_key = 'This is my secret key';
    $secret_iv = 'This is my secret iv';

    // hash
    $key = hash('sha256', $secret_key);

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

    if( $action == 'encrypt' ) {
        $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
        $output = base64_encode($output);
    }
    else if( $action == 'decrypt' ){
        $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
    }

    return $output;
}

$plain_txt = "This is my plain text";
echo "Plain Text = $plain_txt\n";

$encrypted_txt = encrypt_decrypt('encrypt', $plain_txt);
echo "Encrypted Text = $encrypted_txt\n";

$decrypted_txt = encrypt_decrypt('decrypt', $encrypted_txt);
echo "Decrypted Text = $decrypted_txt\n";

if( $plain_txt === $decrypted_txt ) echo "SUCCESS";
else echo "FAILED";

echo "\n";
Sternick answered 9/9, 2016 at 13:31 Comment(4)
iv = initialization vector. Would be prudent to invest sometime understanding encryption before trying to implement it.Colliery
I understand how mysql encryption works using AES_ENCRYPT but that is for mysql. This is just for php strings which need encryptingSternick
@ThomasWilliams By default MySQL's AES_ENCRYPT uses ECB mode, not CBC. The use of ECB is why MySQL does not require you to give it an IV.Pyrogen
If you don't understand these things then you need to be using higher-level crypto APIs that take care of these details correctly.Confectionery
P
30

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.

Pyrogen answered 9/9, 2016 at 13:37 Comment(10)
one tiny addition: stored along with the ciphertext ... some people tend to simply put it in front of the ciphertext and don't mark it as IV ... sometimes it is worth a try to simply see the first blocksize of bits of a ciphertext as a candidate for an IV that was just stored along...Fluoroscopy
I am going to be using this to encrypt strings for a url eg www.somesite.com?a=mystring. If an iv is randomly generated how are you going to decrypt it. I agree I need to do some more reading on this, but my google searches have just led to more confusion. I did actually google this a lot before asking the question.Sternick
Then use www.somesite.com?a=encypyptedstring&iv=theiv.Pyrogen
So am I right in thinking that the iv is like bcrypt string which is at the start of every bcrypt hash eg $2y$10$. Also does it matter about the length of an ivSternick
@ThomasWilliams The IV can be stored anywhere you'd like. Yes, you can put it in front of the ciphertext with a separator if you choose. An IV in AES is always the size of the block size, which in AES's case is 128-bits, or 16 bytes.Pyrogen
Thanks I am googling how to make a CSPRNG nowSternick
ahh I found an openssl command which does this openssl_random_pseudo_bytes reading up on it now.Sternick
@ThomasWilliams With all due respect, you shouldn't be implementing this yourself. Your lack of knowledge about the subject means that you will be very likely to make an implementation mistake and leave a gaping hole in your security. Just my two cents. Find a higher level library.Elsworth
I have got it all working. My lack of knowledge was with openssl. However I have been programming quite a long time in c++ and php. I have been reading a lot about it since asking the question and I have got it all implemented and working. I wrote my own encryption algorithm in C++ once, but it is better to use something that is tried and tested rather than your own code.Sternick
"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." ..and TP Link uses the same iv and key for most of their products.. Jesus..Simonsimona
T
15

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”? .

Tarnetgaronne answered 19/11, 2019 at 18:24 Comment(1)
Sorry for the silly question, but does this mean it's impossible to write search functionality for the particular record? What I mean is, if I re-used the same IV then I could encrypt the search and search for a match, but if there is a different encrypted value then obviously searching by that encrypted value cannot be done? And with that in mind, must I assume that I shouldnt be really be storing sensitive data that I expect to be searchable. Its just searching by someones name comes to mind.Zitella
P
7

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".

Pentylenetetrazol answered 23/5, 2017 at 19:45 Comment(2)
love the explanation re creating $ivSpacetime
When putting it as prefix to the cypher message in a file, which format should be the generated IV?Pa
E
2

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.

Epididymis answered 19/8, 2021 at 10:30 Comment(0)
B
0

I usually set up something like this:

    // PHP Function to encrypt
function encrypt_AES_CBC ($plaintext) {
    $method = "aes-256-cbc";
    $key = "DADA068D255130F7AB5965BD47692E359EE7B0CBC81D9DAD42665B71F7807A4E";
    $bkey = hex2bin($key);
    $iv = hex2bin(md5(microtime().rand()));
    $data = openssl_encrypt($plaintext, $method, $bkey, OPENSSL_RAW_DATA, $iv);
    return base64_encode($iv.$data);
}
// PHP Function to decrypt
function decrypt_AES_CBC ($encryptedText) {
    $method = "aes-256-cbc";
    $key = "DADA068D255130F7AB5965BD47692E359EE7B0CBC81D9DAD42665B71F7807A4E";
    $bkey = hex2bin($key);
    $decoded = base64_decode($encryptedText);
    $iv = substr($decoded, 0, 16);
    $data = substr($decoded, 16);
    return openssl_decrypt( $data, $method, $bkey, OPENSSL_RAW_DATA, $iv );
}

I have created a FileMaker plugin (acfplugin) that can generate this sample code for a given verbal key.

Bibliotheca answered 21/3, 2021 at 6:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.