mcrypt_decrypt is returning a null repsonse - php

I can encrypt strings in php but I cannot decrypt my strings in php when calling the decrypt function, I get a null response. What am I doing wrong? my code is below.
<?php
$txt = "Hello";
$mykey = "mysecretkey12345";
$iv_to_pass_to_decryption = 'mysecretpass23456';
function encrypt($text, $key)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
$iv_to_pass_to_decryption = base64_encode($iv);
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv));
}
function decrypt($text, $key, $ivdecrypt)
{
$text = base64_decode($text);
$ivdecrypt = base64_decode($ivdecrypt);
return base64_decode(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $ivdecrypt));
}
$encryptdata = encrypt($txt, $mykey); // encrypt works fine
$decryptdata = decrypt($encryptdata, $mykey, $iv_to_pass_to_decryption); // Im getting null response from decrypt
echo 'Encrypt: ' . $encryptdata . ' Decrypt: ' . $decryptdata;
?>
Example echo output is:
Encrypt: j42DGZVT/cKIWEe5p3289aWGOZCtZ8yN3MuUidi2InM= Decrypt:

There are two issues I see:
a) The encrypt function assigns the iv to a local variable. You can make it global by including global $iv_to_pass_to_decryption;at the beginning of the encrypt function.
b) In the return statement of the decrypt function you base_decode the message. But you don't encode it going in. Just remove the base64_decode after return.

Related

PHP encryption using OpenSSL

I have been trying to write two functions that will encrypt and decrypt my data, as I'm storing some information that I don't want going into database in plain text. The function that encrypts works fine. But I don't know why the decryption doesn't bring back the plain text?
Is there something I have done wrong?
<?php
$string = "This is my string!";
$encryption_key = "DVF0!LoQs2bPyTvSF0epXPFStbIn!057";
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(AES_256_CBC));
function encryptString($encryption_key, $iv, $string) {
define('AES_256_CBC', 'aes-256-cbc');
$encrypted = openssl_encrypt($string, AES_256_CBC, $encryption_key, 0, $iv);
return $encrypted;
}
function decryptString($encryption_key, $iv, $encrypted) {
define('AES_256_CBC', 'aes-256-cbc');
$encrypted = $encrypted . ':' . $iv;
$parts = explode(':', $encrypted);
$decrypted = openssl_decrypt($parts[0], AES_256_CBC, $encryption_key, 0, $parts[1]);
return $decrypted;
}
$encryptstring = encryptString($encryption_key, $iv, $string);
$decryptstring = decryptString($encryption_key, $iv, $encryptstring);
?>
Original: <? print $string; ?>
Encryption Key: <?php print $encryption_key; ?>
Encrypted func: <?php print $encryptstring; ?>
Decrypted func: <?php print $decryptstring; ?>
Your encryption key changes with each function call using openssl_random_pseudo_bytes
Make the key static such as $encryption_key = "XXXX"; or global the variable and only call it once.
Don't forget to apply that to your $iv as well.

Cannot use a constant IV key and a produced ENCRYPT_KEY in php mcrypt

