Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AES256 on Java vs PHP

Quick one that's thus far been evading me (long night). I'm comparing AES256 in PHP vs Java and noticing discrepancies. Please for simplicity ignore the ascii key and the null IV, those will be replaced in production. But I need to get past this first and can't figure out where I am erring:

PHP:

echo base64_encode(
    mcrypt_encrypt(
        MCRYPT_RIJNDAEL_128,
        "1234567890ABCDEF1234567890ABCDEF",
        "This is a test",
        MCRYPT_MODE_CBC,
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
    )
);

Java

byte[] key = "1234567890ABCDEF1234567890ABCDEF".getBytes("UTF-8");
byte[] iv  = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
SecretKeySpec newKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
byte[] results = cipher.doFinal("This is a test".getBytes("UTF-8"));

return Base64.encodeToString(results,Base64.DEFAULT);

PHP output: 0KwK+eubMErzDaPU1+mwTQ==

Java output: DEKGJDo3JPtk48tPgCVN3Q==

Not quite what I was expecting o_O !

I've also tried MCRYPT_MODE_CBC, MCRYPT_MODE_CFB, MCRYPT_MODE_ECB, MCRYPT_MODE_NOFB, etc.. none of them produced the Java string.

like image 936
Authman Apatira Avatar asked Nov 12 '22 11:11

Authman Apatira


1 Answers

PHP pads the input bytes with \0 to make it a multiple of the block size. The equivalent in Java would be this (assuming the string you want to encrypt is in data):

Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();

byte[] inputBytes = data.getBytes();
int byteLength = inputBytes.length;
if (byteLength % blockSize != 0) {
    byteLength = byteLength + (blockSize - (byteLength % blockSize));
}

byte[] paddedBytes = new byte[byteLength];

System.arraycopy(inputBytes, 0, paddedBytes, 0, inputBytes.length);

cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
byte[] results = cipher.doFinal(paddedBytes);

As a warning to this - zero-based padding is not desired. There's no way to determine the difference between \0 characters at the end of your string, and the actual padding. It's better to use PKCS5Padding instead, but you will get different results in PHP. Ask yourself if you NEED the encryption cross-platform like this.

like image 60
Colin M Avatar answered Nov 15 '22 04:11

Colin M