Test of being false does not work with unserialize - php

I want to decrypt a string when submitting form after entering an input string to be decrypted :
static function decrypt($data) {
$key = 'AVtr34EN';
$td = mcrypt_module_open(MCRYPT_DES,"",MCRYPT_MODE_ECB,"");
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td,$key,$iv);
$data = mdecrypt_generic($td, base64_decode($data));
mcrypt_generic_deinit($td);
if (substr($data,0,1) != '!')
return false;
$data = substr($data,1,strlen($data)-1);
return unserialize($data);
}
When I call this function provided with an argument value of :
zeL1smxhfIEMWCews6vb1Y8yFa5tHbB3b489X0R3QtA=
then I get nothing !
I made a test if ( utils::decrypt($data_) === false ) but the program does not enter in the block of the if !
So how to treat this case ?

You give the string zeL1smxhfIEMWCews6vb1Y8yFa5tHbB3b489X0R3QtA= and using this andsandboxing the PHP it works exactly as expected:
static function decrypt($data) {
$key = 'AVtr34EN';
$td = mcrypt_module_open(MCRYPT_DES,"",MCRYPT_MODE_ECB,"");
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td,$key,$iv);
$data = mdecrypt_generic($td, base64_decode($data));
mcrypt_generic_deinit($td);
//$data = "!s:20:"2�Y:H���6|1|2|1|2|4";���"
if (substr($data,0,1) != '!')
return false;
// If will never be reached in this case,
// as data first character does equal "!"
$data = substr($data,1,strlen($data)-1);
return unserialize($data); //"2�Y:H���6|1|2|1|2|4"
}
Please clarify your question. changing the inpt string to "FDHFDHeh" (or whatever) correctly returns false showing the IF statement is fired.
NOTE:
You are using an input $data variable but then also generating a new $data variable in the function, this is bad practise to have two different things with the same name, and judging by comments this is causing me, if not you, confusion.
Also you can simplify the substr as simply $data = substr($data,1); as because you're starting at character 1, the string length with be strlen($data)-1.
Recommended you rewrite:
static function decrypt($data) {
$key = 'AVtr34EN';
$td = mcrypt_module_open(MCRYPT_DES,"",MCRYPT_MODE_ECB,"");
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td,$key,$iv);
$decryptData = mdecrypt_generic($td, base64_decode($data));
mcrypt_generic_deinit($td);
if (substr($decryptData,0,1) !== '!'){
//re: comments below:
//using !== makes it a strict type comparison
return false;
}
$outputData = substr($decryptData,1);
return unserialize($data);
}
It may also be worthwhile using the mb_string functions.
You can also rewrite the string comparison using arrays (as a string is an array of letters) so, replace if(substr(...)) with:
if ($decryptData[0] !== '!')
return false;
Which means "IF the first character of variable $decryptData is not "!" then return false.

Related

comparing identical strings returns false