I know that a constant IV key is wrong and a random key must be generated. I, however need this as I have been assigned to do this. I have searched all over the net on how to deal with this but failed. My code is below, and any advice will be greatly apprecieted.
Here's the whole code together with the functions
define('ENCRYPTION_KEY', 'ITU2NjNhI0tOc2FmZExOTQ=='); //Encryption KEY
// Encrypt Function
function mc_encrypt($encrypt, $key)
{
//Do Not Put ENCRYPTION_KEY here
$encrypt = serialize($encrypt);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
//$iv = ('AAAAAAAAAAAAAAAAAAAAAA==');
$key = pack('H*', $key);
$mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
$passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $iv);
$encoded = base64_encode($passcrypt).'|'.base64_encode($iv);
return $encoded; //return base64_encode($encoded).':'.$iv;
}
// Decrypt Function
function mc_decrypt($decrypt, $key)
{
$decrypt = explode('|', $decrypt);
$decoded = base64_decode($decrypt[0]);
$iv = base64_decode($decrypt[1]);
if(strlen($iv) !== mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC))
{
return false;
}
$key = pack('H*', $key);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv));
$mac = substr($decrypted, -64);
$decrypted = substr($decrypted, 0, -64);
$calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));
if($calcmac !== $mac)
{
return false;
}
$decrypted = unserialize($decrypted);
return $decrypted;
}
echo '<h1>Sample Encryption</h1>';
$data = 'Patrick';
$encrypted_data = mc_encrypt($data, ENCRYPTION_KEY);
echo '<h2>Example #1: String Data</h2>';
echo 'Data to be Encrypted: ' . $data . '<br/>';
echo 'Encrypted Data: ' . $encrypted_data . '<br/>';
echo 'Decrypted Data: ' . mc_decrypt($encrypted_data, ENCRYPTION_KEY) . '</br>';
If i use that I get the error
Warning: pack(): Type H: illegal hex digit I in C:\xampp\htdocs\sample1\test.php on line 24
and when I use the
$iv = ('AAAAAAAAAAAAAAAAAAAAAA==');
Instead of this
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
while they have both
define('ENCRYPTION_KEY', 'd0a7e7997b6d5fcd55f4b5c32611b87cd923e88837b63bf2941ef819dc8ca282'); //Encryption KEY
this is the error
Warning: mcrypt_encrypt(): The IV parameter must be as long as the blocksize in C:\xampp\htdocs\sample1\test.php on line 26
This is working and tested code on PHP 5.3.18. Demonstration at Viper-7
1) It uses the required base64 encoded 'AAAAAAAAAAAAAAAAAAAAAA==', as the IV ('salt'), which when converted back to a string is 16 bytes of binary zeroes. As we need 32 bytes i just concatenate it with itself to make the required length.
2) There are two supplied keys:
1) base64 encoded: 'ITU2NjNhI0tOc2FmZExOTQ==', which is a 'typical' high quality password string that is 16 bytes long. This needs to converted to a hex string for the encryption functions.
2) The hexadecimal literal: 'd0a7e7997b'...
Please note: The supplied keys, as hex strings, are not equal to each other!
This does not affect the routines, just be aware that the same key must be used to encrypt / decrypt.
The routines:
// Encrypt Function - $key must be a Hexadecimal String
function mc_encrypt($encrypt, $key) {
//Do Not Put ENCRYPTION_KEY here
$encrypt = serialize($encrypt);
// $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
$iv = base64_decode(ENCRYPTION_IV); // convert back to binary string
$actualIV = $iv . $iv; // As it is 16 bytes of binary characters just double it
$key = pack('H*', $key); // convert key back to binary string
$mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
$passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $actualIV);
$encoded = base64_encode($passcrypt).'|'.base64_encode($iv);
return $encoded;
}
Note that '$actualIV' is just a 'trick' to get the 32 bytes required. However, it will work if different 16 byte IV's are used.
Caveats: It is important that different (random) IV's are used when encrypting otherwise identical messages encrypt to the same ciphertext when the same key is used. To use 16 byte IV's in the routine i would be tempted to generate a random IV and just use the first 16 bytes of it concatenated to itself as is used currently.
i.e. replace this code:
$iv = base64_decode(ENCRYPTION_IV); // convert back to binary string
with:
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
$iv = substr($iv, 0, 16);
CBC mode and 'Padding Oracle Attacks'
It looks as though this is not an issue if you use PHP exclusively. There may be issues decrypting on different systems. This link explains the issues: Cryptography/DES-PHP-Block-Padding-in-mcrypt.html
// Decrypt Function - - $key must be a Hexadecimal String
function mc_decrypt($decrypt, $key) {
$decrypt = explode('|', $decrypt);
$decoded = base64_decode($decrypt[0]);
$iv = base64_decode($decrypt[1]);
$actualIV = $iv . $iv; // make it long enough and match the original IV used.
if(strlen($actualIV) !== mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC)){ return false; }
$key = pack('H*', $key);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $actualIV));
$mac = substr($decrypted, -64);
$decrypted = substr($decrypted, 0, -64);
$calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));
if($calcmac!==$mac) { return false; }
$decrypted = unserialize($decrypted);
return $decrypted;
}
Note that '$iv' is concatenated with itself to get the 32 bytes required.
Defined keys:
define('ENCRYPTION_B64KEY', 'ITU2NjNhI0tOc2FmZExOTQ=='); //Encryption KEY
define('ENCRYPTION_IV', 'AAAAAAAAAAAAAAAAAAAAAA==');
define('ENCRYPTION_HEXKEY', 'd0a7e7997b6d5fcd55f4b5c32611b87cd923e88837b63bf2941ef819dc8ca282'); //Encryption KEY
Examples using both supplied keys:
echo '<h1>Sample Encryption</h1>';
$data = 'Patrick';
echo '<h2>Example #1: Using base64 encoded key (ENCRYPTION_B64KEY)</h2>';
$b64HexKey = bin2hex(base64_decode(ENCRYPTION_B64KEY));
$encrypted_data = mc_encrypt($data, $b64HexKey);
echo 'Data to be Encrypted: ' . $data . '<br/>';
echo 'Encrypted Data: ' . $encrypted_data . '<br/>';
echo 'Decrypted Data: ' . mc_decrypt($encrypted_data, $b64HexKey) . '</br>';
echo '<h2>Example #2 using Hexadecimal Key (ENCRYPTION_HEXKEY)</h2>';
$hexKey = ENCRYPTION_HEXKEY;
$encrypted_data = mc_encrypt($data, $hexKey);
echo 'Data to be Encrypted: ' . $data . '<br/>';
echo 'Encrypted Data: ' . $encrypted_data . '<br/>';
echo 'Decrypted Data: ' . mc_decrypt($encrypted_data, $hexKey) . '</br>';
Output from the above:
Sample Encryption
Example #1: Using base64 encoded key (ENCRYPTION_B64KEY)
Data to be Encrypted: Patrick
Encrypted Data: /7qKjoPnNiGveTHo0NnkXfSLFIHE72De1q85QWI/d16j4BzLaqIR7jpap0J2wCdHYgK+IS4Zf1OpZorK9iGnPErkh+owjkoEo/dejHxUaVxOS03+Uqti8i13aGeB6wAU|AAAAAAAAAAAAAAAAAAAAAA==
Decrypted Data: Patrick
Example #2 using Hexadecimal Key (ENCRYPTION_HEXKEY)
Data to be Encrypted: Patrick
Encrypted Data: iAyCpfnOHUeHKHT+BIra2TZbRlLJfXKAO5pRGbmKvLyTOlzr9L6IBRI8ZuDsGVdZym26Qd89hKZxnVPbBSsOktCaztF9akZA8iPa3r0jvgISFldRDdHx8CZyd+GfR9BV|AAAAAAAAAAAAAAAAAAAAAA==
Decrypted Data: Patrick

SHA1 the PHP mcrypt_decrypt result

I have 2 encrypt & decrypt functions using PHP mcrypt library.
public function encrypt_string($input, $key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$cipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $input, MCRYPT_MODE_CBC, $iv);
return base64_encode($iv . $cipher);
}
public function decrypt_string($input, $key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$ciphertext = base64_decode($input);
$iv = substr($ciphertext, 0, $iv_size);
$cipher = substr($ciphertext, $iv_size);
return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipher, MCRYPT_MODE_CBC, $iv);
}
Given that the key is generated by:
$key = pack('H*', 'dfgsdighsdfksdhfosdfasdjldsfsdfgdfkgdl'); // a random key
I can successfully obtain back the input after encryption & decryption.
Here is the code:
$pass = '123456';
echo sha1($pass) . PHP_EOL; // prints 7c4a8d09ca3762af61e59520943dc26494f8941b
$pass_cipher = encrypt_string($pass, $key);
$pass_decrypt = decrypt_string($pass_cipher, $key);
echo $pass_decrypt . PHP_EOL; // prints 123456
echo sha1($pass_decrypt) . PHP_EOL; // prints f41b44dbecccaccfbb4ccf6a7fc4921c03878c6d
However, the SHA1 result is different:
7c4a8d09ca3762af61e59520943dc26494f8941b // before encrypt & decrypt
f41b44dbecccaccfbb4ccf6a7fc4921c03878c6d // after encrypt & decrypt
Why is it different ? What did I miss ?
UPDATE:
The accepted answer is useful. For people who wants additional information, here it is:
echo bin2hex($pass) . PHP_EOL; // prints 313233343536
echo bin2hex($pass_decrypt) . PHP_EOL; // prints 31323334353600000000000000000000
and after trim(), the SHA1 result works as expected, as empty hidden 0 are removed.
Problem is that your decrypt_string returns 16 bytes string, that is filled with 0 bytes at the right side. It's a problem known for about 2 years.
Remove null bytes from the right with line similar to this one:
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipher, MCRYPT_MODE_CBC, $iv), "\0");
Be careful not to encrypt things with null character at the end, as cryptology functions in PHP works as if all strings were null-terminated and are not shy to cut string at first \0 or to return a bit of \0s glued to the end of their output.
in post encrypted data + sign will be replaced with whitespace. thats why decryption was not done .

Issue with PHP mcrypt function

