PHP JSON Decode erroring with valid JSON - php

I am trying to decode a simple JSON string and the format to make it look correct. I actually copied the string and decode is with the same algorithm but without all the extra code and it worked fine.
print_r(json_decode('{"user_id":1,"issused":"2016-02-24 04:40:17","expire":"2016-03-02 04:40:17"}'));
That worked. But when I do
$hash = Hash::salt(32);
$issused = date('Y-m-d H:i:s');
$expire = date('Y-m-d H:i:s', strtotime('+1 week'));
$data = array('user_id' => 1, 'issused' => $issused, 'expire' => $expire);
$encrypt = Cipher::encrypt(json_encode($data), $hash);
$decrypt = Cipher::decrypt($encrypt, $hash);
echo $encrypt;
echo "<br><br>";
echo $decrypt;
echo "<br><br>";
print_r(json_decode($decrypt));
Where $decrypted is the valid formated JSON that I posted above. When I used:
echo json_last_erro();
It gave me an output of 3 which is JSON_ERROR_CTRL_CHAR
Any idea why this isn't being decoded correctly?
EDIT
Here is how I am encrypting data.
class Cipher {
public static function encrypt($string, $hash) {
$size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($size, MCRYPT_RAND);
$encrypted = mcrypt_encrypt(MCRYPT_BLOWFISH, $hash, utf8_encode($string), MCRYPT_MODE_ECB, $iv);
//$encoded = urlencode($encrypted);
$encoded = base64_encode($encrypted);
return $encoded;
}
public static function decrypt($string, $hash) {
//$decoded = urldecode($string);
$decoded = base64_decode($string);
$size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($size, MCRYPT_RAND);
$decrypted = mcrypt_decrypt(MCRYPT_BLOWFISH, $hash, $decoded, MCRYPT_MODE_ECB, $iv);
return $decrypted;
}
}
Here how I am creating the salt.
public static function salt($length) {
return mcrypt_create_iv($length); //base64_encode(openssl_random_pseudo_bytes($length));
}

The extra control characters (\0) are due to the cypher block padding. From the mcrypt_decrypt docs
data
The data that will be decrypted with the given cipher and mode. If
the size of the data is not n * blocksize, the data will be padded
with '\0'.
You can pad the input for the block size yourself in the encrypt and then remove the extra padding in decrypt() or you can trim the trailing zero bytes from the decoded message doing the below.
$decrypt = trim($decrypt, "\0");

Related

Same result for openssl_encrypt and mcrypt_encrypt (MCRYPT_CAST_128)

I have old PHP project where used mcrypt_encrypt
But this function doesn't work in new PHP.
I try to convert it to php7+, use openssl_encrypt, but I got no same result, what I do wrong?
Maybe do you know other way to get same result?
mcrypt_encrypt function:
public static function cryptToCode($data)
{
$iv_size = #mcrypt_get_iv_size(MCRYPT_CAST_128, MCRYPT_MODE_ECB);
$iv = #mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM );
$code = #mcrypt_encrypt(MCRYPT_CAST_128, self::KEY_TRANSLATE_ID, $data, MCRYPT_MODE_ECB, $iv);
$code = bin2hex($code);
return $code;
}
openssl_encrypt function:
public static function cryptToCodeSSL($data, $key = self::KEY_TRANSLATE_ID, $method = "cast-128-ecb") //"cast-128-ecb"
{
$iv_size = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_size);
$code = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
$code = bin2hex($code);
return $code;
}
Done:
I found library http://www.gilfether.com/phpcrypt/
I got same result.

Im trying encrypt some text using a fucntion in php

I found a tutorial online on how to encrypt strings in php but when I call the function and try echo the processed data I'm getting 500 internal error. Here is my code below.
<?php
$iv_to_pass_to_decryption = 'mysecretpass';
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, $iv)
{
$text = base64_decode($text);
$iv = base64_decode($iv);
return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);
}
$txt = "hello";
$mykey = "mysecretkey";
$somedata = encrypt($txt, $mykey);
echo $somedata;
?>
The first problem is, you missed a ) in line 8.
The second problem is mcrypt_decrypt()function is deprecated.
The third problem is mcrypt_encrypt(): Key of size 11 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported. The 'mysecretkey' key is wrong.
I can recommend use the crypt() function: http://php.net/manual/en/function.crypt.php
When validating passwords, a string comparison function that isn't
vulnerable to timing attacks should be used to compare the output of
crypt() to the previously known hash. PHP 5.6 onwards provides
hash_equals() for this purpose.
use below code hope it will help you
$iv_to_pass_to_decryption = 'mysecretpass';
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, $iv)
{
$text = base64_decode($text);
$iv = base64_decode($iv);
return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);
}
$txt = "hello";
$mykey = "mysecretkey12345";
$somedata = encrypt($txt, $mykey);
echo $somedata;

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

Encryption/Decryption results in replacement and incorrect characters at start of string

Here are my encrypt and decrypt functions
public function encrypt($text){
$key = hash("md5", KEY);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_TWOFISH, MCRYPT_MODE_CBC), MCRYPT_RAND);
$result = base64_encode(mcrypt_encrypt(MCRYPT_TWOFISH, $key, $text, MCRYPT_MODE_CBC, $iv));
return $result;
}
public function decrypt($text){
$key = hash("md5", KEY);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_TWOFISH, MCRYPT_MODE_CBC), MCRYPT_RAND);
$result = trim(mcrypt_decrypt(MCRYPT_TWOFISH, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
return $result;
}
When encryption is run on a JSON string to be stored as a text file and then retrieved and decrypted the front section of the resulting string has replacement and/or incorrect characters:
Expected:
{"players":[{"label":"...
Actual:
�Ӹ�!G#${�W�Rՙ�bel":"...
If it makes any difference the actual placement/incorrect chars are different each time I refresh the page on the same file.
In case anyone comes across this...
The IV needs to be prepended to the file before encoding, like so:
public function encrypt($text){
$key = hash("md5", KEY);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_TWOFISH, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
$result = base64_encode($iv.mcrypt_encrypt(MCRYPT_TWOFISH, $key, $text, MCRYPT_MODE_CBC, $iv));
return $result;
}
Then when decrypting take the IV from the decoded string and use it to decrypt, like so:
public function decrypt($text){
$key = hash("md5", KEY);
$decode = base64_decode($text);
$iv = substr($decode, 0, 16);
$decrypt = substr($decode, 16);
$result = mcrypt_decrypt(MCRYPT_TWOFISH, $key, $decrypt, MCRYPT_MODE_CBC, $iv);
return $result;
}

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.

Categories