I have 2 tables a merchant table and order table. each table has a secret key I use to compare to check security. Both are encrypted. I decrypt them to validate. The problem is after decryption I get the same string value but comparing them returns false. Here's the code
THIS ISSUE HAPPENS IF STRING HAS SPECIAL CHARACTERS AND DOESN'T HAPPEN IF STRING HAS LETTERS AND NUMBERS ONLY
public function merchant_encrypt($pure_string, $encryption_key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
return $encrypted_string;
}
public function merchant_decrypt($encrypted_string, $encryption_key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
return $decrypted_string;
}
public function replace_spechial_charater($value){
$value = str_replace('+=','plusequal',$value);
$value = str_replace('=','equalsign',$value);
$value = str_replace('+','plussign',$value);
$value = str_replace('/','slashsign',$value);
$value = str_replace('&','andsign',$value);
return $value;
}
public function restore_spechial_charater($value){
$value = str_replace('plusequal','+=',$value);
$value = str_replace('equalsign','=',$value);
$value = str_replace('plussign','+',$value);
$value = str_replace('slashsign','/',$value);
$value = str_replace('andsign','&',$value);
return $value;
}
public function strhex($string) {
$hexstr = unpack('H*', $string);
return array_shift($hexstr);
}
Saving the merchant key
$enc_key = $row['merchant_id'];
$merchant_key = trim($_POST['key']); //e.g: 1234abcd+=&$
$merchant_key = replace_spechial_charater($merchant_key);
$encrypted_key = merchant_encrypt($merchant_key ,$enc_key);
$encrypted_key = base64_encode($encrypted_key);
//save $encrypted_key in the merchant table
To decrypt it
$decrypted_key = base64_decode($row['key']);
$decrypted_key = decrypt($decrypted_key,$row['merchant_id']);
$decrypted_key = restore_spechial_charater($decrypted_key);
// the result is 2d1d54rt5h4th5rh5tr1h%$&^/+=gdgdfgd
The same non-encrypted key is encrypted in the merchant website but with another enc_key
$enc_key = $row['order_id'];
$merchant_key = $row['key']; // 1234abcd+=&$
$merchant_key = replace_spechial_charater($merchant_key);
$encrypted_key = merchant_encrypt($merchant_key ,$enc_key);
$encrypted_key = base64_encode($encrypted_key);
//send $encrypted_key with other parameters to the payment gateway then returned to the php script
$order_decrypted_key = base64_decode($row['order_id']);
$order_decrypted_key = decrypt($order_decrypted_key ,$row['order_id']);
$order_decrypted_key = restore_spechial_charater($order_decrypted_key );
// the result is 2d1d54rt5h4th5rh5tr1h%$&^/+=gdgdfgd
var_dump(strip_tags($decrypted_key));
var_dump(strip_tags($order_decrypted_key));
$result = strcasecmp( trim($decrypted_key), trim($order_decrypted_key) );
echo $result;
//var_dump(trim()) returns the same result for both values
The result is:
string(39) "2d1d54rt5h4th5rh5tr1h%$&^/+=gdgdfgd"
string(35) "2d1d54rt5h4th5rh5tr1h%$&^/+=gdgdfgd"
3
Then:
$order_key = strhex($order_decrypted_key);
$merchant_key = strhex($decrypted_key);
var_dump(trim($decrypted_key));
var_dump(trim($order_decrypted_key));
string(78)
"326431643534727435683474683572683574723168252426616d703b5e2f2b3d67646764666764"
string(70)
"3264316435347274356834746835726835747231682524265e2f2b3d67646764666764"
So how to fix this issue and check if they are equal or not
Your two strings aren't the same, as everyone gathered. And there is no mystery padding I'm afraid.
Your longer string is 2d1d54rt5h4th5rh5tr1h%$&^/+=gdgdfgd
(notice the htmlentity in the middle, accounting for the 4 extra characters).
(Found by running the following on your unpacked data):
$string = "326431643534727435683474683572683574723168252426616d703b5e2f2b3d67646764666764";
$packed = pack("H*", $string);
var_dump($packed);
Response:
string(39) "2d1d54rt5h4th5rh5tr1h%$&^/+=gdgdfgd"
I can only guess that you are printing your comparison on the web instead than on the terminal, and that you are presenting the result as rendered by the browser (and not the actual result), hence not seeing those extra four characters.
Before saving your data you should probably run something to decode the html entities in your input. Or you could do it before comparing, but much better to save the data properly.
$decrypted_key = htmlspecialchars_decode($decrypted_key);
$order_decrypted_key = htmlspecialchars_decode($order_decrypted_key);

Why does file encryption using mcrypt fail?

