I'm working with cryptography on a project and I need a little help on how to work with openssl_encrypt
and openssl_decrypt
, I just want to know the most basic and correct way to do it. Here is what I got so far:
// To encrypt a string
$dataToEncrypt = 'Hello World';
$cypherMethod = 'AES-256-CBC';
$key = random_bytes(32);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cypherMethod));
$encryptedData = openssl_encrypt($dataToEncrypt, $cypherMethod, $key, $options=0, $iv);
I then store $cypherMethod
, $key
, and $iv
for use when decrypting the $encryptedData
. (Let's not elaborate how I store the values, thanks!)
// To decrypt an encrypted string
$decryptedData = openssl_decrypt($encryptedData, $cypherMethod, $key, $options=0, $iv);
First off, is the above example code a correct example of how to use php openssl_encrypt
?
Second, is my method to generate the $key
and $iv
correct and secure? Because I keep on reading, keys should be cryptographically secure.
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)
?
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.