1

I've written a small class for symmetric encryption with openssl, and it encrypts and decrypts fine within PHP, but I cannot seem to either decrypt the output using the command line, or encrypt the same data in the same way.

My class is:

Class SimpleCrypt {

    public static function encrypt($password, $data, $enc_method='AES-256-CBC', $hash_method='SHA512') {
        self::check_methods($enc_method, $hash_method);
        $iv = self::hashIV($password, $hash_method, openssl_cipher_iv_length($enc_method));
        $infostr = sprintf('$%s$%s$', $enc_method, $hash_method);
        return $infostr . openssl_encrypt($data, $enc_method, $password, false, $iv);
    }

    public static function decrypt($password, $edata) {
        $e_arr = explode('$', $edata);
        if( count($e_arr) != 4 ) {
            Throw new Exception('Given data is missing crucial sections.');
        }
        $enc_method = $e_arr[1];
        $hash_method = $e_arr[2];
        self::check_methods($enc_method, $hash_method);
        $iv = self::hashIV($password, $hash_method, openssl_cipher_iv_length($enc_method));
        return openssl_decrypt($e_arr[3], $enc_method, $password, false, $iv);
    }

    private static function hashIV($password, $method, $iv_size) {
        $myhash = hash($method, $password, TRUE);
        while( strlen($myhash) < $iv_size ) {
            $myhash .= hash($method, $myhash, TRUE);
        }
        return substr($myhash, 0, $iv_size);
    }

    private static function check_methods($enc, $hash) {
        if( ! function_exists('openssl_encrypt') ) {
            Throw new Exception('openssl_encrypt() not supported.');
        } else if( ! in_array($enc, openssl_get_cipher_methods()) ) {
            Throw new Exception('Encryption method ' . $enc . ' not supported.');
        } else if( ! in_array(strtolower($hash), hash_algos()) ) {
            Throw new Exception('Hashing method ' . $hash . ' not supported.');
        }
    }

} // -- end class SimpleCrypt -- //


$enc = SimpleCrypt::encrypt('pass', 'test data');
$dec = SimpleCrypt::decrypt('pass', $enc);
echo $enc . "\n" . $dec;
// Output:
// $AES-256-CBC$SHA512$yH0uN95Vya0pTwcoJRFb+g==
// test data

This bit of code reproduces the IV:

php -r 'echo strtoupper(bin2hex(substr(hash("SHA512", "pass", true), 0, openssl_cipher_iv_length("AES-256-CBC"))));'
//output: 5B722B307FCE6C944905D132691D5E4A

But this code gives me garbled otuput that doesn't resemble the input:

$ echo yH0uN95Vya0pTwcoJRFb+g== | base64 -d | openssl enc -AES-256-CBC -d -nosalt -nopad -k pass -iv 5B722B307FCE6C944905D132691D5E4A
ã`ÈAgè}½5øÍÝEÞ
00000000  e3 60 c8 41 67 e8 7d bd  35 00 f8 cd dd 45 13 de  |.`.Ag.}.5....E..|

Encoding the data from the command line gives me:

$ echo "test data" | openssl enc -e -AES-256-CBC -nosalt -k pass -iv 5B722B307FCE6C944905D132691D5E4A | hexdump -C
00000000  ca fc 84 6a 95 51 8f 0e  61 14 96 77 4e 22 dd 39  |...j.Q..a..wN".9|

$ echo "test data" | openssl enc -e -AES-256-CBC -nosalt -k pass -iv 5B722B307FCE6C944905D132691D5E4A | base64
yvyEapVRjw5hFJZ3TiLdOQ==

Can anyone tell me what I've done incorrectly in my PHP code?

Solution

Just to recap the solution from the Daniel's answer, we need to use the -K argument to openssl rather than -k or -pass and it expects a hex representation of the string. eg:

echo strtoupper(bin2hex('pass'));
//output: 70617373

And then the proper command is:

echo yH0uN95Vya0pTwcoJRFb+g== | base64 -d | openssl enc -AES-256-CBC -d -nosalt -K 70617373 -iv 5B722B307FCE6C944905D132691D5E4A | hexdump -C
00000000  74 65 73 74 20 64 61 74  61                       |test data|

1 Answer 1

1

The badly named password argument to PHP's openssl_encrypt() is not a password, it is the actual key. When using command line openssl enc with lower-case -k, OpenSSL will derive a key from the password using a key derivation function. You want to use openssl enc with upper-case -K and a hexadecimal representation of the key; and make sure to hand openssl_encrypt() a long enough key in the password argument.

See also the very first user-contributed note in the PHP manual on openssl_encrypt().

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.