Sergio David Romero
Sergio David Romero

Reputation: 236

AES Encrypt using CryptoJS

I need to implement AES encryption using JavaScript. Used AES/CBC/NoPadding Mode and created a method to complete 16 lenght blocks. I already solved it using Java. It looks like:

public static String encrypt(byte[] key, byte[] initVector, String value) {
    try {
        IvParameterSpec iv = new IvParameterSpec(initVector);
        SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(completeBlocks(value));
        return Base64.encodeBase64String(encrypted);
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException ex) {
        System.out.println("Error: " + ex);
    }

    return null;
}

/**
 * Completes 16 lenght blocks
 *
 * @param message
 *
 *
 */
static byte[] completeBlocks(String message) {
    try {

        int bytesLenght = message.getBytes("UTF-8").length;
        if (bytesLenght % 16 != 0) {
            byte[] newArray = new byte[bytesLenght + (16 - (bytesLenght % 16))];
            System.arraycopy(message.getBytes(), 0, newArray, 0, bytesLenght);
            return newArray;
        }

        return message.getBytes("UTF-8");

    } catch (UnsupportedEncodingException ex) {
        System.out.println("" + ex);
    }
    return null;
}

public static void main(String[] args) {

    String key = "253D3FB468A0E24677C28A624BE0F939";
    String strToEncrypt = "My Secret text";
    final byte[] initVector = new byte[16];
    String resultado = encrypt(new BigInteger(key, 16).toByteArray(), initVector, strToEncrypt.trim());
    System.out.println("ENCRYPTED:");
    System.out.println(resultado);
}

With inputs key = 253D3FB468A0E24677C28A624BE0F939, strToEncrypt = "My Secret text" and ceros IV. It throws

7StScX3LnPUly/VNzBes0w==

I Know it's the desired output. It's right! I tried to replicate this using JavaScript. I used CryptoJs library. But i wasn't able to produce same Java's output. I have tryed:

var text = "My Secret text";
var key = CryptoJS.enc.Base64.parse("253D3FB468A0E24677C28A624BE0F939");
var iv  = CryptoJS.enc.Base64.parse("                ");
var encrypted = CryptoJS.AES.encrypt(text, key, {iv: iv});
console.log(encrypted.toString());

var decrypted = CryptoJS.AES.decrypt(encrypted, key, {iv: iv});
console.log(decrypted.toString(CryptoJS.enc.Utf8));

Using the same inputs, i get De+CvPVIyiBX2//EE6gXTg== as output. What am I doing wrong? How can i get same Java's output? Thanks a lot!!

Upvotes: 8

Views: 82594

Answers (2)

Sagar M
Sagar M

Reputation: 1092

If you want to encrypt using custom IV, then you can encrypt like...

    let iv = CryptoJS.lib.WordArray.random(IV_LENGTH);
    const key = CryptoJS.enc.Utf8.parse(ENCRYPTION_KEY);

    let encrypted = CryptoJS.AES.encrypt(text, key, { iv })

    const encrypted = encrypted.iv+':'+encrypted.ciphertext

Upvotes: 2

Alex K.
Alex K.

Reputation: 175956

Assuming you will fix things like the empty IV & that this is a proof of concept, your code fails because:

  1. You use no padding in Java, you need to use the same in JS
  2. You manually pad with nulls in Java, you need to do the same in JS
  3. You base64 decode the key but its not base64 (its a hexadecimal string of bytes)
  4. The Java IV is an array of nulls but in JS you use whitespace (and erroneously treat it as base64).

To duplicate the output in JS:

CryptoJS.pad.NoPadding = {pad: function(){}, unpad: function(){}};

var text = "My Secret text\0\0";
var key  = CryptoJS.enc.Hex.parse("253D3FB468A0E24677C28A624BE0F939");
var iv   = CryptoJS.enc.Hex.parse("00000000000000000000000000000000");

var encrypted = CryptoJS.AES.encrypt(text, key, {iv: iv, padding: CryptoJS.pad.NoPadding});

console.log(encrypted.toString());

For:

7StScX3LnPUly/VNzBes0w==

Upvotes: 15

Related Questions