JavaScript中的三重DES加密和PHP中的解密 [英] Triple DES encryption in JavaScript and decryption in PHP

查看:322
本文介绍了JavaScript中的三重DES加密和PHP中的解密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JavaScript加密和php来解密字符串,反之亦然,但问题是在两个平台上,生成的输出是不同的说如果我在两个平台上加密一个字符串abc,他们将产生不同的结果,虽然我确信我的加密是正确的,因为我正在加密的字符串是用相同的语言解密。



我明白,在这种情况下,必须有一些不同的键或iv,但不知道它是什么



加密字符串的Javascript代码

  var encrypted = CryptoJS.TripleDES.encrypt(Message,SecretPassphrase); 
console.log(encrypted); console.log(String(encrypted));

var text =<某些纯文本在这里>;
var key =00f74597de203655b1ebf5f410f10eb8;
var useHashing = true;

if(useHashing){
key = CryptoJS.MD5(key).toString();
key + = key.substring(1,16);
console.log(key);
}
var textWordArray = CryptoJS.enc.Utf16.parse(text);
var keyHex = CryptoJS.enc.Hex.parse(key);
var iv = String.fromCharCode(0)+ String.fromCharCode(0)+ String.fromCharCode(0)+ String.fromCharCode(0)+ String.fromCharCode(0)+ String.fromCharCode(0)+ String .fromCharCode(0)+ String.fromCharCode(0);
var ivHex = CryptoJS.enc.Hex.parse(iv);
console.log('hexadecimal key:'+ keyHex +'\\\
');
console.log('iv:'+ iv +'\\\
');
console.log('hexadecimal iv:'+ ivHex +'\\\
');
var options = {
mode:CryptoJS.mode.CBC,
padding:CryptoJS.pad.Pkcs7,
iv:ivHex
};
var encrypted = CryptoJS.TripleDES.encrypt(textWordArray,keyHex,options);
var base64String = encrypted.toString();
console.log('base64:'+ base64String +'\\\
');
var decryptpted = CryptoJS.TripleDES.decrypt({
ciphertext:CryptoJS.enc.Base64.parse(base64String)
},keyHex,options);
console.log('decryptpted:'+ decryptpted.toString(CryptoJS.enc.Utf16));

加密字符串的PHP代码

  //从哈希生成一个密钥
$ key = md5(utf8_encode(00f74597de203655b1ebf5f410f10eb8),true);

//以$ key的前8个字节,并将它们追加到$ key的末尾。
$ key。= substr($ key,0,8);
//填充3DES
$ blockSize = mcrypt_get_block_size('tripledes','ecb');
$ len = strlen($ value);
$ pad = $ blockSize - ($ len%$ blockSize);
$ value。= str_repeat(chr($ pad),$ pad);

//为3DES
$ iv = chr(0)生成iv。 chr(0)。 chr(0)。 chr(0)。 chr(0)。 chr(0)。 chr(0)。 CHR(0);

//加密数据
$ encData = mcrypt_encrypt(MCRYPT_3DES,$ key,$ value,MCRYPT_MODE_CBC,$ iv);

$ value = base64_encode($ encData);

示例
如果我将字符串admin从javascript它给了我U2FsdGVkX1 + y / zo1FJEZZ0aqPMQuwilOydbJjzIKpYw =



哪里php给我AzZFzbnwp2Y =



注意我使用CryptoJSv3插件进行三重DES *

解决方案

MD5产生128位的输出,但是一个三重DES密钥应该是192位长。这就是为什么你的PHP代码将生成的哈希的前64位复制到后面。 PHP和CryptoJS都使用EDE,这个密钥副本导致了 K1 ||的关键布局K2 || K1



您可以在CryptoJS中做同样的事情。由于CryptoJS使用 WordArray 以32位字的形式内部管理二进制数据,因此可以将前两个字直接复制到内部数组的后面。

