2

hi guys i have java code which produce triple des encryption code for me now i am trying to use it on javascript using crypto-js but both codes provides different keys I dont know why and how to get the same key here is my code

 public String _encrypt(String message) throws Exception {
 MessageDigest md = MessageDigest.getInstance("SHA-1");
 byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
 byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
 System.out.println(bytesToHex(keyBytes));

 SecretKey key = new SecretKeySpec(keyBytes, "TripleDES");
 Cipher cipher = Cipher.getInstance("TripleDES");
 cipher.init(Cipher.ENCRYPT_MODE,key);
 byte[] plainTextBytes = message.getBytes("utf-8");
 byte[] buf = cipher.doFinal(plainTextBytes);

 System.out.println(bytesToHex(buf));



 byte [] base64Bytes = Base64.encodeBase64(buf);
 String base64EncryptedString = new String(base64Bytes);

 return base64EncryptedString;
}

 public static String bytesToHex(byte[] in) {
 final StringBuilder builder = new StringBuilder();
 for(byte b : in) {
     builder.append(String.format("%02x", b));
 }
 return builder.toString();
 }


 public String _decrypt(String encryptedText) throws Exception {

 byte[] message = Base64.decodeBase64(encryptedText.getBytes("utf-8"));

MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");

Cipher decipher = Cipher.getInstance("DESede");
decipher.init(Cipher.DECRYPT_MODE, key);

byte[] plainText = decipher.doFinal(message);

return new String(plainText, "UTF-8");
}

and my java script code as follows

 key = CryptoJS.SHA1(key);
 console.log(key.toString());
 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);

var options = {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: ivHex
};

var encrypted = CryptoJS.TripleDES.encrypt(pt, key, options);
var encryptedBase64 = encrypted.toString();
console.log(encryptedBase64);

var ct = {
ciphertext: CryptoJS.enc.Base64.parse(encryptedBase64)
};                                                    
var decrypted = CryptoJS.TripleDES.decrypt(ct, key, options);
console.log(decrypted.toString(CryptoJS.enc.Utf8));

key ="3ad5485e60a4fecd" message="textToEncrypt"

encrypted got from java chKL5NVtBXesEKfNIokpdw==

encrypted got from javascript chKL5NVtBXeTFwswp882Vw==

Can anyone help me or give me brief knowledge why this happens.

Nadeem Mohammed
  • 559
  • 1
  • 6
  • 14
  • In Javascript you're specifying Pkcs7 padding. I don't see that in the Java code. – Jon Skeet Apr 07 '17 at 11:22
  • Jon Skeet without applying padding the result is same – Nadeem Mohammed Apr 07 '17 at 11:28
  • Maybe Javascript is defaulting the padding to Pkcs7. Or maybe it's the mode. Basically, I'd supply both the padding and the mode to both Javascript and Java explicitly, to be clearer. – Jon Skeet Apr 07 '17 at 11:29
  • If the given answer solved your problem, you may [accept](https://meta.stackexchange.com/q/5234/266187) it. If it didn't, then please expand on what is wrong. – Artjom B. May 12 '17 at 18:21

1 Answers1

1

There are multiple differences in the two codes:

  • You're probably using different modes of operation. Java is using ECB and JS is using CBC.

    Always use a fully qualified Cipher string.

    Cipher.getInstance("TripleDES"); may result in different ciphers depending on the default security provider. It most likely results in "TripleDES/ECB/PKCS5Padding", but it doesn't have to be. If it changes, you'll lose compatibility between different JVMs. For reference: Java default Crypto/AES behavior

    Also, PKCS#5 padding and PKCS#7 padding are equal for all intents and purposes.

  • Your key is likely different. A SHA-1 hash has an output of 20 bytes, but a full 3DES key is 24 bytes long. The Arrays.copyOf(digestOfPassword, 24); fills the remaining 4 bytes with 0x00 byte values. In CryptoJS, you're directly passing the short key into the encrypt function. You'd need to fill the remaining bytes with 0x00 bytes. Since CryptoJS handles binary data in a WordArray, this can be done in this way:

    key = CryptoJS.SHA1(key);
    key.sigBytes += 4; // 32 bit more marked
    key.words.push(0); // 32 bit of zeros
    
  • Your IV is strange. It could be so easy:

    var ivHex = CryptoJS.enc.Hex.parse('0000000000000000'); // 8 bytes
    

    This can be done for testing, but in production the IV must be unpredictable (read: random). Don't use a static IV, because that makes the cipher deterministic and therefore not semantically secure. An attacker who observes ciphertexts can determine when the same message prefix was sent before. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.

I would suggest that you throw away this code (only provides 80 bit of security and uses bad defaults) and use a library for that such as RNCryptor.


Security considerations

Never use ECB mode. It's deterministic and therefore not semantically secure. You should at the very least use a randomized mode like CBC or CTR. It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.

Don't use Triple DES nowadays. It only provides at best 112 bit of security even if you use the largest key size of 192 bit. If a shorter key size is used, then it only provides 56 or 57 bits of security. AES would be faster (processors have a special AES-NI instruction set) and even more secure with the lowest key size of 128 bit. There is also a practical limit on the maximum ciphertext size with 3DES. See Security comparison of 3DES and AES.

Community
  • 1
  • 1
Artjom B.
  • 61,146
  • 24
  • 125
  • 222