Mcrypt js加密值与PHP mcrypt产生的值不同/ Mcrypt JS解密不适用于UTF-8字符

uk

我一直在尝试在服务器端,PHP和客户端上都实现mcrypt加密/解密技术。我目前正在尝试将mcrypt.js库用作:

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

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

 var cMode='ecb';
 var cCipher='rijndael-256';
 var cKey='testtesttesttesttesttesttesttest'; 
 //I am providing the same key

正如我上面评论的enc_str那样$enc_str,为什么mcrypt.Decrypt('<?php echo $enc_str ?>', '')不等于string_decrypt($enc_str, $key)为什么不等于



更新的问题:

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


使用Hex2bin / Bin2hex

PHP结果:

Provided Text: This is test message.
Encyrpted Value: a51e970427ec8f666a5684cc1712ad03b29889cc10f4ccbf55733564d11c0386
Decrypted Value: This is test message.

JS结果:

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

使用Base64编码/解码:

PHP结果:

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结果:

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éÓ!ÆÖ

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


*链接:*

Mcrypt JS库

Base64 JS库

yon

主要问题似乎是您string_encryptstring_decryptPHP函数无权访问该$key变量,因此对于加密密钥而言,mcrypt_encrypt它使用\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0请参阅此问题以获取解释。PHP应该报告key未定义的通知,也许您已关闭错误报告?从加密功能内部回显密钥以确认这一点。

另一个问题是Mcrypt JS库中的错误。\0如果密钥长度小于32字节,该库将使用加密密钥填充密钥,问题是这不是PHPmcrypt_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 = "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

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

所以要让一切正常工作...

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

还有一些注意事项...

  1. 您无法trim输出string_encrypt函数。这将导致删除前导零或尾随零,这将使您无法解密输出。
  2. ECB模式是不安全的,您真的不应该使用它。CBC是必经之路。CBC确实需要IV,并且加密和解密的IV必须相同。
  3. 出于各种原因,JavaScript加密是不安全的,考虑到您的用法,任何人都可以简单地查看页面源代码或调试运行中的javascript以获取加密密钥。阅读ntoskrnl在您的问题评论中发布的链接。

更新:

发生Base64编码问题是因为您使用不适用于二进制数据。对于Base64 javascript库,这是一个相当普遍的问题。我建议改用这个库

至于使用javascript解密时的结尾字符,您需要修剪解密后的输出。您是在PHPstring_decrypt方法中执行此操作,而不是在javascript中执行此操作您可以通过\0对字符串末尾的所有字符进行正则表达式替换来修剪解密的输出

例子:

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

我本应该在原始帖子中包含此内容,但是\0由于FF的警报框未显示这些字符,因此我没有注意到输出中字符。对于那个很抱歉。

最后,我注意到Mcrypt JS库中的另一个错误。第41至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],
}

请注意“ twofish”行末尾的逗号。Firefox和Chrome似乎并不介意,但是IE8会报告错误,并因此而无法加载mcrypt库。要解决问题更改:

"twofish"       :[  16,         32],

到:

"twofish"       :[  16,         32]

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章