0

I have to emulate and JavaScript code in Android to do an AES encrytion and decrytion, but my Android code isn't working as JavaScrip code.

I have to do the same as this code in JavaScript:

<html>
<head>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/pad-zeropadding-min.js"></script>    
<!-- jquery -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<div id="0"></div>
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
<div id="4"></div>
<script>
var key = CryptoJS.enc.Utf8.parse('a5240ba5b7cbde89e8075db30138ce64');
var iv  = CryptoJS.enc.Utf8.parse('1ec9b4a4767e582b8a1e3dcad1782f80');
var message = "message";
$('#0').text("Message: "+message);
var encrypted = CryptoJS.AES.encrypt(message, key, { iv: iv, padding: CryptoJS.pad.ZeroPadding, mode: CryptoJS.mode.CBC});
$('#1').text("Encrypted BASE64: "+encrypted);
$('#2').text("Encrypted HEX: "+encrypted.ciphertext);

var decrypted = CryptoJS.AES.decrypt(encrypted,key, { iv: iv, padding: CryptoJS.pad.ZeroPadding, mode: CryptoJS.mode.CBC});
$('#3').text("Decrypted HEX: "+decrypted);
$('#4').text("Decrypted TEXT: "+decrypted.toString(CryptoJS.enc.Utf8));
</script>
</body>
</html>

I have to do it with bouncycastle lib because the IV has 32 bytes length as you can see, I do it but my code doesn't return the same as this JavaScript code. Anyone know what I am doing wrong, in the android code?

This is the android code:

private static final String ZERO_PADDING_KEY = "a5240ba5b7cbde89e8075db30138ce64";
private static final String IV = "1ec9b4a4767e582b8a1e3dcad1782f80";
public String encryptURL(String url) {
    try {
        Hex hex = new Hex();

        byte[] key = ZERO_PADDING_KEY.getBytes("UTF-8");
        byte[] iv = IV.getBytes("UTF-8");

        PaddedBufferedBlockCipher c = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RijndaelEngine(256)), new ZeroBytePadding());
        c.init(true, new ParametersWithIV(new KeyParameter(key), iv));

        byte[] res = cipherData(c, url.getBytes("UTF-8"));
        String resul = bytesToHex(res);

        return resul;
    } catch (Exception e) {
        Log.e("ENCRYPT ERROR", e.getMessage());
        e.printStackTrace();
    }
    return "";
}

public String decryptUrl(String encrypted) {
    try {
        Hex hex = new Hex();
        byte[] key = ZERO_PADDING_KEY.getBytes("UTF-8");
        byte[] iv = IV.getBytes("UTF-8");


        PaddedBufferedBlockCipher c = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RijndaelEngine(256)), new ZeroBytePadding());
        c.init(false, new ParametersWithIV(new KeyParameter(key), iv));

        byte[] decryptedText = cipherData(c, (byte[]) hex.decode(encrypted));
        String decrypted = new String(decryptedText, "UTF-8");
        Log.d("DECRYPTED", decrypted);

        return decrypted;
    } catch (Exception e) {
        try {
            throw new CryptoException("Unable to decrypt", e);
        } catch (CryptoException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }
    return "";
}

private static byte[] cipherData(PaddedBufferedBlockCipher cipher, byte[] data) throws Exception {

    int minSize = cipher.getOutputSize(data.length);
    byte[] outBuf = new byte[minSize];
    int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
    int length2 = cipher.doFinal(outBuf, length1);
    int actualLength = length1 + length2;
    byte[] result = new byte[actualLength];
    System.arraycopy(outBuf, 0, result, 0, result.length);
    return result;
}

public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

1 Answers1

1

You have new RijndaelEngine(256) in your Android code. It is Rijndael with a block size of 256. CryptoJS only supports AES which is Rijndael with a block size of 128.

Since CryptoJS only supports AES with a block size of 128, the IV size also must be 128. You should parse the IV as Hex. CryptoJS doesn't seem to mind that a bigger IV is passed. In CryptoJS:

var iv = CryptoJS.enc.Hex.parse('1ec9b4a4767e582b8a1e3dcad1782f80');

And in Android you can use the Hex class that you already have in your code.

If you don't want to change the JavaScript code, you can use only the first 128-bit of the IV in Android (I suspect this is what CryptoJS does, but couldn't verify it):

byte[] iv = Arrays.copyOf(IV.getBytes("UTF-8"), 16);
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • But if I put RijndaelEngine(128) I have this exception: java.lang.IllegalArgumentException: initialisation vector must be the same length as block size – Jachumbelechao Unto Mantekilla Jan 21 '15 at 14:54
  • Yes, you have the same problem in JavaScript, but it doesn't seem to trigger the an error. – Artjom B. Jan 21 '15 at 15:00
  • By the way, the IV is supposed to be random for every ciphertext. Just so you know. Generally it is prefixed to the ciphertext and sliced off before decryption . – Artjom B. Jan 21 '15 at 15:02
  • Yes I do it before the Hex, byte[] iv = (byte[]) hex.decode(IV);, but still doesn't return the same. I can't change the JavaScript code, I have to do the same. – Jachumbelechao Unto Mantekilla Jan 21 '15 at 15:03
  • That can't be. Have you checked that the decoded IV is 16 bytes long? If you don't want to change the JS code, you can try to replicate the same behavior. I suspect that only the first 128-bit are used in CryptoJS, but I haven't looked into the source code. – Artjom B. Jan 21 '15 at 15:07
  • Yes only use the 128 first bits, thankyou. You are goin to put the solution? In an answer or put this solution as the accepted answer – Jachumbelechao Unto Mantekilla Jan 21 '15 at 15:15