I have been trying to implement mcrypt encryption/ decryption technique on both server end, PHP and client end. I am trying to use mcrypt.js
library at the moment as:
<?php
$key = 'testtesttesttesttesttesttesttest';
function string_encrypt($string, $key) {
$crypted_text = mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$key,
$string,
MCRYPT_MODE_ECB
);
return base64_encode($crypted_text);
}
function string_decrypt($encrypted_string, $key) {
$decrypted_text = mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$key,
base64_decode($encrypted_string),
MCRYPT_MODE_ECB
);
return trim($decrypted_text);
}
echo 'Provided Text: '.$test_str = 'This is test message.';
echo '<br />';
echo 'Encyrpted Value: '.$enc_str = string_encrypt($test_str, $key);
echo '<br />';
echo 'Decrypted Value: '.string_decrypt($enc_str, $key);
echo '<br />';
?>
<script src='rijndael.js'></script>
<script src='mcrypt.js'></script>
<script src='base64v1_0.js'></script>
<script lang='javascript'>
var enc_str = mcrypt.Encrypt('<?php echo $test_str ?>','');
enc_str = B64.encode(enc_str);
alert(enc_str);
// I don't get this same as encypted PHP text. i.e. $enc_str
var dec_str = B64.decode('<?php echo $enc_str ?>');
alert(mcrypt.Decrypt(dec_str,''));
// I don't get this same as decypted PHP text.
// i.e. string_decrypt($enc_str)
</script>
I have used these following private vars at the mcrypt.js library.
var cMode='ecb';
var cCipher='rijndael-256';
var cKey='testtesttesttesttesttesttesttest';
//I am providing the same key
As I commented above, why is it enc_str
not equal as $enc_str
and why is it mcrypt.Decrypt('<?php echo $enc_str ?>', '')
not equal as string_decrypt($enc_str, $key)
?
Updated question:
I tried both base64 encode/ decode and even hex2bin/ bin2hex to parse those strings but these two produced following results:
Using Hex2bin/ Bin2hex
PHP result:
Provided Text: This is test message.
Encyrpted Value: a51e970427ec8f666a5684cc1712ad03b29889cc10f4ccbf55733564d11c0386
Decrypted Value: This is test message.
JS result:
Provided Text:This is test message.
Mcrypted value:¥'ìfjV̲ÌôÌ¿Us5dÑ
Encyrpted Value:a51e970427ec8f666a5684cc1712ad03b29889cc10f4ccbf55733564d11c0386
After Hex to Bin Text:¥'ìfjV̲ÌôÌ¿Us5dÑ
Decrypted Value:This is test message.�����������
/*These diamond with question mark is produced while decypting the value.*/
Using Base64 encode/ decode:
PHP result:
Provided Text: This is test message.
Mcrypt encrypted value : ¥—'ìfjV„̲˜‰ÌôÌ¿Us5dц
/*
Here mcrypted value provided by JS and PHP is different
That is causing to produce different value at two ends
*/
Encyrpted Value: pR6XBCfsj2ZqVoTMFxKtA7KYicwQ9My/VXM1ZNEcA4Y=
Decrypted Value: This is test message.
JS result:
Provided Text:This is test message.
Mcrypted value:¥'ìfjV̲ÌôÌ¿Us5dÑ
Encyrpted Value:wqUewpcEJ8Oswo9malbChMOMFxLCrQPCssKYwonDjBDDtMOMwr9VczVkw5EcA8KG
After Base64 Decode:¥'ìfjV̲ÌôÌ¿Us5dÑ���
Decrypted Value:This is test message.�����������bFaêF«+JéÓ!ÆÖ
And on both cases, UTf-8 content can not be decrypted on JS end.
*Links: *
The main issue appears to be that your
string_encrypt
andstring_decrypt
PHP functions don't have access to the$key
variable, so for the encryption keymcrypt_encrypt
is using\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
. See this question for an explanation. PHP should report a notice thatkey
is undefined, have you turned off error reporting perhaps? Echo the key from inside the encrypt function to confirm this.Another issue is a bug in the Mcrypt JS library. This library pads the encryption key with
\0
if the key length is less than 32 bytes, the problem is that this is not how the PHPmcrypt_encrypt
function pads the key. Themcrypt_encrypt
function pads the key up to the nearest valid key length (16, 24, or 32 bytes). The issue in mcrypt.js is at lines 63 and 64, change this:to this:
Now we can confirm the fix...
PHP:
Javascript:
Finally, all of these encryption functions produce binary as their output. Binary cannot be written as plain text in most cases without damaging the data. To solve this, either encode the binary to Hex or Base64 and then decode it before trying to decrypt.
So to get everything working...
A few more notes...
trim
the output of thestring_encrypt
function. This will cause leading or trailing zeros to be removed, which will make it so that you cannot decrypt the output.Update:
Your Base64 encoding issue occurs because the library you're using doesn't work with binary data. This is a fairly common issue for Base64 javascript libraries. I'd recommend using this library instead.
As for the trailing
�
characters when decrypting with javascript, you need to trim the decrypted output. You're doing this in your PHPstring_decrypt
method, but not in your javascript. You can trim the decrypted output by doing a regex replace on all\0
characters at the end of the string.Example:
I should have included this in my original post, but I didn't notice the
\0
characters in the output because FF's alert box doesn't display them. Sorry about that.Finally, I noticed another bug in the Mcrypt JS library. Lines 41 to 47:
Notice the comma at the end of the "twofish" line. Firefox and Chrome don't seem to mind this, but IE8 will report an error and fail to load the mcrypt library because of it. To fix the issue change:
to: