How are the IV and authentication tag handled for “AES/GCM/NoPadding”?

Q1: Is the IV returned by cipher.getIV() safe for me to use in this way?

Yes, it is at least for the Oracle provided implementation. It is generated separately using the default SecureRandom implementation. As it is 12 bytes in size (the default for GCM) then you have 96 bits of randomness. The chance that the counter repeats is abysmally small. You can look up the source in the OpenJDK (GPL’ed) which the Oracle JDK is based on.

I would however still recommend you to generate your own 12 random bytes as other providers may behave differently.

Q2: Is that IV always 12 bytes long?

It’s extremely likely as it is the GCM default, but other lengths are valid for GCM. The algorithm will however have to do additional calculations for any other size than 12 bytes. Due to weaknesses it is strongly recommended to keep it at 12 bytes / 96 bits and API’s may restrict you to that choice of IV size.

Q3: Is the authentication tag always 16 bytes (128 bits) long?

No, it can have any size in bytes ranging from 64 bits to 128 bits with 8 bit increments. If it is smaller it simply consists of the leftmost bytes of the authentication tag though. You can specify another size of tag using GCMParameterSpec as third parameter for your init call.

Note that the strength of GCM is strongly dependent on the size of the tag. I would recommend keeping it to 128 bits. 96 bits should be the minimum especially if you want to generate a lot of ciphertext.

Q4: With #2 and #3, and the lack of padding, does that mean my encrypted messages are always 12 + src.length + 16 bytes long? (And so I can safely squish them into one byte array, for which I know the correct length?)

See above. For the Oracle provider this is the case. Use GCMParameterSpec to be sure of it.

Q5: Is it safe for me to display an unbounded number of src data encryptions to users, given constant src data that the users know?

Virtually unbound, yes. I would start worrying after about 2^48 encryptions. In general you should however design for key change.

Q6: Is it safe for me to display an unbounded number of src data encryptions to users, if the src data is different every time (e.g. including System.currentTimeMillis() or random numbers)?

See answer to Q5 & Q7

Q7: Would it help if I padded the src data with random numbers before encryption? Say 8 random bytes in front and back, or only on one end? Or would that not help at all / make my encryption worse?

No, it would not help at all. GCM uses CTR mode underneath, so it would just be encrypted with the key stream. It would not act as an IV. Nowadays you could look at AES-GCM-SIV if you have an ever changing message to encrypt, but note that that algorithm is not implemented in any of the JCA providers.

If you need a lot of ciphertexts (higher than 2^48!, or 2^32 – ~4 billion – for the cautious) then I would suggest you use that random number and your key for a key derivation function or KDF. HKDF is currently best of breed, but you may need to use Bouncy Castle or implement it yourself.

Leave a Comment