Search code examples
javaphpencryptionaesinitialization-vector

How to decode a AES-256 / CBC / ZeroBytePadding encrypted object


I am pretty new in Java Cryptography.I have provided with the following PHP code to decrypt a AES-256 / CBC / ZeroBytePadding encrypted object.

function decrypt($key, $data)
{
    if (!in_array(strlen($key), array(32, 48, 64)))
{
    throw new Exception("Invalid key");
}

$key_hex = pack('H*', $key);

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);

$ciphertext = base64_decode($data);

# retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
$iv_dec = substr($ciphertext, 0, $iv_size);

# retrieves the cipher text (everything except the $iv_size in the front)
$ciphertext_dec = substr($ciphertext, $iv_size);

# may remove 00h valued characters from end of plain text
$result = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key_hex, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

return $result;
}

I need to do the same in java. After lots of searching I have made the following code:

 public String decrypt(byte key[], String encrypted)
            throws GeneralSecurityException {
        if (key.length != 32 || key.length != 48 || key.length != 64) {
            throw new IllegalArgumentException("Invalid key size.");
        }
    byte[] ciphertextBytes = Base64.decodeBase64(encrypted.getBytes());

    // Need to find the IV length here. I am using 16 here

    IvParameterSpec iv = new IvParameterSpec(ciphertextBytes, 0, 16);
    ciphertextBytes = Arrays.copyOfRange(ciphertextBytes, 16,
            ciphertextBytes.length);

    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
    byte[] original = cipher.doFinal(ciphertextBytes);

    // remove zero bytes at the end
    int lastLength = original.length;
    for (int i = original.length - 1; i > original.length - 16; i--) {
        if (original[i] == (byte) 0) {
            lastLength--;
        } else {
            break;
        }
    }

    return new String(original, 0, lastLength);
}

But I need to find the IV length here. In PHP they are doing this using: $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); How to implement it in java? Can anybody help me please?

I am calling the method like this:

public static void main(String args[]) {
        String key =     "F5D4471791B79B6360C1EFF4A76250C1D7E5C23F5E4C3C43893B6CCAA796E307";
        String encrypted =     "F4N8SvpF1zgyMnQKwLlX\\/Dfgsj4kU58pg3kaSrt+AJt9D7\\/3vAfngegtytAdCUwwkQ2nxj8PVABRy0aaeBfsJN9n2Ltco6oPjdcmx8eOI";

    try {
        String decrypted = decrypt(Hex.decodeHex(key.toCharArray()), encrypted);
        System.out.println(decrypted);
    } catch (GeneralSecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

Solution

  • An IV for AES (Rijndael-128) in CBC mode has always the same size as the block, which is 16 bytes or 128 bits. If you keep using CBC mode, then you can hardcode that value or use Cipher#getBlockSize().

    If you want to use AES-256, then you need to install the Unlimited Strength policy files for your JRE/JDK (Link for Java 8). AES-128 can be used without modification, but the US export restrictions require that you enable the higher key sizes yourself.