How do you supply algorithm parameters (the IV/nonce) to a Java Cipher, and how do IvParameterSpec and GCMParameterSpec differ?
answer
- params go in cipher.init, not the transformation string
- CBC/CTR -> IvParameterSpec(iv)
- GCM -> GCMParameterSpec(tagBits, nonce)
- GCM nonce = 12 bytes, tag = 128 bits, never reuse nonce+key
- decrypt rebuilds same spec; GCM throws AEADBadTagException
basics
~10 sYou pass parameters as a third argument to cipher.init. For CBC/CTR you use IvParameterSpec(iv). For GCM you use GCMParameterSpec(tagLengthBits, nonce), which also sets the authentication tag length. The IV/nonce must be unique per encryption.
solid answer
~50 sThe transformation string only chooses algorithm/mode/padding; the IV or nonce is supplied at init via an AlgorithmParameterSpec: cipher.init(mode, key, spec). For CBC and CTR you use IvParameterSpec(byte[] iv) — just the IV bytes. For GCM you must use GCMParameterSpec(int tagLengthBits, byte[] nonce), which additionally carries the authentication-tag length (typically 128 bits). The critical rule for both: the IV/nonce must be unique per key per message — for GCM, reusing a nonce with the same key is catastrophic (it can leak the authentication key and expose plaintext XOR). So generate the IV with a SecureRandom (or a guaranteed-unique counter for GCM), prepend it to the ciphertext (it need not be secret), and read it back on decrypt to rebuild the same spec. On decrypt you must supply the exact same parameters; for GCM, doFinal throws AEADBadTagException if the tag fails, signaling tampering or wrong key/nonce.
code
java · 21 lines// --- GCM encrypt ---
byte[] nonce = new byte[12];
SecureRandom.getInstanceStrong().nextBytes(nonce);
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, nonce);
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
c.init(Cipher.ENCRYPT_MODE, key, gcmSpec);
byte[] ct = c.doFinal(plaintext); // ciphertext + 16-byte tag
// store [nonce | ct]
// --- GCM decrypt ---
c.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, nonce));
try {
byte[] pt = c.doFinal(ct); // verifies tag
} catch (AEADBadTagException e) {
// tampered / wrong key / wrong nonce -> reject
}
// --- CBC uses a different spec ---
IvParameterSpec cbcSpec = new IvParameterSpec(iv16);
Cipher cbc = Cipher.getInstance("AES/CBC/PKCS5Padding");
cbc.init(Cipher.ENCRYPT_MODE, key, cbcSpec);go deeper
Knows the IV/nonce is passed to cipher.init and must be different each time.
Can choose IvParameterSpec for CBC and GCMParameterSpec for GCM, and knows the GCM nonce is ~12 bytes with a 128-bit tag.
Explains nonce-uniqueness consequences, AAD, prepend-IV storage, and handles AEADBadTagException/BadPaddingException safely on decrypt.
Reasons about nonce-management strategies (random vs counter, birthday bounds, key rotation) and bakes safe envelope formats into shared crypto libraries.
## Where parameters fit in the lifecycle Using a `Cipher` is three steps: 1. **Select** — `Cipher.getInstance("AES/GCM/NoPadding")` chooses algorithm/mode/padding. 2. **Init** — `cipher.init(opmode, key, params)` supplies the key and the **algorithm parameters** (the IV/nonce). `opmode` is `Cipher.ENCRYPT_MODE` or `DECRYPT_MODE`. 3. **Process** — `cipher.update(...)` / `cipher.doFinal(...)` transform the data. The transformation string deliberately does **not** carry the IV/nonce, because that value changes every message. It is passed at init as an `AlgorithmParameterSpec`. ## What an IV / nonce is An **IV (initialization vector)** or **nonce** ('number used once') is a per-message value that makes encryption non-deterministic, so encrypting the same plaintext twice gives different ciphertext. It is **not secret** — it is normally stored/transmitted alongside the ciphertext — but it has strict **uniqueness** requirements. ## IvParameterSpec — for CBC and CTR ```java byte[] iv = new byte[16]; // AES block size for CBC new SecureRandom().nextBytes(iv); IvParameterSpec spec = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, key, spec); ``` `IvParameterSpec` is a thin wrapper around the IV bytes. For **CBC** the IV must be **16 bytes** (one block) and should be **unpredictable** (use `SecureRandom`) — a predictable CBC IV enables certain chosen-plaintext attacks. For **CTR** it carries the initial counter/nonce. ## GCMParameterSpec — for GCM (AEAD) GCM needs more than just the nonce: it also needs the **authentication tag length**, because GCM produces a MAC tag appended to the ciphertext. ```java byte[] nonce = new byte[12]; // 12 bytes = recommended GCM nonce size new SecureRandom().nextBytes(nonce); GCMParameterSpec spec = new GCMParameterSpec(128, nonce); // 128-bit tag cipher.init(Cipher.ENCRYPT_MODE, key, spec); // optional associated data, authenticated but not encrypted: cipher.updateAAD(headerBytes); byte[] ct = cipher.doFinal(plaintext); // ciphertext + 16-byte tag ``` Key differences from `IvParameterSpec`: - **First arg = tag length in bits** (128 is standard; 96/104/112/120/128 allowed). Shorter tags weaken integrity. - **Nonce should be 12 bytes** — the optimal/native GCM size; other lengths are hashed internally and lose the strict uniqueness guarantees. - GCM supports **AAD** (Associated Authenticated Data) via `updateAAD` — extra data that is authenticated but not encrypted (e.g., a message header). Using `IvParameterSpec` with a GCM cipher is wrong; the JCE will reject it or you lose the tag-length configuration. ## The non-negotiable rule: never reuse a nonce with the same key - **CBC:** reusing/predicting the IV degrades security and can enable chosen-plaintext attacks. - **GCM:** nonce reuse with the same key is **catastrophic** — it reveals the XOR of two plaintexts *and* can leak GCM's internal authentication subkey (the GHASH key), letting an attacker forge messages. Generate each nonce with `SecureRandom`, or use a strictly increasing counter you can guarantee never repeats per key. This is why long-lived keys + random 96-bit nonces have a usage-count limit (birthday bound ~2^32 messages). ## Storing and recovering parameters Since the IV/nonce is not secret, the common pattern is to **prepend it to the ciphertext**: ```java // encrypt: [nonce(12) | ciphertext+tag] // decrypt: read first 12 bytes as nonce, rebuild GCMParameterSpec, init DECRYPT_MODE ``` Alternatively, after init you can call `cipher.getIV()` or `cipher.getParameters()` to retrieve what the provider used (handy if you let the provider generate the IV by calling `init` without a spec). ## Decryption and failures On decrypt you must supply the **identical** parameters. For GCM, `doFinal` verifies the tag and throws `AEADBadTagException` (a subclass of `BadPaddingException`) if it fails — meaning tampering, wrong key, wrong nonce, or wrong AAD. **Do not** use any decrypted bytes before `doFinal` returns successfully; treat a thrown tag exception as 'reject the whole message'. For CBC, a wrong key/padding surfaces as `BadPaddingException` (the basis of padding-oracle attacks if you leak the difference — so handle errors uniformly). With all this, a reader can init a cipher correctly for CBC vs GCM, pick the right spec class and tag/nonce sizes, explain why nonce uniqueness matters, and handle the decrypt-side failures safely.
- What happens if you reuse the same nonce with the same key in GCM?It is catastrophic: an attacker can recover the XOR of the two plaintexts and, worse, can recover GCM's internal authentication subkey, enabling forgery of arbitrary authenticated messages. Each (key, nonce) pair must be used at most once.
- Why is GCMParameterSpec needed instead of just IvParameterSpec for GCM?GCM produces an authentication tag, so the spec must also carry the tag length (in bits). IvParameterSpec only holds the IV bytes and cannot express the tag length, so the provider can't be configured correctly for AEAD.
- Is the IV/nonce secret?No. It must be unique (and for CBC, unpredictable) but it is not confidential; it is typically prepended to the ciphertext in cleartext.
The transformation string is the recipe; the IV/nonce is the unique batch number stamped on each jar. GCMParameterSpec is a fancier label that also records a tamper-evident seal length (the tag).
saying these in an interview costs you the question
- Hardcoding a fixed IV/nonce or reusing one across messages with the same key
- Using IvParameterSpec for GCM and losing the tag-length configuration
- Treating the IV as a secret and trying to hide/derive it from the key
- Reading decrypted bytes before GCM doFinal succeeds (ignoring AEADBadTagException)
- Using a non-CSPRNG (java.util.Random) to generate IVs/nonces