gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 13:17:50 26 4
gpt4 key购买 nike

我一直在尝试在服务器端、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 库中使用了以下私有(private)变量。

 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 library

Base64 JS library

最佳答案

主要问题似乎是您的 string_encryptstring_decrypt PHP 函数无法访问 $key 变量,因此对于加密 key mcrypt_encrypt 使用 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0。参见 this question寻求解释。 PHP 应该报告 key 未定义的通知,您是否关闭了错误报告?从加密函数中回显 key 以确认这一点。

另一个问题是 Mcrypt JS 库中的错误。如果 key 长度小于 32 字节,这个库用 \0 填充加密 key ,问题是这不是 PHP mcrypt_encrypt 功能垫键。 mcrypt_encrypt 函数将 key 填充到最接近的有效 key 长度(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. 您不能修剪 string_encrypt 函数的输出。这将导致删除前导或尾随零,从而使您无法解密输出。
  2. ECB 模式不安全,您真的不应该使用它。 CBC 是必经之路。 CBC 确实需要一个 IV,并且加密和解密的 IV 必须相同。
  3. Javascript 加密出于各种原因并不安全,考虑到您对它的使用,任何人都可以简单地查看页面源代码或调试正在运行的 javascript 以获取加密 key 。阅读 ntoskrnl 在您的问题评论中发布的链接。

更新:

您的 Base64 编码问题发生是因为 library you're using不适用于二进制数据。对于 Base64 javascript 库来说,这是一个相当普遍的问题。我建议使用 this library相反。

对于javascript解密时尾部的字符,需要修剪解密后的输出。您在 PHP string_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]

关于php - Mcrypt js 加密值不同于 PHP mcrypt/Mcrypt JS 解密生成的值不适用于 UTF-8 字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18786025/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com