AES encryption using Java and decryption using Javascript

rkj picture rkj · Mar 24, 2014 · Viewed 28.2k times · Source

I am making an application which needs Java based AES Encryption and JavaScript based decryption. I am using the following code for encryption as a basic form.

public class AESencrp {

  private static final String ALGO = "AES";
  private static final byte[] keyValue = 
      new byte[] { 'A', 'b', 'c', 'd', 'e', 'f', 'g',
      'h', 'i', 'j', 'k','l', 'm', 'n', 'o', 'p'};

  public static String encrypt(String Data) throws Exception {
    Key key = generateKey();
    Cipher c = Cipher.getInstance(ALGO);
    c.init(Cipher.ENCRYPT_MODE, key);
    byte[] encVal = c.doFinal(Data.getBytes());
    String encryptedValue = new BASE64Encoder().encode(encVal);
    return encryptedValue;
  }


  private static Key generateKey() throws Exception {
    Key key = new SecretKeySpec(keyValue, ALGO);
    return key;
  }
}

The JavaScript that I am trying to use to decrypt is

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js">   </script>

var decrypted = CryptoJS.AES.decrypt(encrypted,"Abcdefghijklmnop").toString(CryptoJS.enc.Utf8);

But the JavaScript decryption is not working. I am new to this, could someone tell me a way to solve without changing the Java code block ?

I tried Base-64 decoding my text like this:

var words  = CryptoJS.enc.Base64.parse(encrKey);
var base64 = CryptoJS.enc.Base64.stringify(words);
var decrypted = CryptoJS.AES.decrypt(base64, "Abcdefghijklmnop");
alert("dec :" +decrypted);

but still no good.

I tried the solution suggested below to resolve possible padding issue but its not giving any solution.

var key = CryptoJS.enc.Base64.parse("QWJjZGVmZ2hpamtsbW5vcA==");
var decrypt = CryptoJS.AES.decrypt( encrKey, key, { mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7 } );

alert("dec :" +decrypt);

Answer

Oleg Estekhin picture Oleg Estekhin · Mar 24, 2014
  1. Your Java code uses the 128-bit AES key while your JavaScript code uses the 256-bit AES key.

  2. Your Java code uses the "Abcdefghijklmnop".getBytes() as the actual key value, while your JavaScript code uses the "Abcdefghijklmnop" as the passphrase from which the actual key is derived.

  3. The default transformation for Java AES is AES/ECB/PKCS5Padding, while default transformation for CryptoJS is AES/CBC/PKCS7Padding.

One way to fix your example is to fix the JavaScript side:

// this is Base64 representation of the Java counterpart
// byte[] keyValue = new byte[] { 'A', 'b', 'c', 'd', 'e', 'f', 'g',
//                'h', 'i', 'j', 'k','l', 'm', 'n', 'o', 'p'};
// String keyForJS = new BASE64Encoder().encode(keyValue);
var base64Key = "QWJjZGVmZ2hpamtsbW5vcA==";
console.log( "base64Key = " + base64Key );

// this is the actual key as a sequence of bytes
var key = CryptoJS.enc.Base64.parse(base64Key);
console.log( "key = " + key );

// this is the plain text
var plaintText = "Hello, World!";
console.log( "plaintText = " + plaintText );

// this is Base64-encoded encrypted data
var encryptedData = CryptoJS.AES.encrypt(plaintText, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
});
console.log( "encryptedData = " + encryptedData );

// this is the decrypted data as a sequence of bytes
var decryptedData = CryptoJS.AES.decrypt( encryptedData, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
} );
console.log( "decryptedData = " + decryptedData );

// this is the decrypted data as a string
var decryptedText = decryptedData.toString( CryptoJS.enc.Utf8 );
console.log( "decryptedText = " + decryptedText );