duanhan7001
duanhan7001
2015-12-03 09:01
浏览 85

JavaScript中的三重DES加密和PHP中的解密

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 + '
');
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 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*

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • duanli6618
    duanli6618 2015-12-03 13:40
    已采纳

    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.
    </div>
    
    点赞 评论

相关推荐