Fixed initialization vectors

Fixed or reused initialization vectors

Description

CBC requires an unpredictable IV, while GCM requires that an IV never be reused with the same key. Reusing a key and IV, using a zero-filled IV, or deriving it from a fixed string can reveal repeating ciphertext patterns, particularly in the first CBC block. In GCM, nonce reuse undermines both confidentiality and integrity: an attacker can relate plaintexts through the XOR of ciphertexts and may forge authentication tags.

Potential impact

  • Pattern disclosure: with the same CBC key and IV, identical first plaintext blocks produce identical ciphertext blocks.
  • Plaintext relationships: GCM ciphertexts produced with the same key and IV can reveal relationships between their plaintexts.
  • Forgery: repeated GCM nonces can compromise authentication and allow valid tags to be forged.
  • Message correlation: repeated patterns can reveal relationships between requests and responses. Replay prevention requires separate protocol controls.

Remediation

  • Generate a fresh IV for each encryption. Use SecureRandom.nextBytes(iv) for unpredictable random IVs; 12 bytes (96 bits) is the usual recommendation for GCM.
  • Do not use an array allocated by new byte[N] while it is still zero-filled, or use constant-derived values such as "constant".getBytes() as IVs.
  • Store or transmit the IV with the ciphertext and prevent reuse under the same key. Random IVs can collide, so manage per-key usage limits and key rotation as well.
  • Where appropriate, consider a nonce-misuse-resistant mode such as AES-GCM-SIV. Unique nonces remain the basic operating principle.
  • Use the required IV length: 16 bytes for AES-CBC and normally 12 bytes for GCM.

Examples

Before

java
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class StaticIvBad {
    // BAD: 고정(제로) IV 사용으로 GCM 보안 붕괴
    public byte[] encrypt(byte[] key, byte[] plaintext) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        SecretKeySpec sk = new SecretKeySpec(key, "AES");
        byte[] iv = new byte[12]; // 모든 바이트가 0 -> 예측 가능
        GCMParameterSpec spec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.ENCRYPT_MODE, sk, spec);
        return cipher.doFinal(plaintext);
    }
}

After

java
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.security.SecureRandom;

public class RandomIvGood {
    // GOOD: 매번 SecureRandom으로 새 IV 생성하고, IV를 암호문과 함께 저장/전달
    public byte[] encrypt(byte[] key, byte[] plaintext) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        SecretKeySpec sk = new SecretKeySpec(key, "AES");
        byte[] iv = new byte[12]; // GCM 권장 12바이트
        SecureRandom.getInstanceStrong().nextBytes(iv);
        GCMParameterSpec spec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.ENCRYPT_MODE, sk, spec);
        byte[] ciphertext = cipher.doFinal(plaintext);
        // IV || C 형식으로 결합해 저장/전달
        ByteBuffer out = ByteBuffer.allocate(iv.length + ciphertext.length);
        out.put(iv).put(ciphertext);
        return out.array();
    }
}

Explanation:

  • Before: Reusing the all-zero IV under the same GCM key repeats the nonce, exposing plaintext relationships and risking tag forgery. Fixed IVs also expose patterns in CBC.
  • After: SecureRandom generates a 12-byte IV for each encryption, and the IV is stored or transmitted with the ciphertext. Random generation does not guarantee absolute uniqueness; limit per-key usage and prevent IV reuse.

References