4

According to the documentation of OpenSSL ( https://www.openssl.org/docs/apps/enc.html#OPTIONS ) they expect a hex-digit value for key and iv; does that mean only numbers? or will a md5 hash do? (Because a md5 doesn't seem reversible)

  • Note i'm mentioning key and iv because $password in the PHP function openssl_encrypt is actually the key.

(Almost) straight from PHP comments ( http://php.net/manual/en/function.openssl-encrypt.php )

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

$source = 'It works !';

$iv = substr( md5( "123sdfsdf4567812345678" ), 0, 16 );
$pass = '1234567812345678';
$method = 'aes-256-cbc';

echo "\niv in hex to use: ".$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 ".$iv;

echo 'executing: '.$exec."\n\n";
echo exec ($exec);
echo "\n";
jww
  • 97,681
  • 90
  • 411
  • 885
KaekeaSchmear
  • 1,548
  • 5
  • 18
  • 30

2 Answers2

3

Your first link is about the command-line tools, not the PHP functions. You'd have a hard time throwing binary data in a terminal, hence why the key there has to be hex-encoded.

In PHP however, openssl_encrypt() and openssl_decrypt() expect a raw binary string.

The documentation is also misleading in that it mentions a 'password' instead of 'key'. You've noticed that, but an encryption key is not something that you should just type in via your keyboard and md5()-ing anything is also never the answer for an encryption key. The key has to be randomly generated via openssl_random_pseudo_bytes() (or at least that's the most convenient way for your case):

$key = openssl_random_pseudo_bytes(32);

(the same goes for IVs as well)

If you need to hex-encode the resulting $key, just pass it to bin2hex(), but the example that you gave is a bit broken ... you're doing double encryption. Encrypting the file contents via PHP is enough, you don't need to deal with the command line.

Please note that my answer is far from the whole story about doing encryption. You should also add authentication, proper padding, think carefully of how to manage & store your keys, etc.

If you want to learn about it, here's a fairly short, but still descriptive blog post that gives the right answers to key points that you should cover: http://timoh6.github.io/2014/06/16/PHP-data-encryption-cheatsheet.html

If what you need is to simply get the job done - use a popular encryption library, don't write your own.

Narf
  • 14,600
  • 3
  • 37
  • 66
  • Correct me if I'm wrong, but AES 256 CBC requires a 256 bit encryption key. This implies that you actually need to generate 32 random bytes, not 16. – vmrob Jun 08 '15 at 17:07
  • 1
    You're not wrong, that was my mistake - updated the answer. Thanks. – Narf Jun 08 '15 at 17:13
1

It took me some time to work with the openssl documentation. Finally I had the solution to return encoded and decoded as ASCII text with base64_encode():

//Return encrypted string
public function stringEncrypt ($plainText, $cryptKey = '7R7zX2Urc7qvjhkr') {

  $length   = 8;
  $cstrong  = true;
  $cipher   = 'aes-128-cbc';

  if (in_array($cipher, openssl_get_cipher_methods()))
  {
    $ivlen = openssl_cipher_iv_length($cipher);
    $iv = openssl_random_pseudo_bytes($ivlen);
    $ciphertext_raw = openssl_encrypt(
      $plainText, $cipher, $cryptKey, $options=OPENSSL_RAW_DATA, $iv);
    $hmac = hash_hmac('sha256', $ciphertext_raw, $cryptKey, $as_binary=true);
    $encodedText = base64_encode( $iv.$hmac.$ciphertext_raw );
  }

  return $encodedText;
}


//Return decrypted string
public function stringDecrypt ($encodedText, $cryptKey = '7R7zX2Urc7qvjhkr') {

  $c = base64_decode($encodedText);
  $cipher   = 'aes-128-cbc';

  if (in_array($cipher, openssl_get_cipher_methods()))
  {
    $ivlen = openssl_cipher_iv_length($cipher);
    $iv = substr($c, 0, $ivlen);
    $hmac = substr($c, $ivlen, $sha2len=32);
    $ivlenSha2len = $ivlen+$sha2len;
    $ciphertext_raw = substr($c, $ivlen+$sha2len);
    $plainText = openssl_decrypt(
      $ciphertext_raw, $cipher, $cryptKey, $options=OPENSSL_RAW_DATA, $iv);
  }

  return $plainText;
}
Roman
  • 19,236
  • 15
  • 93
  • 97
  • 1
    The hmac should be calcuated on the ciphertext including the IV, not after. I'm not aware of any attack that leverages this, but its the proper way. – The Surrican Aug 07 '20 at 12:01