Use of Initialization Vector in Openssl_Encrypt

Use of Initialization Vector in openssl_encrypt

An IV is generally a random number that guarantees the encrypted text is unique.

To explain why it's needed, let's pretend we have a database of people's names encrypted with the key 'secret' and no IV.

1 John dsfa9p8y098hasdf
2 Paul po43pokdfgpo3k4y
3 John dsfa9p8y098hasdf

If John 1 knows his cipher text (dsfa9p8y098hasdf) and has access to the other cipher texts, he can easily find other people named John.

Now in actuality, an encryption mode that requires an IV will always use one. If you don't specify an IV, it's automatically set to a bunch of null bytes. Imagine the first example but with a constant IV (00000000).

1 John dsfa9p8y098hasdf 00000000
2 Paul po43pokdfgpo3k4y 00000000
3 John dsfa9p8y098hasdf 00000000

To prevent repeated cipher texts, we can encrypt the names using the same 'secret' key and random IV's:

1 John sdf875n90mh28458 86714561
2 Paul fg9087n5b60987nf 13541814
3 John gjhn0m89456vnler 44189122

As you can see, the two 'John' cipher texts are now different. Each IV is unique and has influenced the encryption process making the end result unique as well. John 1 now has no idea what user 3's name is.

Decryption requires the use of the same IV the text was encrypted with of course, which is why it must be stored along side the encrypted data. For decryption the IV is useless‡ without the key though so transmitting or storing it with the encrypted text is of no concern.

This is an overly simplistic example but the truth is, not using IV's has serious security ramifications, which is the reason IV's exist in the first place. Undoubtedly, countless IV-less encryption implementations have been exploited.

‡ As my security knowledge has progressed, I've learned that there are some more complicated exploits for various block cipher modes and concatenation techniques (not particularly related to the concatenation methodology described below) that can utilize IV's to attain keys. Notable examples exploit RC4 data streams to determine the keys and decrypt wi-fi traffic for older technologies like WEP and WPA:

  • Weaknesses in the Key Scheduling Algorithm of
    RC4
  • A Practical Attack on the Fixed RC4 in the
    WEP Mode

Now, your code appears to be setting the IV (1234567812345678) but not using it on decryption. That's certain to fail.

You also may want to utilize some of PHP's IV generation functions. I think this should work for you:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, 0, $iv);
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash, 0, $iv);

For storage/transmission, one option is to simply concatenate the IV and cipher text like so:

$data = $iv.$encryptedMessage;

Then on retrieval, pull the IV out for decryption:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = substr($data, 0, $iv_size);
$decryptedMessage = openssl_decrypt(substr($data, $iv_size), $encryptionMethod, $secretHash, 0, $iv);

If you're storing the IV in a database for example, you could also store the IV in an adjacent column to simplify the extraction process.


For more info, check out PHP's Mcrypt library. It's quite full featured and has tons of examples, many of which can help you out with openssh encryption implementations.
http://php.net/manual/en/function.mcrypt-encrypt.php


An obligatory security disclaimer: My words describe the simplest of simple concepts in the simplest possible way. In the reach and depth of my knowledge, I am an absolute novice. Even the best of the best security researchers and experts introduce encryption vulnerabilities all the time. Even so, the less you write on your own, the better off your users, customers, family, and friends will be. No offense! While it's fun, interesting, and even practical to learn about encryption theory, especially applied to computer science in something as accessible as PHP, staying up to date with best practices and using the latest trusted libraries is going to provide the most secure systems for 99.9999999% of us. Nothing is perfect, but it's best to stand on the shoulders of giants. As a wise man probably might have said, "The more you learn the more you realize how little you know."

How to fix openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in laravel?

Even though you are using a deprecated way to instantiate your class (using same name instead of __construct method) the sample code you provided is working.

You can improve your class like this.

class DES
{
private $key;
private $iv;
public function __construct(string $key, string $iv = '') {
$this->key = $key;
if(strlen($iv) != 8) {
$this->iv = \Illuminate\Support\Str::random(8);
} else {
$this->iv = $iv;
}
}

public function encrypt($str) {
return base64_encode( openssl_encrypt($str, 'DES-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv ) );
}

}

Is an Initialization Vector necessary if using different keys for each encrypted data set?

Is an Initialization Vector necessary if using different keys for each encrypted data set?

It depends on the mode. For ECB mode, no. In fact ECB mode does not take an IV. However, as soon as you encrypt data that is larger than the block size, you loose semantic security. That is, anything over the cipher's block size will leak information. See the picture of Tux at Block Cipher Modes of Operation.

Other modes, such as CBC, OFC, FBC, CTR and the others require an IV. The IV requirements differ among the modes, though. Some allow a unique IV, others require random IV, and some forbid reuse of an IV within a key.

As for your warning: just use a random IV with each encryption and you will avoid most of the pitfalls. If you re-encrypt a decrypted message, then use a fresh IV.

Is there an advantage to still using an IV or a disadvantage to not using an IV here?

Two messages encrypted under the same user will produce the same cipher text if the messages are the same. You've leaked information, and lost semantic security.

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.

openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended error phpmyadmin

This is due to the certificate was not properly renewed in apache server. Although you can access MySql Db in your server using Sql Workbench for windows and Sequel pro for Mac or if you want to fix this issue in your server you can perform this command

sudo apache2ctl stop

to stop the service, and

sudo apache2ctl start

to start it again.

The certificate will be renewed and Issue will be fixed.

Correct way to use php openssl_encrypt

First off, is the above example code a correct example of how to use php openssl_encrypt?

Your usage of the function looks correct, however you may want to consider a mode of operation other than CBC. CBC is tricky to get right because just encrypting data in this mode has known attacks against it, such as the infamous CBC bit-flipping attack, which allows an attacker to make meaningful changes to the plaintext by modifying the ciphertext. If possible I would use an authenticated encryption mode like GCM if you can (looks like it's supported in PHP 7.1+ (Example #1)).

If you use CBC mode take a look at Example #2 in the docs. Note that after encrypting a MAC (message authentication code) is computed over the ciphertext and stored. This MAC should be recomputed before decrypting the ciphertext, and if it does not match the stored MAC then the ciphertext has been modified and is invalid.

Second, is my method to generate the $key and $iv correct and secure? Because I keep on reading, keys should be cryptographically secure.

Keys need to be generated using a cryptographically secure random number generator. Luckily, most operating systems provide one out of the box via /dev/urandom. This answer does a good job explaining how to read from /dev/urandom in PHP. openssl_random_pseudo_bytes should also be cryptographically secure but there are times when this is not the case.

Initialization Vectors (IVs) need to be random and should never be reused with the same key.

Lastly, isn't a 32-byte value required for AES-256-CBC? If yes, then why is it that openssl_cipher_iv_length() returns only int(16) as the length? Shouldn't it be int(32)?

AES is a block cipher that works on 128 bit (16 byte) blocks, regardless of key size.



Related Topics



Leave a reply



Submit