I have an issue using mcrypt to encrypt a file on filesystem to e.g. store it into Mysql database. I have reduced the issue to the following lines of code:
<?php
$key = vzc_generateKey();
$file_content = file_get_contents("test.pdf"); // Fails
$file_content = file_get_contents("test2.docx"); // Fails
//$file_content = "12323"; // Works great
$hash_start = md5($file_content);
$encrypt = vzc_encryptV3($file_content, $key);
$decrypt = vzc_decryptV3($encrypt, $key);
$hash_end = md5($decrypt);
echo ($hash_end == $hash_start)."##";
function vzc_generateKey()
{
$cstrong = false;
while ($cstrong == false)
{
$bytes = openssl_random_pseudo_bytes(16, $cstrong);
}
return bin2hex($bytes);
}
function vzc_decryptV3($crypt,$key) {
$content = base64_decode($crypt['crypt']);
$iv = $crypt['iv'];
$rijndael = 'rijndael-256';
$cp = mcrypt_module_open($rijndael, '', 'ofb', '');
$ks = mcrypt_enc_get_key_size($cp);
$key = substr(md5($key), 0, $ks);
mcrypt_generic_init($cp, $key, $iv);
$decrypted = mdecrypt_generic($cp, $content);
mcrypt_generic_deinit($cp);
mcrypt_module_close($cp);
return trim(base64_decode($decrypted));
}
function vzc_encryptV3($file_content,$key) {
$content = base64_encode($file_content);
$rijndael = 'rijndael-256';
$cp = mcrypt_module_open($rijndael, '', 'ofb', '');
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($cp), MCRYPT_RAND);
else
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($cp), MCRYPT_DEV_RANDOM);
$ks = mcrypt_enc_get_key_size($cp);
$key = substr(md5($key), 0, $ks);
mcrypt_generic_init($cp, $key, $iv);
$encrypted = mcrypt_generic($cp, $content);
$returnvalue = array("crypt"=>trim(base64_encode($encrypted)), "iv"=>$iv);
mcrypt_generic_deinit($cp);
mcrypt_module_close($cp);
return $returnvalue;
}
?>
Using the String "12323" everything works fine, both Hashes do equal. But those two test files (one pdf and one docx) fail. It seems that the decryption returns different values then the origin data.
What can I do to solve this issue?
Thank you very much in advance for any tip you can provide.
It is probably the fact that the files are not exactly n * blocksize long. This leads the algorithm to pad the end of the file with '\0' and this changes the content of the file when you do the md5 calculation.
One way around this is to strip the padding off of the last block, if you can reliably find the end of the file.

How to encrypt and decrypt data in php?

How to encrypt and decrypt data in php?
My code so far is:-
function encrypter($plaintext)
{
$plaintext = strtolower($plaintext);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256,FLENCKEY,$plaintext,MCRYPT_MODE_ECB);
return trim(base64_encode($crypttext));
}
function decrypter($crypttext)
{
$crypttext = base64_decode($crypttext);
$plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256,FLENCKEY,$crypttext,MCRYPT_MODE_ECB);
return trim($crypttext);
}
$test = "abc#gmail.com";
echo encrypter(test);
Output is
iLmUJHKPjPmA9vY0jfQ51qGpLPWC/5bTYWFDOj7Hr08=
echo decrypter(test);
Output is
��-
In your decrypter() function, you return the wrong data.
You should return $plaintext instead of $crypttext:
function decrypter($crypttext)
{
$crypttext = base64_decode($crypttext);
$plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256,FLENCKEY,$crypttext,MCRYPT_MODE_ECB);
//return trim($crypttext);
return trim($plaintext);
}
The other code samples on this page (including the question) are not secure.
To be secure:
Don't use mcrypt.
Use authenticated encryption.
Never use ECB mode (a.k.a. MCRYPT_MODE_ECB).
See this answer for secure encryption in PHP.
This is what I use. Super simple.
function encrypt_decrypt($action, $string) {
$output = false;
$key = '$b#bl2I#?%%4K*mC6r273~8l3|6#>D';
$iv = md5(md5($key));
if( $action == 'encrypt' ) {
$output = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, $iv);
$output = base64_encode($output);
}
else if( $action == 'decrypt' ){
$output = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($string), MCRYPT_MODE_CBC, $iv);
$output = rtrim($output, "");
}
return $output;
}
You can change $key to whatever you want, or leave it. (this is not my key, btw)
encrypt_decrypt('encrypt', $str) to encrypt
encrypt_decrypt('decrypt', $str) to decrypt
Inside the decrypter function, change the
return trim($crypttext);
to
return trim($plaintext);
But looking at your function, I am not quite sure whether it will return exactly the same string, because of the strtolower function. You can't just do a strtoupper function as the original text may not be all in capital letters.
Warning
mcrypt_encrypt has been DEPRECATED as of PHP 7.1.0. Relying on this function is highly discouraged.
Use openssl_encrypt instead.

mcrypt not decrypting to same length

