How can I decrypt using BouncyCastle, a string using a GCM Tag , IV string and Key string, all of them in HEX?

Viewed 353

I amn trying to replicate the AES-Decrypt function from CyberChef, using GCM mode and HEX input. Screenshot of the operation:

CyberChefAesDecrypt

So far, I've written the following code:

package decryption;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;

public class Main {
    public static final int GCM_TAG_LENGTH = 32;

    public static void main(String[] args) throws Exception {
        String IV = "9092d522e11120919fce8492";
        String input = "90fab0";
        String GCMTag = "02883e111ad6f79cd53674b5f833abab";
        String key = "8cda92dcb3283da821daa275359642c7a05d60a4badb5769618193a930c1cdec";

        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), 0, key.getBytes(StandardCharsets.UTF_8).length, "AES");
        System.out.println(decrypt(input.getBytes(StandardCharsets.UTF_8), secretKey, IV.getBytes(StandardCharsets.UTF_8)));
    }

    public static String decrypt(byte[] cipherText, SecretKeySpec key, byte[] IV) throws Exception {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV);
        cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
        byte[] decryptedText = cipher.doFinal(cipherText);
        return new String(decryptedText);
    }
}

For the above code I am getting:

Exception in thread "main" org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$InvalidKeyOrParametersException: Invalid value for MAC size: 256
    at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineInit(Unknown Source)
    at java.base/javax.crypto.Cipher.init(Cipher.java:1442)
    at java.base/javax.crypto.Cipher.init(Cipher.java:1375)
    at decryption.Main.decrypt(Main.java:29)
    at decryption.Main.main(Main.java:19)

Fairly certain I am way off, but I did not find any articles/tutorials on how the GCM Tag can be used as input.

1 Answers

The length of the GCM tag used here is not 32, but 16 bytes.

Furthermore, the BC provider expects ciphertext and tag in concatenated form (ciphertext|tag).

And you have to hex decode key, IV, ciphertext and tag. Since you are running BouncyCastle, you can use org.bouncycastle.util.encoders.Hex.decode(...).

Overall:

import org.bouncycastle.util.encoders.Hex;
...
public static final int GCM_TAG_LENGTH = 16;
... 
SecretKeySpec secretKey = new SecretKeySpec(Hex.decode(key), "AES");
System.out.println(decrypt(Hex.decode(input + GCMTag), secretKey, Hex.decode(IV))); // 985

It is not clear from your code whether you are using a static IV/nonce. If so, you should be aware that using a static IV/nonce for GCM is a serious problem, s. e.g. here.
Instead, for each encryption, a random (non-secret) IV/nonce is generated, concatenated with the ciphertext (and tag), and sent together to the decrypting side, which can separate the IV/nonce based on the known IV/nonce size (12 bytes for GCM).


AES/GCM is also supported by the SunJCE provider (at least as of Java 8, s. e.g. here), so you may not need BouncyCastle. For hex decoding you can then use a solution from this post. Starting with Java 17 there is a built-in support.

Related