KaekeaSchmear
KaekeaSchmear

Reputation: 1578

openssl_encrypt, openssl_decrypt key, iv

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)

(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";

Upvotes: 4

Views: 11033

Answers (2)

Roman
Roman

Reputation: 21883

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;
}

Upvotes: 1

Narf
Narf

Reputation: 14752

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.

Upvotes: 3

Related Questions