Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to use php openssl_encrypt

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)?

like image 817
Jo E. Avatar asked Dec 29 '17 05:12

Jo E.


People also ask

How do you use encrypt and decrypt in PHP?

In PHP, Encryption and Decryption of a string is possible using one of the Cryptography Extensions called OpenSSL function for encrypt and decrypt. openssl_encrypt() Function: The openssl_encrypt() function is used to encrypt the data. Parameters: $data: It holds the string or data which need to be encrypted.

What is IV in Openssl_encrypt?

Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in file phpseclib/Crypt/Base.php, line #1311. Running the same code on a redhat 7 system with openssl 1.0.


3 Answers

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.

like image 97
puzzlepalace Avatar answered Sep 30 '22 10:09

puzzlepalace


Here is the most basic way to use openssl_encrypt and openssl_decrypt. Make sure to create 32 byte secret_key and 16 byte secret_iv

function encrypt_decrypt($action, $string) 
    {
        $output = false;
        $encrypt_method = "AES-256-CBC";
        $secret_key = 'xxxxxxxxxxxxxxxxxxxxxxxx';
        $secret_iv = 'xxxxxxxxxxxxxxxxxxxxxxxxx';
        // hash
        $key = hash('sha256', $secret_key);    
        // iv - encrypt method AES-256-CBC expects 16 bytes 
        $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;
    }
like image 40
Shrish Shrivastava Avatar answered Sep 30 '22 12:09

Shrish Shrivastava


// --- Encrypt --- //
$key = openssl_digest("passkey", 'SHA256', TRUE);
$plaintext = "Data to be encrypted";
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
// binary cipher
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
// or replace OPENSSL_RAW_DATA & $iv with 0 & bin2hex($iv) for hex cipher (eg. for transmission over internet)

// or increase security with hashed cipher; (hex or base64 printable eg. for transmission over internet)
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
$ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );

// --- Decrypt --- //
$c = base64_decode($ciphertext);
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32);
$ciphertext_raw = substr($c, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
if (hash_equals($hmac, $calcmac))
    echo $original_plaintext."\n";
like image 26
Zimba Avatar answered Sep 30 '22 12:09

Zimba