Use openssl_decrypt() with passphase (not key/iv)

Multi tool use


Use openssl_decrypt() with passphase (not key/iv)
I'm trying to decrypt some data that has been encrypted with a passphrase and aes-256-cbc
method in a PHP script.
aes-256-cbc
Here is how I encrypt the original data
printf "Hello" | openssl enc -e -base64 -A -aes-256-cbc -k "MYPASSWORD"
// output
U2FsdGVkX1+dWuBuiitifH4zu1Yv/l7+HcfIqR/wxSc=
When I try to decrypt it in command-line it works fine
printf "U2FsdGVkX1+dWuBuiitifH4zu1Yv/l7+HcfIqR/wxSc=" | openssl enc -d -base64 -A -aes-256-cbc -k "MYPASSWORD"
// output
Hello
BUT when I use openssl_decrypt() in my PHP script it doesn't work!!
$result = openssl_decrypt("U2FsdGVkX1+dWuBuiitifH4zu1Yv/l7+HcfIqR/wxSc=", 'AES-256-CBC', "MYPASSWORD");
var_dump($result);
//output
bool(false)
I append the following lines to get the error
while ($msg = openssl_error_string())
echo $msg . "<br />n";
And it returns:
error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad
decrypt
I know that I should use a key/iv pair but I am not able to extract it from my passphrase with any salt. How can I get it to make the following command work?
printf "U2FsdGVkX1+dWuBuiitifH4zu1Yv/l7+HcfIqR/wxSc=" | openssl enc -d -base64 -A -aes-256-cbc -K ??????????????? -iv ????????????????
// expected output !!!
Hello
EDIT:
I tried to get key/iv with -P
argument but it doesn't work
-P
printf "U2FsdGVkX1+dWuBuiitifH4zu1Yv/l7+HcfIqR/wxSc=" | openssl enc -d -base64 -A -aes-256-cbc -k "MYPASSWORD" -p
salt=9D5AE06E8A2B627C
key=8ACC4E30E9128FBB0763DDDA8998A7141DFDC77B9DADF0A5FC65E67E2A8313FA
iv =4150125DCCD36F73A9F08F3020151A04
Hello
printf "U2FsdGVkX1+dWuBuiitifH4zu1Yv/l7+HcfIqR/wxSc=" | openssl enc -d -base64 -A -aes-256-cbc -K 8ACC4E30E9128FBB0763DDDA8998A7141DFDC77B9DADF05E67E2A8313FA -iv 4150125DCCD36F73A9F08F3020151A04
bad decrypt
140735954895816:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:529:
??G?"r!C???&C&??
2 Answers
2
The issue here is that you are not using EVP_BytesToKey
. This is the OpenSSL KDF used to derive a key and IV from your password.
EVP_BytesToKey
Note that it is insecure. You should prefer passing a hex key and IV directly to openssl enc
.
openssl enc
There is a difference between the password (or passphrase) used as a parameter to openssl enc
via the -k
option (in your case "MYPASSWORD"
) and the key
parameter that the PHP function openssl_decrypt()
expects. The -k
option to openssl enc
is a passphrase of any length from which an actual 256 bits encryption key will be derived. That is also the key that the PHP openssl_decrypt()
function needs. This encryption key is 256 bits because you have chosen aes-256
.
openssl enc
-k
"MYPASSWORD"
key
openssl_decrypt()
-k
openssl enc
openssl_decrypt()
aes-256
You can get to know what that derived encryption key is by adding the -p
option when invoking openssl enc
. This also prints the iv
, another parameter that you will need to use with the PHP openssl_decrypt()
function. For example:
-p
openssl enc
iv
openssl_decrypt()
printf "Hello" | openssl enc -e -base64 -A -aes-256-cbc -k "MYPASSWORD" -nosalt -p
key=E0FAC2DD2C00FFE30F27A6D14568CB4F12EB84676A3A2BFB172A444C3BBB831F
iv =5A79774BB4B326EED949E6871FC27697
sp0z18QezUO8tSy7tgjOEw==
These printed key
and iv
values are the ones that you will need to feed into your PHP openssl_decrypt()
function invocation, like this:
key
iv
openssl_decrypt()
$ciphertext = 'sp0z18QezUO8tSy7tgjOEw==';
$key = hex2bin('E0FAC2DD2C00FFE30F27A6D14568CB4F12EB84676A3A2BFB172A444C3BBB831F');
$iv = hex2bin('5A79774BB4B326EED949E6871FC27697');
$result = openssl_decrypt($ciphertext, 'AES-256-CBC', $key, 0, $iv);
var_dump($result);
Running the PHP script now results in success:
$ php decrypt.php
string(5) "Hello"
You may have noticed the extra -nosalt
option when running openssl enc
. Salt is used to add some randomness/uniqueness to the key derivation process and -nosalt
omits that step. As a result, the key
, iv
and ciphertext
will be the same in every run (if the same passphrase and plaintext are used) and you should be able to exactly reproduce the output. If you do not use -nosalt
, your experiment will still work but the key
, iv
and ciphertext
values will be different for each run.
-nosalt
openssl enc
-nosalt
key
iv
ciphertext
-nosalt
key
iv
ciphertext
Another option would be to let the PHP code derive the key
and iv
from the passphrase before invoking openssl_decrypt()
. To do that, you will have to inspect the code of the enc
tool for the openssl
version that you are using. There you can see which key derivation function is used -- it depends on the version of openssl
you are using as well as the options you are giving it -- and whether that is available in the PHP bindings of openssl
.
key
iv
openssl_decrypt()
enc
openssl
openssl
openssl
Update, responding to your comment where you add the information that you only have the ciphertext and the passphrase available and that ciphertext was created with crypto-js
.
crypto-js
Looking at the source code of crypto-js
, it mentions in a comment in the source file evpkdf.js
that "the key derivation function is meant to conform with EVP_BytesToKey", which is the same function that most openssl
versions use. So you should be able to use the openssl enc
tool to extract the key
and the iv
by using the -p
option, like this:
crypto-js
evpkdf.js
openssl
openssl enc
key
iv
-p
$printf "U2FsdGVkX1+dWuBuiitifH4zu1Yv/l7+HcfIqR/wxSc=" | openssl enc -d -base64 -A -aes-256-cbc -k "MYPASSWORD" -p
salt=71A87BEBF4581AB3
key=917293FEC17514C078D156A8C4787B04A585167BD997E884E4C4219FEA0DC2A1
iv =DA6A91BC5F86B1EEE5C57DF97282C204
(which you have confirmed in another comment by now as well) and then use those when invoking the PHP function, as described above. Note that you will have to do this for every ciphertext separately, because the salt
(and thus the key
and iv
) were chosen differently, randomly by crypto-js
for each encryption action. To do this in PHP directly, see my previous remark: the required functionality does not seem to be available in its decrypt
module.
salt
key
iv
crypto-js
decrypt
All that said, you would probably be better off moving away from the key derivation that openssl enc
and crypto-js
use and that relies on the proprietary mechanism implemented by the OpenSSL EVP_ByesToKey
function. Even openssl enc
now warns about this being deprecated .
openssl enc
crypto-js
EVP_ByesToKey
openssl enc
Instead, start using a standard algorithm like PBKDF2. This is supported by more recent versions of openssl enc
and I have spotted it in the source code of the crypto-js
and PHP crypto
modules as well (but have never used those myself). If you have a database of encrypted data that you need to keep, you can re-encrypt its contents one time, using the old approach to decrypt and the PKDBF2 approach to encrypt.
openssl enc
crypto-js
crypto
What
openssl
cmd-line command do you use to decrypt those ciphertexts with only the passphrase?– Reinier Torenbeek
18 hours ago
openssl
printf "U2FsdGVkX1+dWuBuiitifH4zu1Yv/l7+HcfIqR/wxSc=" | openssl enc -d -base64 -A -aes-256-cbc -k "MYPASSWORD"
– B 7
18 hours ago
printf "U2FsdGVkX1+dWuBuiitifH4zu1Yv/l7+HcfIqR/wxSc=" | openssl enc -d -base64 -A -aes-256-cbc -k "MYPASSWORD"
OK, just add the
-p
option to that line and it will print the key
and the iv
that you need to use in your PHP
script. I added this to the answer.– Reinier Torenbeek
18 hours ago
-p
key
iv
PHP
I added a final remark about a better way forward... In a nutshell: stop using proprietary openssl stuff.
– Reinier Torenbeek
16 hours ago
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Hi @Reinier. Thank you for you help! I understand your answer but my problem is that I have some ciphertexts and its passphrase. I used CryptoJS to generate ciphertexts and I stored them in DB. And now I need to retrieve the original string in a PHP script. So I need to get key/iv from the passphrase. I can't generate a new ciphertext. It should be possible because openssl in cmd-line is able to decrypt ciphertexts with only passphrase
– B 7
19 hours ago