0

Since a couple of days i try to figure out why i have in javascript(cryptojs) and java different encryption output. Im at a dead end and dont know what to change anymore, i think i will lose my head on this. This is the complete code and should be easy to copy paste for testing. You are my last hope. ^^

plainText = plaintext
password = password
salt = 3FF2EC019C627B945225DEBAD71A01B6985FE84C95A70EB132882F88C0A59A55
iv = 3C46C00F42A6044A"

Javascript result = zbohHpV5RtmHiH3cKDY15w==

Java result = wVdRQiIqkyVlttkWpCMSpQ==

Javascript html: updated and changed iterations to 10

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Aes Test</title>
        <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/pbkdf2.js"></script>
        <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
    </head>
    <body>
        <div id="result"></div>
    </body>
    <script>


var password = "password";
var salt = "3FF2EC019C627B945225DEBAD71A01B6985FE84C95A70EB132882F88C0A59A55";

var plainText = "plaintext";
var iv = "3C46C00F42A6044A";

var key = CryptoJS.PBKDF2(password, CryptoJS.enc.Hex.parse(salt), {keySize: 128/32, iterations: 10});

var a = CryptoJS.AES.encrypt(plainText, key, {iv: CryptoJS.enc.Hex.parse(iv)}).ciphertext.toString(CryptoJS.enc.Base64);


var result = "encypted: " + a + "<br \>";
document.getElementById("result").innerHTML = result;
    </script>
</html>

Java Main.class

public class main {

    public static void main(String[] args) throws Exception {
        String result = Aes.encrypt("plaintext", "password", "3FF2EC019C627B945225DEBAD71A01B6985FE84C95A70EB132882F88C0A59A55", "3C46C00F42A6044A");
        System.out.println(result);    
    }  
}

Java Aes.class

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class Aes { 
    private static final int pswdIterations = 10;
    private static final int keySize =  128;

    public static String encrypt(String plainText, String password, String salt, String initializationVector) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] saltBytes = salt.getBytes("UTF-8");
        byte[] ivBytes = initializationVector.getBytes("UTF-8");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, pswdIterations, keySize);
        SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivBytes));
        byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes());
        return new Base64().encodeAsString(encryptedTextBytes);
    } 
}
7
  • how is the this this even executing in java ? AES/CBC/PKCS5Padding supports only 128 keysize length. docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html You should be getting Illegal Keysize exception Commented Oct 3, 2014 at 21:25
  • @Anupam: Those are the required to support sizes. In addition, if you install the Unlimited Crypto Jurisdiction files larger key sizes are available. Commented Oct 3, 2014 at 21:36
  • I did disable the restriction but if you want to help you can set it to 128 bit, doesnt matter in that case. Is the standard padding in javascript not AES/CBC/PKCS7 and equals to java AES/CBC/PKCS5 padding? Commented Oct 3, 2014 at 21:40
  • @wook Ok. Just wanted to make sure, because you did not mention this. If you have updated your JCEPolicy then the issue can be narrowed down to padding. The block size of PKSC7 and PKCS5 are different. The block size of PKCS5 is 8 bytes, PKSC7 can have block size of 1-255 bytes. I don't know how to specify the block size. Commented Oct 3, 2014 at 21:53
  • @Anupam Yeah thats true i changed it in the code above to 128 bit now. In the javascript code it is converting the iv and salt to hex. In java it is converting to bytes, i was able to convert the salt to hex but not the iv(gives me some z index error). Result => encryption still is a different result :(. Dont know maybe the mistake is somehow there? Commented Oct 3, 2014 at 22:16

2 Answers 2

1

Finally they are both equal thanks to pasimako to put me on the road. I had to change the way iv and salt was converted to hex and also the lenght of the iv and as mentioned above the keySize and iterationCount variables were undefined aswell.

Here is the complete working code.

They both should output:

encypted: 47S4kEkmEoMoOgngftzyFg==

Javascript

<script>
var password = "password";
var salt = "3FF2EC019C627B945225DEBAD71A01B6985FE84C95A70EB132882F88C0A59A55";

var plainText = "plaintext";
var iv = "12345678901234567890123456789012";

var key = CryptoJS.PBKDF2(password, CryptoJS.enc.Hex.parse(salt), {keySize: 128/32, iterations: 10});

var a = CryptoJS.AES.encrypt(plainText, key, {iv: CryptoJS.enc.Hex.parse(iv)}).ciphertext.toString(CryptoJS.enc.Base64);


var result = "encypted: " + a + "<br \>";
document.getElementById("result").innerHTML = result;
</script>

Java Main.class

public class main {

public static void main(String[] args) throws Exception {
    String result = Aes.encrypt("plaintext", "password", "3FF2EC019C627B945225DEBAD71A01B6985FE84C95A70EB132882F88C0A59A55", "12345678901234567890123456789012");
    System.out.println(result);    
}  
}

Java Aes.class

public class Aes { 
private static final int pswdIterations = 10;
private static final int keySize =  128;

public static String encrypt(String plainText, String password, String salt, String initializationVector) throws NoSuchAlgorithmException, NoSuchPaddingException, DecoderException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException  {
             Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
             SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
             KeySpec spec = new PBEKeySpec(password.toCharArray(), Hex.decodeHex(salt.toCharArray()), pswdIterations, keySize);
             SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
             cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(Hex.decodeHex(initializationVector.toCharArray())));
             byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes());
             return new Base64().encodeAsString(encryptedTextBytes);
} 
}
Sign up to request clarification or add additional context in comments.

Comments

0

First of all your JavaScript code is wrong. Try the code below to see that your keySize and iterationCount variables are undefined.

Aes.generateKey = function(salt, passPhrase) {
  console.log(this.keySize);
  console.log(this.iterationCount);
  var key = CryptoJS.PBKDF2(
          passPhrase, 
          CryptoJS.enc.Hex.parse(salt),
          { keySize: this.keySize, iterations: this.iterationCount });
  return key;
 }

The result from JavaScript should be Bttn5HNBIFDQ5hb1IbOFXQ==

var password = "password";
var salt = "3FF2EC019C627B945225DEBAD71A01B6985FE84C95A70EB132882F88C0A59A55";

var plainText = "plaintext";
var iv = "3C46C00F42A6044A";

var key = CryptoJS.PBKDF2(password, CryptoJS.enc.Hex.parse(salt), {keySize: 128/32, iterations: 10000});

var a = CryptoJS.AES.encrypt(plainText, key, {iv: CryptoJS.enc.Hex.parse(iv)}).ciphertext.toString(CryptoJS.enc.Base64);

console.log(a);

4 Comments

Thanks for clearing that up. But still the javascript output does not match to the java output. Cryptojs is converting salt and iv to hex and in java im converting to bytes. I was able to convert the salt to hex but not the iv without error. Maybe the mistake is here?
How do you convert the String (with hex values) to a byte array in Java? Are you using something similar to this post: link
Yeah something similar. Also tried the methods in your link just getting again a new different encryption ciphertext. But no match javascript <-> java :(
Nevertheless, when you use the .getBytes("UTF-8") on a String representing a hex value you get an array of UTF8 characters instead of a number which is what you actually want in this case. You should first correct that and then try to find a solution for the iv error...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.