Mcrypt js加密值不同于PHP生成的mcrypt / Mcrypt JS解密对于UTF-8字符不起作用 [英] Mcrypt js encryption value is different than that produced by PHP mcrypt / Mcrypt JS decrypt doesn't work for UTF-8 chars

查看:186
本文介绍了Mcrypt js加密值不同于PHP生成的mcrypt / Mcrypt JS解密对于UTF-8字符不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试在服务器端,PHP和客户端上实现mcrypt加密/解密技术。我现在试图使用 mcrypt.js 库:

 <?php 
$ key ='testtesttesttesttesttesttesttest';

函数string_encrypt($ string,$ key){
$ crypted_text = mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$ key,
$ string,
MCRYPT_MODE_ECB
);
return base64_encode($ crypted_text);
}

函数string_decrypt($ encrypted_string,$ key){
$ decryptpted_text = mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$ key,
base64_decode ($ encrypted_string),
MCRYPT_MODE_ECB
);
return trim($ decryptpted_text);
}

echo'提供的文本:'。$ test_str ='这是测试消息。
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);
//我没有得到与被剔除的PHP文本相同的内容。即$ enc_str
var dec_str = B64.decode('<?php echo $ enc_str?');
alert(mcrypt.Decrypt(dec_str,''));
//我不会这样被解密的PHP文本。
//即string_decrypt($ enc_str)
< / script>

我在mcrypt.js库中使用了以下私有变量。

  var cMode ='ecb'; 
var cCipher ='rijndael-256';
var cKey ='testtesttesttesttesttesttesttest';
//我提供相同的键

如上所述, code> enc_str 不等于 $ enc_str ,为什么它 mcrypt.Decrypt('<?php echo $ enc_str?>','')不等于 string_decrypt($ enc_str,$ key)









更新的问题:



我尝试过base64编码/解码,甚至hex2bin / bin2hex来解析这些字符串,但是这两个字符串产生了以下结果:






使用Hex2bin / Bin2hex



PHP结果:

 提供的文本:这是测试消息。 
加密值:a51e970427ec8f666a5684cc1712ad03b29889cc10f4ccbf55733564d11c0386
解密值:这是测试消息。

JS结果:

 提供的文本:这是测试消息。 
微软的价值:¥'ìfjV̲Ìôμ$5dÑ
获取价值:a51e970427ec8f666a5684cc1712ad03b29889cc10f4ccbf55733564d11c0386
Hex到Bin文本后:¥'ìfjV̲Ìô¿Us5dÑ
解密值:这是测试消息。
/ *这些带有问号的钻石产生同时解除价值。* /






使用Base64编码/解码:



结果:

 提供的文本:这是测试消息。 
Mcrypt加密值:¥-'ìfjV̲‰ÌÌ¿†††
/ *
这里由JS和PHP提供的加密值是不同的
这导致产生不同的两端的价值
* /
Encyrpted值:pR6XBCfsj2ZqVoTMFxKtA7KYicwQ9My / VXM1ZNEcA4Y =
解密值:这是测试消息。

JS结果:

 提供的文本:这是测试消息。 
微软的价值:¥'ìfjV̲Ìô¿Us5dÑ
带宽值:wqUewpcEJ8Oswo9malbChMOMFxLCrQPCssKYwonDjBDDtMOMwr9VczVkw5EcA8KG
Base64解码后:¥'ìfjV̲Ìô¿Us5dÑ
解密值:这是测试消息。 bFaêF«+JéÓ!ÆÖ

在这两种情况下,UTf -8内容无法解密JS端。






*链接:*



Mcrypt JS库



Base64 JS库

解决方案

主要问题似乎是您的 string_encrypt string_decrypt PHP函数无法访问 $ key 变量,因此对于加密密钥 mcrypt_encrypt 正在使用 \0\0\0\0\0\0\0\0 \\0\0\0\0\0\0\0\0 。有关说明,请参阅此问题。 PHP应该报告一个通知,即 key 未定义,您是否已关闭错误报告?从加密函数内回收密钥以确认。



另一个问题是Mcrypt JS库中的错误。如果密钥长度小于32字节,则此库将加密密钥加载 \0 ,问题是这个不是 mcrypt_encrypt 功能按键。 mcrypt_encrypt 功能将键锁定到最接近的有效密钥长度(16,24或32字节)。 mcrypt.js中的问题是第63和64行,更改如下:

  if(key.length< 32)
key + = Array(33-key.length).join(String.fromCharCode(0));

到:

  if(key.length< 16)
key + = Array(17-key.length).join(String.fromCharCode(0));
else if(key.length< 24&& key.length> 16)
key + = Array(25-key.length).join(String.fromCharCode(0));
else if(key.length< 32&& key.length> 24)
key + = Array(33-key.length).join(String.fromCharCode(0));

