2015-12-03 90 views
0

我正在使用JavaScript加密和php解密字符串,反之亦然,但问题是在两个平台上产生的输出是不同的如果我加密一个字符串“abc “在这两个平台上,他们会产生不同的结果,但我确信我的加密是正确的,因为我正在加密的字符串是用相同的语言解密的。JavaScript中的三重DES加密和PHP解密

我明白,在这种情况下,必须有东西在关键或IV不同,但不知道是什么

Javascript代码加密字符串

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代码加密字符串

//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); 

示例 如果我从javascript加密字符串“admin”它给了我“U2 FsdGVkX1 + Y/zo1FJEZZ0aqPMQuwilOydbJjzIKpYw =”

凡为PHP给我 “AzZFzbnwp2Y =”

我使用CryptoJSv3插件三重DES *

+0

为什么现在使用Triple DES?使用AES:[示例](http://stackoverflow.com/questions/24337317/encrypt-with-php-decrypt-with-javascript-cryptojs) –

+0

它是过去的项目的一部分,我不应该改变:) – Arpita

+0

哪部分不应该改变?你能否显示一个示例字符串,以便更容易找到匹配的解密? –

回答

0

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

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

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>


此代码是不是这些原因非常安全:

  • 它采用三重DES只提供112位安全的,最好的。你应该使用AES。
  • 它使用静态IV。这在语义上不安全,因为攻击者可能会看到您是否仅通过观察密文来发送相同的消息。您需要为每个加密使用随机IV,并将其与密文一起发送。
  • 它不使用身份验证。这个系统可能容易受到填充oracle的攻击。这是一个在线攻击,它使攻击者能够用多次尝试解密任何密文。您或者需要使用GCM/EAX(不建议用于Triple DES)的身份验证模式,或者在密文上运行HMAC-SHA256来生成身份验证标签并将其与密文一起发送,以在接收端进行验证。
+0

你将如何为这段代码创建一个随机IV? –

+1

@MartinBarker CryptoJS通过使用'var iv = CryptoJS.lib.WordArray.random(8);'(IV for 3DES是8字节长)提供了非加密安全的随机字节发生器。不过你应该使用更好的随机性。 [这是一个polyfill](https://github.com/artjomb/cryptojs-extension/blob/master/src/random.js)以获得更好的随机数,如果它在浏览器中可用的话。 –

+0

谢谢你,我会研究它,我试图创建一个非常安全的JSONRPC方法,所以我要加密与SSL连接内的Triple-DES只是为了确保它的安全:) –