I am trying to mcrypt some data using a class I created (methods below). This is how you mcrypt data then using pack, then you can use unpack to get the data back.
$packed = $server->cache->pack("packed", array(123,123,123), "Password");
if(!$packed){
echo "Could not encrypt data\n";
}
$server->cache->unpack("packed", "Password");
when I pack it, I do a var_dump on the json_encode() data, and get this:
string(13) "[123,123,123]"
When I unpack it, I do a var_dump on the mcrypt_decode() string, and get this:
string(32) "[123,123,123]"
Why are the lengths different? When I do a json_decode() on the mcrypt_decode() string, I get null back, and this is the reason. If I trim the data it works, but I shouldn't have to trim it.
Here are the methods:
<?php
public function put($key, $value, $life = 0)
{
$this->cache[$key] = $value;
$life = (int)$life;
if($life > 0)
{
$life = strtotime("now + $life seconds");
}
$this->life[$key] = $life;
}
public function get($key)
{
return $this->cache[$key];
}
public function pack($key, $value, $secret, $life = 0)
{
if(!function_exists("mcrypt_encrypt"))
{
$this->put($key, $value, $life);
return false;
}
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$value = json_encode($value);
var_dump($value);
$cryptdata = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $secret, $value, MCRYPT_MODE_ECB, $iv);
$this->put($key, $cryptdata, $life);
return true;
}
public function unpack($key, $secret)
{
if(!function_exists("mcrypt_decrypt"))
{
return json_decode($this->get($key), true);
}
$cryptdata = $this->get($key);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $secret, $cryptdata, MCRYPT_MODE_ECB, $iv);
//$data = json_decode($data, true);
var_dump($data);
}
When using a block cipher mode like ECB (you shouldn't be using that one btw), MCrypt will NUL-pad the data, so that its length is dividable by the encryption algorithm's block size.
If you must know, for Rijndael-256 the block size is 256 bits or 32 bytes.
Considering that you're encrypting JSON data, you can just rtrim() the data and not worry about it. There's no way around that unless you switch to a counter mode like CTR.

PHP mycrypt problem, weird characters/warnings

I have no idea what I'm doing wrong. I just need to be able to encrypt and decrypt without getting weird characters or warnings. It says I'm supposed to be using an IV of length 16 and that I'm using a length of 9 but "0123456789abcdef" is 16 characters.
Warning: mcrypt_generic_init() [function.mcrypt-generic-init]: Iv size incorrect; supplied length: 9, needed: 16 in /home/mcondiff/public_html/projects/enc/enc.php on line 10
See http://www.teamconcept.org/projects/enc/enc.php
I'm lost, confused, a little lightheaded. Here do I go from here? I have to use this encryption and get it working for a project.
<?php
class enc
{
function encrypt($str, $key) {
$key = $this->hex2bin($key);
$td = mcrypt_module_open("rijndael-128", "", "cbc", "fedcba9876543210");
mcrypt_generic_init($td, $key, CIPHER_IV);
$encrypted = mcrypt_generic($td, $str);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return bin2hex($encrypted);
}
function decrypt($code, $key) {
$key = $this->hex2bin($key);
$code = $this->hex2bin($code);
$td = mcrypt_module_open("rijndael-128", "", "cbc", "fedcba9876543210");
mcrypt_generic_init($td, $key, CIPHER_IV);
$decrypted = mdecrypt_generic($td, $code);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return utf8_encode(trim($decrypted));
}
function hex2bin($hexdata) {
$bindata = "";
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
}
$theEncryption = new enc();
$user = "John Doe";
$email = "john#example.com";
$user = $theEncryption->encrypt($user, "0123456789abcdef");
$email = $theEncryption->encrypt($email, "0123456789abcdef");
echo 'User: '.$user;
echo 'Email: '.$email;
?>
Can somone point me in the right direction or point out what i'm doing wrong?
Thanks
Mike
CIPHER_IV is probably an undefined constant. PHP raises a "Use of undefined constant" notice and then uses the "constant" as string. The string "CIPHER_IV" is 9 characters long.
In your php file, do a print of CIPHER_IV and see what it contains.
See http://us2.php.net/mcrypt_generic_init for the specifics
You've probably copy-pasted the code from a blog: googling mcrypt_generic_init CIPHER_IV only gives this post and a blog ;)
The IV is a parameter that you need to specify to the function, not a constant that the first blogger put in misinterpreting the second blogger's article.
At http://propaso.com/blog/?cat=6, they declare these:
$secret_key = "01234567890abcde";
$iv = "fedcba9876543210";
and then do:
mcrypt_generic_init($td, $secret_key, $iv);
Simply declare your IV to be something, then use it.

Categories