现在我们可以确认修复程序...



PHP:

  function string_encrypt($ string){
$ crypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $ string,MCRYPT_MODE_ECB);
return $ crypted_text;
}

$ test_str =这是要加密的测试消息。
$ enc_str = string_encrypt($ test_str);
echo bin2hex($ enc_str);

输出:
f98fca4ddc4c10d6cd47df56b081b78566ee4facbcf2254b46f7809d9b255529d2078f28b150e802d72818be1888536fac6219f6ce7b9d9332a24afa09288f0e

Javascript:

 函数toHex(str){
var hex =''; $($ i $)
var val =''+ str.charCodeAt(i).toString(16);
for(var i = 0; i< str.length; i ++)
if(val.length == 1)
hex + ='0'+ val;
else
hex + = val;
}
返回十六进制;
}

var enc_str = mcrypt.Encrypt(这是要加密的测试消息,,,rijndael-256,ecb);
alert(toHex(enc_str));

输出:
f98fca4ddc4c10d6cd47df56b081b78566ee4facbcf2254b46f7809d9b255529d2078f28b150e802d72818be1888536fac6219f6ce7b9d9332a24afa09288f0e

最后,所有这些加密函数产生二进制作为其输出。在大多数情况下,二进制文件不能以纯文本形式写入,而不会损坏数据。要解决这个问题,请将二进制编码为Hex或Base64,然后在尝试解密之前将其解码。



所以要使一切正常...

 <?php 
$ key ='testtesttesttesttesttesttesttest';

函数string_encrypt($ string,$ key){
$ crypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$ key,$ string,MCRYPT_MODE_ECB);
return $ crypted_text;
}

函数string_decrypt($ encrypted_string,$ key){
$ decryptpted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_256,$ key,$ encrypted_string,MCRYPT_MODE_ECB);
return trim($ decryptpted_text);
}

echo $ test_str ='这是要加密的测试消息。 echo'< br />';
$ enc_str = string_encrypt($ test_str,$ key);
echo bin2hex($ enc_str); echo'< br />';
echo string_decrypt($ enc_str,$ key); echo'< br />';

?>

< script src ='rijndael.js'>< / script>
< script src ='mcrypt.js'>< / script>

< script lang ='javascript'>
函数toHex(str){
var hex =''; $($ i $)
var val =''+ str.charCodeAt(i).toString(16);
for(var i = 0; i< str.length; i ++)
if(val.length == 1)
hex + ='0'+ val;
else
hex + = val;
}
返回十六进制;
}
函数hexToString(hex){
var str =''; (var i = 0; i< hex.length; i + = 2)
{
str + =''+ String.fromCharCode(parseInt(hex.charAt(i)+ hex.charAt +1),16));
}
return str;
}
var enc_str = mcrypt.Encrypt('<?php echo $ test_str?','','testtesttesttesttesttesttesttest','rijndael-256','ecb');
alert(toHex(enc_str));
alert(mcrypt.Decrypt(hexToString('<?php echo bin2Hex($ enc_str)?>'),'','testtesttesttesttesttesttesttest','rijndael-256','ecb' \x00 + $ / g,''));
< / script>

还有一些注释...


  1. 您不能 trim 输出 string_encrypt 函数。这将导致前导或尾随零被删除,这将使您无法解密输出。

  2. ECB模式不安全,您不应该使用它。 CBC是要走的路。 CBC 需要IV,对于加密和解密,IV必须是相同的。

  3. 由于各种原因,Javascript加密不安全,任何人都可以简单地查看页面源码或调试运行的javascript来获取加密密钥。阅读ntoskrnl发表在您的问题评论中的链接。

更新:



您的Base64编码问题发生是因为您正在使用的图书馆不使用二进制数据。这对于Base64 JavaScript库来说是一个相当普遍的问题。我建议您使用此图书馆代替。



对于使用javascript解密的尾随 字符,您需要修剪解密输出。您在PHP string_decrypt 方法中执行此操作,但不在您的JavaScript中。您可以通过在字符串末尾的所有 \0 字符上进行正则表达式替换来修剪解密的输出。



示例:

  mcrypt.Decrypt(dec_str,'')。replace(/ \x00 + $ / g, )

我应该将其包含在我的原始帖子中,但是我没注意到 \0 输出中的字符,因为FF的警报框不显示。很抱歉,



最后,我注意到Mcrypt JS库中有另一个错误。第41到47行:

  var ciphers = {//块大小,键大小
rijndael-128: [16,32],
rijndael-192:[24,32],
rijndael-256:[32,32],
serpent:[16,32 ],
twofish:[16,32],
}

注意二鱼行末尾的逗号。 Firefox和Chrome似乎并不介意这一点,但IE8将会报告一个错误,无法加载mcrypt库。解决问题的变化:

 twofish:[16,32],

