0
votes

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();
    }

}
2
Please don't edit your question to include an answer. You can post an answer to your own question. After you've done that, please rollback your question to revision 4.Artjom B.
The answer in your question uses a key that is not a valid Hex-encoding, because it contains characters beyond 0-9, a-f, A-F. This code should throw an error.Artjom B.

2 Answers

2
votes

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.

0
votes

Answer: With the help of Artjom B. I have created the code that will decrypt the AES-256 / CBC / ZeroBytePadding encrypted string. I am posting this for others who need the help.

1. Firstly you have to download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy for your JDK version.

2. Extract the zip file & put the local_policy.jar & US_export_policy.jar in the path /JDK Path/jre/lib/security. This is required as my key is 64 byte. AES requires 16/24/32 bytes of key.

3. Copy paste my code & change it as per your requirement :P.

import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.binary.Base64;

public class Decryption {

public static void main(String args[]) {
//I have changed the original key. So mere copy pasting may not work. Put your key here.
    String key = "FfDaaaaaaa444aaaa7aaEFF4A76efaaaaaE5C23F5E4C3adeaaaaaaCAA796E307";
    String encrypted = "8AQ8SvpF1zgyNyxKwLlX\\/cGzwLE5skU58pg3kaSrt+AJt9D7\\/3vaNRPZISIKMdCUwwkQ2nxj8PVABRy0aaeBfsJN9n2Ltco6oPjdcmx8eOI";
    String decrypted = "";
    try {

        try {
            decrypted = decrypt(Hex.decodeHex(key.toCharArray()), encrypted);
        } catch (DecoderException e) {
            e.printStackTrace();
        }

        System.out.println(decrypted);
    } catch (GeneralSecurityException e) {
        e.printStackTrace();
    }

}

public static 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());

    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); 

}

}

Thanks @Artjom B. for your help & expertise :).