简体   繁体   中英

Openssl aes-256-cbc encryption from command prompt and decryption in PHP (and vice versa)

I am trying to encrypt (openssl aes-256-cbc) a string through Windows command prompt and decrypt the result in PHP.

I have done the encryption through:

echo {un:est@test.com,upass:klkKJS*dfd!j@d76w} | openssl enc -e -aes-256-cbc -a -salt -pass pass:sw8/M!CLl:=cmgtHts?v/Wb7C$Vk9Sy-{go.*+E;[GAg~KQi*rI!1#z;x/KT

For decryption, my php code is:

$ivlen = openssl_cipher_iv_length('aes-256-cbc');
$iv = openssl_random_pseudo_bytes($ivlen);
echo openssl_decrypt('U2FsdGVkX18ruQUgA9LEOOvdOUQXv/o8z6ZNO820MKzSIbMjFcyfNo1efQwAOINxMY9+UxZjxaT+JEWmlUyYQw==', 'aes-256-cbc', 'sw8/M!CLl:=cmgtHts?v/Wb7C$Vk9Sy-{go.*+E;[GAg~KQi*rI!1#z;x/KT', $options=0, $iv);

But the decrypted string is empty. Please help.

(Note: I also need to do the reverse procedure, ie encryption in php and decryption from WIN command prompt. So please add any suggestion that may help.)

The OpenSSL statement generates a random 8 bytes salt during encryption, which is used together with the password to derive a 32 bytes key and a 16 bytes IV with the OpenSSL function EVP_BytesToKey() .

With key and IV the encryption is performed with AES-256 in CBC mode. The result consists of the concatenation of the ASCII encoding of Salted__ , followed by the salt and the actual ciphertext, all Base64 encoded.

The decryption in PHP/OpenSSL must be implemented as follows:

  • Determination of salt and actual ciphertext.
  • Using salt, password and EVP_BytesToKey() to get key and IV.
  • Using key and IV to perform decryption with AES-256 in CBC mode.

One possible implementation is:

<?php
function EVP_BytesToKey($salt, $password) {
    $bytes = '';
    $last = '';
    while(strlen($bytes) < 48) {
        $last = hash('md5', $last . $password . $salt, true);
        $bytes.= $last;
    }
    return $bytes;
} 
    
$saltCiphertext = base64_decode('U2FsdGVkX18ruQUgA9LEOOvdOUQXv/o8z6ZNO820MKzSIbMjFcyfNo1efQwAOINxMY9+UxZjxaT+JEWmlUyYQw==');
$salt = substr($saltCiphertext, 8, 8);
$ciphertext = substr($saltCiphertext, 16);
$keyIv = EVP_BytesToKey($salt, 'sw8/M!CLl:=cmgtHts?v/Wb7C$Vk9Sy-{go.*+E;[GAg~KQi*rI!1#z;x/KT');
$key = substr($keyIv, 0, 32);
$iv = substr($keyIv, 32);
echo openssl_decrypt($ciphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); // {un:est@test.com,upass:klkKJS*dfd!j@d76w}
?>

In earlier versions OpenSSL used MD5 as digest in EVP_BytesToKey() by default, from version V1.1.0 SHA256. In the posted example, decryption with MD5 is successful, so obviously MD5 was used in encryption.
Note that key derivation with EVP_BytesToKey() is deemed insecure nowadays.

As suggested by @Topaco for PHP openssl decryption of a string encoded through command prompt, here is an example of the opposite (PHP encryption to decode in command line). Thanks to @Topaco's comment and this piece of code .

<?php
function EVP_BytesToKey($salt, $password) {
    $bytes = '';
    $last = '';
    while(strlen($bytes) < 48) {
        $last = hash('md5', $last . $password . $salt, true);
        $bytes.= $last;
    }
    return $bytes;
}

$saltDeciphertext= '{un:est@test.com,upass:klkKJS*dfd!j@d76w}';
$crypttext = "Salted__";
$salt= random_bytes(8);
$crypttext .= $salt;
$keyIV= EVP_BytesToKey($salt, 'sw8/M!CLl:=cmgtHts?v/Wb7C$Vk9Sy-{go.*+E;[GAg~KQi*rI!1#z;x/KT');
$key = substr($keyIV, 0, 32);
$iv = substr($keyIV, 32);
$crypttext .= openssl_encrypt($saltDeciphertext, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
echo base64_encode($crypttext);
?>

Subsequent decryption command:

echo U2FsdGVkX1+rDCycmwvc6rImKmrzaC9WTlzFanXt476975aYQcxPt2fgnRazm7CorGkpAWm9vmcu33YpiTYziw== | openssl enc -d -aes-256-cbc -a -salt -pass pass:sw8/M!CLl:=cmgtHts?v/Wb7C$Vk9Sy-{go.*+E;[GAg~KQi*rI!1#z;x/KT

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM