Reputation: 53
I'm am trying to encrypt/decrypt some data using openssl_encrypt/openssl_decrypt. The purpose is as follows: the user enters some data in the GUI, this data is encrypted and stored at the database. Later it will be retrieved and decrypted only for a certain user profile.
The encrypt part is working fine since I've followed a colleague's advice, that is wrapping the output into a bin2hex function.
The whole point is I don't seem able to get a binary output when decrypting the data, even if I try to convert the output using hex2bin. I always get outputs like "� �Ps�1�_G�5�OUT".
I'm running out of ideas, actuallly I really don't know what to do at this point.
This is a sample code I've wrote to test this functions:
PHP
function encrypt($string) {
$cypher = 'aes-256-cbc';
$key = 's7aBkf4Ypn59bWviQziPDXyPasdaYlhQ';
$ivsize = openssl_cipher_iv_length($cypher);
$iv = openssl_random_pseudo_bytes($ivsize);
$encripted = openssl_encrypt(
$string, $cypher, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv
);
return $iv . $encripted;
}
function decrypt($string) {
$cypher = 'aes-256-cbc';
$key = 's7aBkf4Ypn59bWviQziPDXyPasdaYlhQ';
$ivsize = openssl_cipher_iv_length($cypher);
$iv = mb_substr($string, 0, $ivsize, '8bit');
$decrypted = mb_substr($string, $ivsize, null, '8bit');
$output = openssl_decrypt(
$decrypted, $cifrado, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv
);
return $output;
}
HTML:
<!doctype html>
<html>
<head><title>TEST</title></head>
<body>
<div style='margin-left:250px;'>
<form action="test.php" method="POST">
Encrypt
<input type="text" name="encrypt" value=''/>
<input type="submit" name="send" value='Send'/>
<br/><br/>
<?php
if (isset($_POST['encrypt']) && !empty($_POST['encrypt'])) {
echo 'encrypted string: ' . bin2hex(encrypt($_POST['encrypt']));
}
?>
<br/>
<br/>
Decrypt
<input type="text" name="decrypt" value=''/>
<input type="submit" name="send" value='Send'/>
<br/><br/>
<?php
if (isset($_POST['decrypt']) && !empty($_POST['decrypt'])) {
echo 'decrypted string: ' . decrypt($_POST['decrypt']);
var_dump(decrypt($_POST['decrypt']));
}
?>
</form>
</body>
Any ideas or help would be appreciated.
My PHP version is 5.4.45-0+deb7u2.
Thanks in advance.
Upvotes: 3
Views: 3425
Reputation: 4513
Updated in line with the remarks by @Zaph.
There was a minor syntax error. However the issue with the code is that, in the encrypt routine you are only allowed to us one of: OPENSSL_RAW_DATA or OPENSSL_ZERO_PADDING. It is mentioned in the documentation.
Comments from @Zaph: PKCS#7 padding which it the general padding, should be used. It turns out that the default for PHP OpenSSL is PKCS#7. So, do not add any padding option and you will get the right thing.
Openssl_encrypt()
adds PKCS7 padding to the plaintext before encrypting with a block cipher in CBC or ECB mode. Openssl_decrypt()
strips the padding after decryption.
I am using PHP 5.4.4.
So, the only option needed was: OPENSSL_RAW_DATA.
Please note that the IV (Initialisation Vector) is changed every time and stored in the output string. Why? If you provide the same string and password it is certain to be a different output string every time.
To enable the encrypted string to be stored safely anywhere. I have base64_encoded
it.
Demonstration at: ideone.com
###Encryption:
/**
* Encrypt a string
*
*
* @Param string $data
* @Param string $key
*
* @return string - base64_encoded
*/
function encrypt($data, $key) {
$cypher = 'aes-256-cbc';
$ivSize = openssl_cipher_iv_length($cypher);
$ivData = openssl_random_pseudo_bytes($ivSize);
$encripted = openssl_encrypt($data,
$cypher,
$key,
OPENSSL_RAW_DATA,
$ivData);
return base64_encode($ivData . $encripted);
}
###Decryption:
/**
* Decrypt a string
*
* @Param string $data
* @Param string $key
*
* @return string - original text
*/
function decrypt($data, $key) {
$cypher = 'aes-256-cbc';
$ivSize = openssl_cipher_iv_length($cypher);
$data = base64_decode($data);
$ivData = substr($data, 0, $ivSize);
$encData = substr($data, $ivSize);
$output = openssl_decrypt($encData,
$cypher,
$key,
OPENSSL_RAW_DATA,
$ivData);
return $output;
}
$srcText = "Hello World! - " . uniqid();
$key = 's7aBkf4Ypn59bWviQziPDXyPasdaYlhQ';
$srcEncrypted = '';
$srcDecrypted = '';
$srcEncrypted = encrypt($srcText, $key);
$srcDecrypted = decrypt($srcEncrypted, $key);
var_dump($srcText,
$srcEncrypted,
$srcDecrypted,
$srcDecrypted == $srcText);
###Sample output:
string 'Hello World! - 5776adf944c52' (length=28)
string 'NOjIIMM0visDbJPmBsAMgH+OQbYiReLBSvzg5JVZTMUOCAtk3CO7FBNs/Dn/vE9s' (length=64)
string 'Hello World! - 5776adf944c52' (length=28)
boolean true
Upvotes: 4