Decrypting with different IV - php

I've found a pair of encryption and decryption functions that look like they obey all the rules of data security that I'm desperate to fully understand but probably won't be able to without a doctorate in this stuff.
They work great when I'm encrypting and decrypting something on the same page with the same IV.
But when I try saving the results to an SQL database and then pulling them back out again and decrypting, it doesn't work.
$key = "secretsecret";
$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 = "the text to encrypt";
echo "Plain Text: " . $text . "<br><br>";
$encrypted = encrypt($key, $text, $iv);
echo "Encrypted Text: " . $encrypted . "<br><br>";
echo "Decrypted Text: ". decrypt($key, $encrypted, $iv) . "<br><br>"; //this works fine
//save encrypted text to SQL
mysql_query("UPDATE table SET test='".addslashes($encrypted)."' WHERE id='1'");
Then if on another page view I pull the text back out and try to:
echo "Decrypted Text: ". decrypt($key, $textFromSQL, $iv) . "<br><br>";
I get gibberish. What do I need to do to get the text decrypted properly with a different IV?

You need to use the same Initialization Vector (IV) in the decryption as you do in the enryption. This means you need to store the IV in the database.
The IV doesn't need to be secret, unlike the key.
Something like this:
mysql_query("UPDATE table SET test='".addslashes($encrypted)."', IV='".addslashes($IV)."' WHERE id='1'");
Then when you decrypt the data use the stored IV.

Related

PHP aes-128-gcm openssl_decrypt only works after using openssl_encrypt

I have to decrypt aes-128-gcm encrypted data I get from an external party. Since openssl_decrypt never returned any data, I tried to encrypt the elsewhere decrypted data myself, to see if that works and in fact I receive the same encrypted data I try to decrypt. Therefore I know, all my parameters are correct. So I played around with my PHP code and come to the strange conclusion, that decrypting the data only works for me, after I encrypt the plaintext?!?
Does anybody have any idea what's going on here?
thanks,
Harry
<?php
$method='aes-128-gcm';
$key = hex2bin('0748BEF58E04D5917ED0B9B558628265');
//echo "iv_length: ". openssl_cipher_iv_length($method)."<br>";
$iv = hex2bin('534D5367700114E600102D29');
$tag = NULL;
$enc = hex2bin('09E89C959CD513057787832142E6796E1F6DE55CBA8E5CEC6E16AA635B3B102DDB22D85841923DDC2EE3052027945DFD00D025A0A5D0EB385E0033DD28037D80B47522B3DB310B01871474686B609D2DA15864785895DF2BE887');
$plain = hex2bin('0F00102D280C07E4081F01103B1000FF8880020C09060006190900FF090D323232313230323031323735360904103B1000090507E4081F0106004C48DF06000000CB06000089CF06000E61E7060000020A060000000009000900');
$decrypted = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
$encrypted = openssl_encrypt($plain, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
$decrypted2 = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
echo "plain: ".bin2hex($plain)."<br>";
echo "enc: ".bin2hex($encrypted)."<br>";
echo "dec: ".bin2hex($decrypted)."<br>";
echo "dec2: ".bin2hex($decrypted2)."\n";
while ($msg = openssl_error_string())
echo $msg . "<br>\n";
?>
OUTPUT:
plain:
0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900
enc:
09e89c959cd513057787832142e6796e1f6de55cba8e5cec6e16aa635b3b102ddb22d85841923ddc2ee3052027945dfd00d025a0a5d0eb385e0033dd28037d80b47522b3db310b01871474686b609d2da15864785895df2be887
dec:
dec2:
0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900
Welcome to Stackoverflow. You are using the AES algorithm in mode GCM and that means that the ciphertext is secured against modification with an "authentication tag" or short "tag". This tag is generated when encrypting a plaintext with AES-GCM and needs to be available when decrypting the ciphertext.
In your code you provide an empty $tag-variable to the decrypt-function and the decryption fails. When generating a "new" plaintext with openssl_encrypt your $tag-variable gets filled with a tag. Now you are decrypting again and provide this tag to the openssl_decrypt-function and the decryption works like expected.
So you need to get the value of the $tag from the third party to successfully decrypt the ciphertext back to plaintext.
Using this small change in the sourcecode the program provides the $tag:
$decrypted = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
echo "tag: ".bin2hex($tag)."<br>" . PHP_EOL;
$encrypted = openssl_encrypt($plain, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
echo "tag: ".bin2hex($tag)."<br>" . PHP_EOL;
$decrypted2 = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
result:
tag: <br>
tag: 9268f3568512fc9f15075096c1b47902<br>
Edit with solution
According to this answer of #Maarten Bodewes (https://stackoverflow.com/a/49244840/8166854) there is a chance of decypting "aes gcm"
encrypted data without a authentication tag because
AES GCM = AES CTR + AuthTag
Changing your source code as below decrypts the password as expected in the first run, I added manually the hex-data '00000002' to the iv:
plain: 0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900<br>
enc: 09e89c959cd513057787832142e6796e1f6de55cba8e5cec6e16aa635b3b102ddb22d85841923ddc2ee3052027945dfd00d025a0a5d0eb385e0033dd28037d80b47522b3db310b01871474686b609d2da15864785895df2be887<br>
decCtr: 0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900<br>
decGcm: 0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900
code:
<?php
$method='aes-128-gcm';
$key = hex2bin('0748BEF58E04D5917ED0B9B558628265');
$iv = hex2bin('534D5367700114E600102D29');
$tag = NULL;
$enc = hex2bin('09E89C959CD513057787832142E6796E1F6DE55CBA8E5CEC6E16AA635B3B102DDB22D85841923DDC2EE3052027945DFD00D025A0A5D0EB385E0033DD28037D80B47522B3DB310B01871474686B609D2DA15864785895DF2BE887');
$plain = hex2bin('0F00102D280C07E4081F01103B1000FF8880020C09060006190900FF090D323232313230323031323735360904103B1000090507E4081F0106004C48DF06000000CB06000089CF06000E61E7060000020A060000000009000900');
//$decrypted = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
$methodCtr = 'aes-128-ctr';
$ivCtr = hex2bin('534D5367700114E600102D2900000002');
$decryptedCtr = openssl_decrypt($enc, $methodCtr, $key, OPENSSL_RAW_DATA, $ivCtr);
$encrypted = openssl_encrypt($plain, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
echo "tag: ".bin2hex($tag)."<br>" . PHP_EOL;
$decryptedGcm = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
echo "plain: ".bin2hex($plain)."<br>" . PHP_EOL;
echo "enc: ".bin2hex($encrypted)."<br>" . PHP_EOL;
echo "decCtr: ".bin2hex($decryptedCtr)."<br>" . PHP_EOL;
echo "decGcm: ".bin2hex($decryptedGcm)."\n" . PHP_EOL;
while ($msg = openssl_error_string())
echo $msg . "<br>\n";
?>

encrypt and decrypt with diacrits

I have these code for encrypt and decrypt.
It works good for text (for example: "This is a text"), which is withnout diacritics (that means without : ěščřžýáíéúů).
But I need encrypt and decrypt text with this special letters (with : ěščřžýáíéúů).
Can somebody help me, please?
Thank so much for every answer and help.
Have a nice day. M.
define ("ENCRYPTION_KEY", "QaY7e4d1c");
$string= "This is a text"; // -> this work alright
//$string= "áýžřčšě"; I NEED THIS TEXT ENCRYPT AND DECRTYPT
echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);
function 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;
}
function 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;
}
You're calling utf8_encode in your encryption function, but not calling utf8_decode when you decrypt, so your functions as they stand don't complement each other.
I'd recommend removing the call to utf8_encode entirely. mcrypt_encrypt doesn't care what encoding your string uses, so whatever you pass in will be what you get back out. Your script works fine for me if I remove it:
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, $pure_string, MCRYPT_MODE_ECB, $iv);
I'd also suggest reading this: https://paragonie.com/blog/2015/05/if-you-re-typing-word-mcrypt-into-your-code-you-re-doing-it-wrong

