comparing identical strings returns false

520 Views Asked by At

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

1

There are 1 best solutions below

0
On BEST ANSWER

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