I use the following function to decrypt data on my server:
function decrypt($key, $text) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}
I have read a lot about NOT using ECB however (and know it is deprecated so wanted to switch to CBC. Simply switching the mode to:
function decrypt($key, $text) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_CBC, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND)));
}
does not work however. No errors are generated but the data returned is still encrypted.
What am I missing?
Updated code - still with errors:
$key = "hello";
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_DEV_RANDOM);
function encrypt($key, $text) {
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv)));
}
function decrypt($key, $text) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
}
$text = 12345;
echo "Plain Number : " . $text . "<br><br>";
$encrypted = encrypt($key, $text);
echo "AES Number : " . $encrypted . "<br><br>";
echo "Plain Number : ". decrypt($key, $encrypted) . "<br><br>";
this should work - but it returns the error:
blocksize in
blocksize in> Warning: mcrypt_encrypt()
[function.mcrypt-encrypt]: The IV
parameter must be as long as the
blocksize inblocksize in
blocksize in
When you decrypt you need to use the same IV as when you encrypted. It looks like you're generating a new, random IV during decryption.
It's OK to append or prepend the IV to the ciphertext. IVs are not secret but they should be unique for each encrypted message and only used once.
Your updated code has an issue with $iv being a global variable that's not available in the respective en-/decoding functions:
$key = "hello";
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_DEV_RANDOM);
function encrypt($key, $text, $iv) {
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv)));
}
function decrypt($key, $text, $iv) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
}
$text = 12345;
echo "Plain Number : " . $text . "<br><br>";
$encrypted = encrypt($key, $text, $iv);
echo "AES Number : " . $encrypted . "<br><br>";
echo "Plain Number : ". decrypt($key, $encrypted, $iv) . "<br><br>";
Or you can still rely on the global $iv by importing it into the local function scope:
function encrypt($key, $text) {
global $iv; // or use $GLOBALS['iv] instead of $iv in the call below
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv)));
}
function decrypt($key, $text) {
global $iv; // or use $GLOBALS['iv] instead of $iv in the call below
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
}
but this is surely not a recommended practice as it couples your code to global variables.
Did you change the mode when encrypting this text as well?
Also, when using MCRYPT_MODE_CBC, you need to use the same key and IV during encryption and decryption. Randomized IV does not work with CBC.

mcrypt_decrypt return strange code

I tried to encrypt an array then decrypt it back to string by calling a function, it's seem return the correct value if I does all encrypt and decrypt at once time in the function, however, if I return the encrypt value, then call the function again to decrypt it will return me some strange code.
Example 1:
public main()
{
$dataArray = array("one"=>1, "two"=>2, "three"=>3);
$a = $this->encryptDecryptInfo(json_encode($dataArray),$this->key);
var_dump($a);
}
public function encryptDecryptInfo($text,$key)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,
$text= base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CFB, $iv));
return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_CFB, $iv);
}
This will return me the correct value which is string(27) "{"one":1,"two":2,"three":3}"
Example 2:
public main()
{
$dataArray = array("one"=>1, "two"=>2, "three"=>3);
$a = $this->encryptDecryptInfo(json_encode($dataArray),$this->key,"encrypt");
$b = $this->encryptDecryptInfo($a,$this->key,"decrypt");
var_dump($b);
}
public function encryptDecryptInfo($text,$key,$type)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB), MCRYPT_RAND);
if($type == "encrypt")
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CFB, $iv));
else return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_CFB, $iv);
}
However if I do my code in this way, it will return me strange value which is like this string(27) "�ÔérôŸY éXgíœÈÐN*é౜CµÖ" .
Deos anyone know why this is happen? Both encrypt and decrypt coding are the same for example 1 and example 2, but why it will return strange code in example instead? Any way to fix this issue?
I think this is encoding issue look for UTF here - http://php.net/manual/en/function.base64-encode.php in the comments there is a UTF8 safe encoding function.
By passing the parameters left and right you are changing the encoding and you loose it in the translation. Welcome to PHP :)
You must use the same IV for decryption. Just save it along with encrypted data, for example:
if($type == "encrypt") {
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB), MCRYPT_RAND);
return base64_encode($iv . '##' .
mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CFB, $iv));
} else {
list($iv, $data) = explode('##', base64_decode($text));
return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CFB, $iv);
}
I had a similar issue. In the database I originally set it up for 16 characters. When I changed to encrypting, I forgot to change that number so the entire encrypted value was not stored. Once I corrected this it returned normal characters :)

Categories