$ $class =false>

  var pt =admin; document.querySelector(#pt)。innerHTML = ; var key =00f74597de203655b1ebf5f410f10eb8; key = CryptoJS.MD5(key); //将3DES子键1复制到最后的64位,使一个完整的192位密钥.words [4] = key.words [0]; key .words [5] = key.words [1]; //创建一个64位零填充iv = CryptoJS.lib.WordArray.create(64/8); var encrypted = CryptoJS.TripleDES.encrypt(pt,key, {iv:iv}); var encryptedBase64 = encrypted.toString(); document.querySelector(#enc)。innerHTML = encryptedBase64; var ct = {ciphertext:CryptoJS.enc.Base64.parse(encryptedBase64)}; = CryptoJS.TripleDES.decrypt(ct,key,{iv:iv} ); document.querySelector(#dec)。innerHTML = decryptpted.toString(CryptoJS.enc.Utf8);  

 < script src =https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/tripledes.js>< ; / script>< script src =https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/md5.js>< / script>< p>预期:AzZFzbnwp2Y =< br /> Got:< span id =enc>< / span>< / p>< p>预期:< span id =pt < / span>< br /> Got:< span id =dec>< / span>< / p>  






由于这些原因,此代码不太安全:




  • 它使用三重DES,最多只提供112位的安全性。你应该使用AES。

  • 它使用静态IV。这不是语义上安全的,因为攻击者可能会看到您是否只发送相同的消息,只能通过观察密文。您需要为每个加密使用随机IV,并将其与密文一起发送。

  • 它不使用身份验证。该系统可能容易受到填充oracle攻击。这是一种在线攻击,使攻击者能够通过多次尝试来解密任何密文。您需要使用经过认证的模式,如GCM / EAX(不适用于三重DES),或通过密文运行HMAC-SHA256,以产生认证标签,并与密文一起发送,以便在接收端进行验证。 li>

I am using JavaScript to encrypt and php to decrypt the string and vice versa but the problem is that on both the platforms the output being generated is different say If I encrypt a string "abc" on both the platforms they will produce different results although I am sure my encryption is correct because the string I am encrypting is decrypted in same language.

I understands that in this case there has to be something different in key or iv but do not know what it

Javascript code to encrypt string

var encrypted = CryptoJS.TripleDES.encrypt("Message", "SecretPassphrase");
console.log(encrypted);console.log(String(encrypted));

var text = "<some plain text goes here>";
var key = "00f74597de203655b1ebf5f410f10eb8";
var useHashing = true;

if (useHashing) {
    key = CryptoJS.MD5(key).toString();
    key +=  key.substring(1, 16);
    console.log(key);
}
var textWordArray = CryptoJS.enc.Utf16.parse(text);
var keyHex = CryptoJS.enc.Hex.parse(key);
var iv = String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0);
var ivHex = CryptoJS.enc.Hex.parse(iv);
console.log('hexadecimal key: ' + keyHex + '\n');
console.log('iv: ' + iv + '\n');
console.log('hexadecimal iv: ' + ivHex + '\n');
var options = {
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
    iv: ivHex
};
var encrypted = CryptoJS.TripleDES.encrypt(textWordArray, keyHex, options);
var base64String = encrypted.toString();
console.log('base64: ' + base64String + '\n');
var decrypted = CryptoJS.TripleDES.decrypt({
    ciphertext: CryptoJS.enc.Base64.parse(base64String)
}, keyHex, options);
console.log('decrypted: ' + decrypted.toString(CryptoJS.enc.Utf16));

PHP code to encrypt string

//Generate a key from a hash
$key = md5(utf8_encode("00f74597de203655b1ebf5f410f10eb8"), true);

//Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8);
//Padding for 3DES        
$blockSize = mcrypt_get_block_size('tripledes', 'ecb');
$len = strlen($value);
$pad = $blockSize - ($len % $blockSize);
$value .= str_repeat(chr($pad), $pad);

//Generating iv for 3DES
$iv = chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0);

//Encrypt data
$encData = mcrypt_encrypt(MCRYPT_3DES, $key, $value, MCRYPT_MODE_CBC, $iv);

$value = base64_encode($encData);

Example If I encrypt the string "admin" from javascript it gives me "U2FsdGVkX1+y/zo1FJEZZ0aqPMQuwilOydbJjzIKpYw="

Where as php give me "AzZFzbnwp2Y="

Note I am using CryptoJSv3 plugin for triple DES*

解决方案

MD5 produces output of 128 bit, but a Triple DES key should be 192 bit long. That is why your PHP code copies the first 64 bits of the produced hash to the back. PHP and CryptoJS both use the EDE and this key copy leads to the key layout of K1 || K2 || K1.

You can do the same thing in CryptoJS. Since CryptoJS uses a WordArray to manage binary data internally as words of 32 bit, you can directly copy the first two words to the back of the internal array.

var pt = "admin";
document.querySelector("#pt").innerHTML = pt;

var key = "00f74597de203655b1ebf5f410f10eb8";
key = CryptoJS.MD5(key);

// copy 3DES subkey 1 to the last 64 bit to make a full 192-bit key
key.words[4] = key.words[0];
key.words[5] = key.words[1];

// create a 64-bit zero filled
var iv = CryptoJS.lib.WordArray.create(64/8);
var encrypted = CryptoJS.TripleDES.encrypt(pt, key, {iv: iv});
var encryptedBase64 = encrypted.toString();

document.querySelector("#enc").innerHTML = encryptedBase64;

var ct = {
    ciphertext: CryptoJS.enc.Base64.parse(encryptedBase64)
};
var decrypted = CryptoJS.TripleDES.decrypt(ct, key, {iv: iv});

document.querySelector("#dec").innerHTML = decrypted.toString(CryptoJS.enc.Utf8);

<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/tripledes.js"></script>
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/md5.js"></script>
<p>Expected: "AzZFzbnwp2Y="<br/>Got: "<span id="enc"></span>"</p>
<p>Expected: "<span id="pt"></span>"<br/>Got: "<span id="dec"></span>"</p>


This code is not very secure for those reasons:

  • It uses Triple DES which only provides 112 bit of security, at best. You should use AES.
  • It uses a static IV. This is not semantically secure, because an attacker might see whether you sent the same message only by observing the ciphertexts. You need to use a random IV for each encryption and send it along with the ciphertext.
  • It doesn't use authentication. This system might be vulnerable to the padding oracle attack. It is an online attack which enables the attacker to decrypt any ciphertext with multiple tries. You either need to use an authenticated mode like GCM/EAX (not advisable for Triple DES) or run an HMAC-SHA256 over the ciphertext to produce the authentication tag and send it along with the ciphertext to verify it on the receiving end.

这篇关于JavaScript中的三重DES加密和PHP中的解密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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