to:

 twofish:[ 16,32] 


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: *

Mcrypt JS library

Base64 JS library

解决方案

The main issue appears to be that your string_encrypt and string_decrypt PHP functions don't have access to the $key variable, so for the encryption key mcrypt_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 that key 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 PHP mcrypt_encrypt function pads the key. The mcrypt_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:

if(key.length<32)
    key+=Array(33-key.length).join(String.fromCharCode(0));

to this:

if(key.length<16)
    key+=Array(17-key.length).join(String.fromCharCode(0));
else if(key.length<24 && key.length>16)
    key+=Array(25-key.length).join(String.fromCharCode(0));
else if(key.length<32 && key.length>24)
    key+=Array(33-key.length).join(String.fromCharCode(0));

Now we can confirm the fix...

PHP:

function string_encrypt($string) {
    $crypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, "", $string, MCRYPT_MODE_ECB);
    return $crypted_text;
}

$test_str = "This is test message to be encrypted.";
$enc_str = string_encrypt($test_str);
echo bin2hex($enc_str);

Output:
f98fca4ddc4c10d6cd47df56b081b78566ee4facbcf2254b46f7809d9b255529d2078f28b150e802d72818be1888536fac6219f6ce7b9d9332a24afa09288f0e

Javascript:

function toHex(str) {
    var hex = '';
    for(var i=0;i<str.length;i++) {
        var val = ''+str.charCodeAt(i).toString(16);
        if(val.length == 1)
            hex += '0'+val;
        else
            hex += val;
    }
    return hex;
}

var enc_str = mcrypt.Encrypt("This is test message to be encrypted.", "", "", "rijndael-256", "ecb");
alert(toHex(enc_str));

Output:
f98fca4ddc4c10d6cd47df56b081b78566ee4facbcf2254b46f7809d9b255529d2078f28b150e802d72818be1888536fac6219f6ce7b9d9332a24afa09288f0e

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...

<?php 
$key = 'testtesttesttesttesttesttesttest';

function string_encrypt($string, $key) {
    $crypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $string, MCRYPT_MODE_ECB);
    return $crypted_text;
}

function string_decrypt($encrypted_string, $key) {
    $decrypted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted_string, MCRYPT_MODE_ECB);
    return trim($decrypted_text);
}

echo $test_str = 'This is test message to be encrypted.';   echo '<br />';
$enc_str = string_encrypt($test_str, $key);
echo bin2hex($enc_str);                                     echo '<br />';
echo string_decrypt($enc_str, $key);                        echo '<br />';

?>

<script src='rijndael.js'></script>
<script src='mcrypt.js'></script>

<script lang='javascript'>
    function toHex(str) {
        var hex = '';
        for(var i=0;i<str.length;i++) {
            var val = ''+str.charCodeAt(i).toString(16);
            if(val.length == 1)
                hex += '0'+val;
            else
                hex += val;
        }
        return hex;
    }
    function hexToString (hex) {
        var str = '';
        for (var i=0; i<hex.length; i+=2) {
            str += ''+String.fromCharCode(parseInt(hex.charAt(i)+hex.charAt(i+1), 16));
        }
        return str;
    }
    var enc_str = mcrypt.Encrypt('<?php echo $test_str ?>', '', 'testtesttesttesttesttesttesttest', 'rijndael-256', 'ecb');
    alert(toHex(enc_str));
    alert(mcrypt.Decrypt(hexToString('<?php echo bin2Hex($enc_str) ?>'), '', 'testtesttesttesttesttesttesttest', 'rijndael-256', 'ecb').replace(/\x00+$/g, '')); 
</script>

A few more notes...

  1. You cannot trim the output of the string_encrypt function. This will cause leading or trailing zeros to be removed, which will make it so that you cannot decrypt the output.
  2. ECB mode is insecure and you really shouldn't use it. CBC is the way to go. CBC does require an IV, and the IV must be the same for both encryption and decryption.
  3. Javascript encryption is not secure for various reasons, given your usage of it anyone could simply view the pages source or debug the running javascript to get the encryption key. Read the link posted by ntoskrnl in your question comments.

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 PHP string_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:

mcrypt.Decrypt(dec_str,'').replace(/\x00+$/g, '')

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:

var ciphers={       //  block size, key size
    "rijndael-128"  :[  16,         32],
    "rijndael-192"  :[  24,         32],
    "rijndael-256"  :[  32,         32],
    "serpent"       :[  16,         32],
    "twofish"       :[  16,         32],
}

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:

"twofish"       :[  16,         32],

to:

"twofish"       :[  16,         32]

这篇关于Mcrypt js加密值不同于PHP生成的mcrypt / Mcrypt JS解密对于UTF-8字符不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