admin管理员组

文章数量:1435286

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*

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*

Share Improve this question edited Dec 3, 2015 at 13:43 Artjom B. 62k26 gold badges136 silver badges231 bronze badges asked Dec 3, 2015 at 9:01 ArpitaArpita 1,3982 gold badges18 silver badges36 bronze badges 8
  • Why are you using Triple DES nowadays? Use AES: Examples – Artjom B. Commented Dec 3, 2015 at 12:48
  • It is a part of project from past and I am not supposed to change that :) – Arpita Commented Dec 3, 2015 at 13:00
  • Which part aren't you supposed to change? Can you show an example string so that it is easier to find a matching decryption? – Artjom B. Commented Dec 3, 2015 at 13:04
  • I am not supposed to change the encryption we are using i.e. 3DES to AES – Arpita Commented Dec 3, 2015 at 13:05
  • But you can change everything else (e.g. add semantic security by using a random IV or add ciphertext authentication by running HMAC)? – Artjom B. Commented Dec 3, 2015 at 13:11
 |  Show 3 more ments

1 Answer 1

Reset to default 2

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./CryptoStore/crypto-js/3.1.2/build/rollups/tripledes.js"></script>
<script src="https://cdn.rawgit./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.

本文标签: Triple DES encryption in JavaScript and decryption in PHPStack Overflow