This is the code I use to encrypt/decrypt the data:
// Set the method
$method = 'AES-128-CBC';
// Set the encryption key
$encryption_key = 'myencryptionkey';
// Generet a random initialisation vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));
// Define the date to be encrypted
$data = "Encrypt me, please!";
var_dump("Before encryption: $data");
// Encrypt the data
$encrypted = openssl_encrypt($data, $method, $encryption_key, 0, $iv);
var_dump("Encrypted: ${encrypted}");
// Append the vector at the end of the encrypted string
$encrypted = $encrypted . ':' . $iv;
// Explode the string using the `:` separator.
$parts = explode(':', $encrypted);
// Decrypt the data
$decrypted = openssl_decrypt($parts[0], $method, $encryption_key, 0, $parts[1]);
var_dump("Decrypted: ${decrypted}");
It ususaly works fine, but sometimes (1 in 10 or even less often) it fails. When it fails than the text is only partially encrypted:
This is the error message when it happens:
Warning: openssl_decrypt(): IV passed is only 10 bytes long, cipher expects an IV of precisely 16 bytes, padding with \0
And when it happens the encrypted text looks like:
Encrypt me���L�se!
I thought that it might be caused by a bug in PHP, but I've tested on different hosts: PHP 7.0.6 and PHP 5.6. I've also tried multiple online PHP parsers like phpfidle.org or 3v4l.org.
It seems that openssl_random_pseudo_bytes
not always returns a string of a proper length, but I have no idea why.
Here's the sample: https://3v4l.org/RZV8d
Keep on refreshing the page, you'll get the error at some point.
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));
with:$iv = base64_encode(openssl_random_pseudo_bytes(openssl_cipher_iv_length($method)));
Then the string length will not be 16 bytes long.openssl_encrypt
expects it to be 16 bytes long (In case of AES-128-CBC method). Did I miss something? – Gratitude