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);
    } 
}
wook
  • 13
  • 1
  • 7
  • how is the this this even executing in java ? AES/CBC/PKCS5Padding supports only 128 keysize length. http://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html You should be getting Illegal Keysize exception – anu Oct 03 '14 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. – President James K. Polk Oct 03 '14 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? – wook Oct 03 '14 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. – anu Oct 03 '14 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? – wook Oct 03 '14 at 22:16
  • @wook Where are you getting this error ? java or javascript ? Also can you specify the error ? – anu Oct 03 '14 at 22:32
  • @Anupam In java if i try to convert the iv to hex it says "Wrong IV length: must be 16 bytes long" and if i make it 16 bytes "Illegal hexadecimal character z at index 1" – wook Oct 03 '14 at 22:44

2 Answers2

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);
} 
}
wook
  • 13
  • 1
  • 7
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);
pasimako
  • 101
  • 2
  • 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? – wook Oct 03 '14 at 22:24
  • How do you convert the String (with hex values) to a byte array in Java? Are you using something similar to this post: [link](http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java) – pasimako Oct 03 '14 at 23:15
  • Yeah something similar. Also tried the methods in your link just getting again a new different encryption ciphertext. But no match javascript <-> java :( – wook Oct 03 '14 at 23:43
  • 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... – pasimako Oct 03 '14 at 23:52