PHP: obfuscate PHP output?

I'm trying to find out if there is a way to obfuscate the PHP output (html stuff).
basically, I have a few hidden inputs and they have some PHP outputs in them...
Example:
<input type="hidden" name="myinput" value="<?php echo $variable; ?>" />
is there any way to obfuscate its value in the users browser but still readable server side so I can pass the input value between pages?
any suggestion and help would be appreciated.
EDIT:
I did it like this:
$string = "my string to be be encrypted goes here";
$secret_key = "This is my secret key";
// Create the initialization vector for added security.
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
// Encrypt $string
$encrypted_string = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $secret_key, $string, MCRYPT_MODE_CBC, $iv);
// Decrypt $string
$decrypted_string = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $secret_key, $encrypted_string, MCRYPT_MODE_CBC, $iv);
echo "Original string : " . $string . "<br />\n";
echo "Encrypted string : " . $encrypted_string . "<br />\n";
echo "Decrypted string : " . $decrypted_string . "<br />\n";
Instead of returning the values as part of the form field; do not send them data at all! Save the data to a database table and link to the current user. Link the data with the user via any number of methods (User id, cookie, session, etc). when the form is submitted retrieve the secret and execute your business logic.
Side note: If you want the data to be secure you want to encrypt it, not hash, not encode; encrypt.

How to pass query string variable (like id, name, etc..) with url in safe way?

I just want to pass some query string variables with URL like below. But in this way anyone can see the passing variables. I can use base64_encode() and base64_decode() methods but these are also not secure. Because anyone can reverse it. Please help me if anyone have the best solution.
header('Location: http://www.example.com?id='.$id);
or
header('Location: http://www.example.com?name='.$name);
I think this is the best and secure solution for this..
<?php
/*
* PHP mcrypt - Basic encryption and decryption of a string
*/
$string = "Some text to be encrypted";
$secret_key = "This is my secret key";
// Create the initialization vector for added security.
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
// Encrypt $string
$encrypted_string = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $secret_key, $string, MCRYPT_MODE_CBC, $iv);
// Decrypt $string
$decrypted_string = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $secret_key, $encrypted_string, MCRYPT_MODE_CBC, $iv);
echo "Original string : " . $string . "<br />\n";
echo "Encrypted string : " . $encrypted_string . "<br />\n";
echo "Decrypted string : " . $decrypted_string . "<br />\n";
?>
Output will be like below:
Original string : Some text to be encrypted
Encrypted string : –LÁ`b]!üƒN{Iç&|«kÿÅLèëÉ°Xp
Decrypted string : Some text to be encrypted

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 .

Categories