hsu*_*suk 6 php encryption mcrypt mcrypt-js
我一直在尝试在服务器端,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>
Run Code Online (Sandbox Code Playgroud)
我在mcrypt.js库中使用了以下私有变量.
var cMode='ecb';
var cCipher='rijndael-256';
var cKey='testtesttesttesttesttesttesttest';
//I am providing the same key
Run Code Online (Sandbox Code Playgroud)
正如我在上面评论的那样,为什么它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.
Run Code Online (Sandbox Code Playgroud)
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.*/
Run Code Online (Sandbox Code Playgroud)
使用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.
Run Code Online (Sandbox Code Playgroud)
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éÓ!ÆÖ
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,UTf-8内容都无法在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库中的一个错误.\0
如果密钥长度小于32个字节,则此库填充加密密钥,问题是这不是 PHP mcrypt_encrypt
函数填充密钥的方式.该mcrypt_encrypt
功能将密钥填充到最近的有效密钥长度(16,24或32字节).mcrypt.js中的问题位于第63和64行,更改为:
if(key.length<32)
key+=Array(33-key.length).join(String.fromCharCode(0));
Run Code Online (Sandbox Code Playgroud)
对此:
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));
Run Code Online (Sandbox Code Playgroud)
现在我们可以确认修复...
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
Run Code Online (Sandbox Code Playgroud)
使用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
Run Code Online (Sandbox Code Playgroud)
最后,所有这些加密函数都产生二进制作为其输出.在大多数情况下,二进制文件不能以纯文本形式写入而不会损坏数据.要解决此问题,请将二进制编码为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>
Run Code Online (Sandbox Code Playgroud)
还有一些笔记......
trim
输出这个string_encrypt
功能.这将导致删除前导零或尾随零,这将使您无法解密输出.更新:
出现Base64编码问题是因为您使用的库不能使用二进制数据.对于Base64 javascript库来说,这是一个相当普遍的问题.我建议改用这个库.
对于?
使用javascript解密时的尾随字符,您需要修剪解密输出.你在PHP string_decrypt
方法中这样做,但不是在你的javascript中.您可以通过\0
对字符串末尾的所有字符执行正则表达式替换来修剪解密输出.
例:
mcrypt.Decrypt(dec_str,'').replace(/\x00+$/g, '')
Run Code Online (Sandbox Code Playgroud)
我应该把它包含在我的原始帖子中,但是我没有注意到\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],
}
Run Code Online (Sandbox Code Playgroud)
注意"twofish"行末尾的逗号.Firefox和Chrome似乎并不介意,但IE8会报告错误,因此无法加载mcrypt库.要解决问题更改:
"twofish" :[ 16, 32],
Run Code Online (Sandbox Code Playgroud)
至:
"twofish" :[ 16, 32]
Run Code Online (Sandbox Code Playgroud)