Why is this an issue?

When encrypting data with Counter (CTR) derived block cipher modes of operation, it is essential not to reuse the same initialization vector (IV) with a given key, such IV is called a "nonce" (number used only once). Galois/Counter (GCM) and Counter with Cipher Block Chaining-Message Authentication Code (CCM) are both CTR-based modes of operation.

An attacker, who has knowledge of one plaintext (original content) and ciphertext (encrypted content) pair, is able to retrieve the corresponding plaintext of any other ciphertext generated with the same IV and key. It also drastically decreases the key recovery computational complexity by downgrading it to a simpler polynomial root-finding problem.

When using GCM, NIST recommends a 96 bit length nonce using a 'Deterministic' approach or at least 96 bits using a 'Random Bit Generator (RBG)'. The 'Deterministic' construction involves a counter, which increments per encryption process. The 'RBG' construction, as the name suggests, generates the nonce using a random bit generator. Collision probabilities (nonce-key pair reuse) using the 'RBG-based' approach require a shorter key rotation period, 2^32 maximum invocations per key.

Noncompliant code example

public void encrypt(byte[] key, byte[] ptxt) {
    byte[] bytesIV = "7cVgr5cbdCZV".getBytes("UTF-8"); // The initialization vector is a static value

    GCMParameterSpec gcmSpec    = new GCMParameterSpec(128, nonce); // The initialization vector is configured here
    SecretKeySpec keySpec       = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);  // Noncompliant
}

Compliant solution

public void encrypt(byte[] key, byte[] ptxt) {
    SecureRandom random = new SecureRandom();
    byte[] bytesIV = new byte[12];
    random.nextBytes(bytesIV); // Random 96 bit IV

    GCMParameterSpec gcmSpec    = new GCMParameterSpec(128, nonce);
    SecretKeySpec keySpec       = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
}

Resources