Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
JDK8 AES-GCM code example
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.Arrays;
public class AESGCMUpdateAAD2 {
// AES-GCM parameters
public static final int AES_KEY_SIZE = 128; // in bits
public static final int GCM_NONCE_LENGTH = 12; // in bytes
public static final int GCM_TAG_LENGTH = 16; // in bytes
public static void main(String[] args) throws Exception {
int testNum = 0; // pass
if (args.length > 0) {
testNum = Integer.parseInt(args[0]);
if (testNum <0 || testNum > 3) {
System.out.println("Usage: java AESGCMUpdateAAD2 [X]");
System.out.println("X can be 0, 1, 2, 3");
System.exit(1);
}
}
byte[] input = "Hello AES-GCM World!".getBytes();
// Initialise random and generate key
SecureRandom random = SecureRandom.getInstanceStrong();
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(AES_KEY_SIZE, random);
SecretKey key = keyGen.generateKey();
// Encrypt
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
final byte[] nonce = new byte[GCM_NONCE_LENGTH];
random.nextBytes(nonce);
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce);
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] aad = "Whatever I like".getBytes();;
cipher.updateAAD(aad);
byte[] cipherText = cipher.doFinal(input);
// Decrypt; nonce is shared implicitly
cipher.init(Cipher.DECRYPT_MODE, key, spec);
// EXPECTED: Uncommenting this will cause an AEADBadTagException when decrypting
// because AAD value is altered
if (testNum == 1) aad[1]++;
cipher.updateAAD(aad);
// EXPECTED: Uncommenting this will cause an AEADBadTagException when decrypting
// because the encrypted data has been altered
if (testNum == 2) cipherText[10]++;
// EXPECTED: Uncommenting this will cause an AEADBadTagException when decrypting
// because the tag has been altered
if (testNum == 3) cipherText[cipherText.length - 2]++;
try {
byte[] plainText = cipher.doFinal(cipherText);
if (testNum != 0) {
System.out.println("Test Failed: expected AEADBadTagException not thrown");
} else {
// check if the decryption result matches
if (Arrays.equals(input, plainText)) {
System.out.println("Test Passed: match!");
} else {
System.out.println("Test Failed: result mismatch!");
System.out.println(new String(plainText));
}
}
} catch(AEADBadTagException ex) {
if (testNum == 0) {
System.out.println("Test Failed: unexpected ex " + ex);
ex.printStackTrace();
} else {
System.out.println("Test Passed: expected ex " + ex);
}
}
}
}
@Tomato-
Copy link

Tomato- commented Apr 16, 2018

How to alter key size from 128 to 256? cannot only alter param AES_KEY_SIZE to 256
Thanks!

I know the reason now: https://stackoverflow.com/questions/6481627/java-security-illegal-key-size-or-default-parameters

Copy link

ghost commented Jun 26, 2019

This code throws a error
java.security.InvalidAlgorithmParameterException: unknown parameter type.
while running the same on JDK 12

@cinderblocks
Copy link

For completeness you should also add the IV to the tag, e.g. cipher.updateAAD(nonce);

The nonce is already included in the calculation of the authentication tag. Not really any reason why you would need to include it in AAD as you can't verify it without already having the IV in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment