Documentation on openssl_encrypt

openssl_encrypt = Encrypts data

Encrypts given data with given method and key, returns a raw or base64 encoded string

data The data. method The cipher method. For a list of available cipher methods, use openssl_get_cipher_methods(). password The password. options options is a bitwise disjunction of the flags OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING. iv A non-NULL Initialization Vector.

Usage, params, and more on openssl_encrypt

string openssl_encrypt ( string $data , string $method , string $password [, int $options = 0 [, string $iv = "" ]] )

data The data. method The cipher method. For a list of available cipher methods, use openssl_get_cipher_methods(). password The password. options options is a bitwise disjunction of the flags OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING. iv A non-NULL Initialization Vector.

Returns the encrypted string on success or FALSE on failure.

Emits an E_WARNING level error if an unknown cipher algorithm is passed in via the method parameter. Emits an E_WARNING level error if an empty value is passed in via the iv parameter.

Notes and warnings on openssl_encrypt

Other code examples of openssl_encrypt being used

Many users give up with handilng problem when openssl command line tool cant decrypt php openssl encrypted file which is encrypted with openssl_encrypt function.

For example how beginner is encrypting data:

<?php

$string
= 'It works ? Or not it works ?';
$pass = '1234';
$method = 'aes128';

file_put_contents ('./file.encrypted', openssl_encrypt ($string, $method, $pass));

?>

And then how beginner is trying to decrypt data from command line:

# openssl enc -aes-128-cbc -d -in file.encrypted -pass pass:123

Or even if he/she determinates that openssl_encrypt output was base64 and tries:

# openssl enc -aes-128-cbc -d -in file.encrypted -base64 -pass pass:123

Or even if he determinates that base64 encoded file is represented in one line and tries:

# openssl enc -aes-128-cbc -d -in file.encrypted -base64 -A -pass pass:123

Or even if he determinates that IV is needed and adds some string iv as encryption function`s fourth parameter and than adds hex representation of iv as parameter in openssl command line :

# openssl enc -aes-128-cbc -d -in file.encrypted -base64 -pass pass:123 -iv -iv 31323334353637383132333435363738

Or even if he determinates that aes-128 password must be 128 bits there fore 16 bytes and sets $pass = '1234567812345678' and tries:

# openssl enc -aes-128-cbc -d -in file.encrypted -base64 -pass pass:1234567812345678 -iv -iv 31323334353637383132333435363738

All these troubles will have no result in any case.

BECAUSE THE PASSWORD PARAMETER DOCUMENTED HERE IS NOT THE PASSWORD.

It means that the password parameter of the function is not the same string used as [-pass pass:] parameter with openssl cmd tool for file encryption decryption.

IT IS THE KEY !

And now how to correctly encrypt data with php openssl_encrypt and how to correctly decrypt it from openssl command line tool.

<?php

   
function strtohex($x)
    {
       
$s='';
        foreach (
str_split($x) as $c) $s.=sprintf("%02X",ord($c));
        return(
$s);
    }
   
   
$source = 'It works !';

   
$iv = "1234567812345678";
   
$pass = '1234567812345678';
   
$method = 'aes-128-cbc';

    echo
"\niv in hex to use: ".strtohex ($iv);
    echo
"\nkey in hex to use: ".strtohex ($pass);
    echo
"\n";

   
file_put_contents ('./file.encrypted',openssl_encrypt ($source, $method, $pass, true, $iv));

   
$exec = "openssl enc -".$method." -d -in file.encrypted -nosalt -nopad -K ".strtohex($pass)." -iv ".strtohex($iv);

    echo
'executing: '.$exec."\n\n";
    echo
exec ($exec);
    echo
"\n";

?>

IV and Key parameteres passed to openssl command line must be in hex representation of string.

The correct command for decrypting is:

# openssl enc -aes-128-cbc -d -in file.encrypted -nosalt -nopad -K 31323334353637383132333435363738 -iv 31323334353637383132333435363738

As it has no salt has no padding and by setting functions third parameter we have no more base64 encoded file to decode. The command will echo that it works...

: /

Beware of the padding this method adds !

<?php
$encryption_key
= openssl_random_pseudo_bytes(32);
$iv = openssl_random_pseudo_bytes(16);
$data = openssl_random_pseudo_bytes(32);

for (
$i = 0; $i < 5; $i++) {
$data = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA, $iv);
echo
strlen($data) . "\n";
}
?>

With this sample the output will be:
48
64
80
96
112

This is because our $data is already taking all the block size, so the method is adding a new block which will contain only padded bytes.

The only solution that come to my mind to avoid this situation is to add the option OPENSSL_ZERO_PADDING along with the first one:
<?php
$data
= openssl_encrypt($data, 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
?>

/!\ Be careful when using this option, be sure that you provide data that have already been padded or that takes already all the block size.

Since the $options are not documented, I'm going to clarify what they mean here in the comments.  Behind the scenes, in the source code for /ext/openssl/openssl.c:

    EVP_EncryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
    if (options & OPENSSL_ZERO_PADDING) {
        EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0);
    }

And later:

        if (options & OPENSSL_RAW_DATA) {
            outbuf[outlen] = '\0';
            RETVAL_STRINGL((char *)outbuf, outlen, 0);
        } else {
            int base64_str_len;
            char *base64_str;

            base64_str = (char*)php_base64_encode(outbuf, outlen, &base64_str_len);
            efree(outbuf);
            RETVAL_STRINGL(base64_str, base64_str_len, 0);
        }

So as we can see here, OPENSSL_ZERO_PADDING has a direct impact on the OpenSSL context.  EVP_CIPHER_CTX_set_padding() enables or disables padding (enabled by default).  So, OPENSSL_ZERO_PADDING disables padding for the context, which means that you will have to manually apply your own padding out to the block size.  Without using OPENSSL_ZERO_PADDING, you will automatically get PKCS#7 padding.

OPENSSL_RAW_DATA does not affect the OpenSSL context but has an impact on the format of the data returned to the caller.  When OPENSSL_RAW_DATA is specified, the returned data is returned as-is.  When it is not specified, Base64 encoded data is returned to the caller.

Hope this saves someone a trip to the PHP source code to figure out what the $options do.  Pro developer tip:  Download and have a copy of the PHP source code locally so that, when the PHP documentation fails to live up to quality expectations, you can see what is actually happening behind the scenes.