Non Random IV With CBC Mode

ID

csharp.non_random_iv_with_cbc_mode

Severity

critical

Resource

Predictability

Language

CSharp

Tags

CWE:329, NIST.SP.800-53, OWASP:2021:A2, PCI-DSS:6.5.1

Description

Use of a non-random Initialization Vector (IV) with Cipher Block Chaining (CBC) mode can result in predictable ciphertext, exposing encrypted data to potential attacks. Ensure IVs are generated using a secure random number generator.

Rationale

Cipher Block Chaining (CBC) mode combines using XOR blocks of plaintext with the previous ciphertext block before encryption, thus requiring an initialization vector (IV) for the first block. If IVs are reused, then identical plaintexts would be encrypted to identical ciphertexts. However, even if IVs are not identical but are predictable, then they still break the security of CBC mode against Chosen Plaintext Attacks (CPA). To avoid this, use a fresh random IV for each message.

The same weakness with IVs happens with other modes like Cipher Feedback (CFB). But

Using a non-random or predictable IV with CBC mode can undermine the security of the encryption scheme, leading to potential vulnerabilities like distinguishing attacks or message deduplication attacks.

Poorly implemented IV handling often derives from static values or predictable patterns, compromising the confidentiality of sensitive data.

To clarify, consider the following C# code sample:

public class AESExample
{
    private static readonly byte[] HardcodedIV = Encoding.UTF8.GetBytes("MyHardcodedIV123"); // 16 bytes

    public static byte[] Encrypt(string plaintext, byte[] Key)
    {
        // ... checks ommitted
        byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);

        using (Aes aes = Aes.Create())
        {
            aes.Key = Key;
            aes.IV = HardcodedIV; // FLAW : Non-random IV
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            using (var encryptor = aes.CreateEncryptor())
            {
                return encryptor.TransformFinalBlock(plaintextBytes, 0, plaintextBytes.Length);
            }
        }
    }
}

In this code, a static and predictable IV is used for AES encryption in CBC mode, significantly weakening the cryptographic strength of the system.

Remediation

Modern cryptography prefers in general Authenticated Encryption with Associated Data (AEAD) schemes, which provide both confidentiality and integrity, over classical confidentiality-only schemes, such as CBC, which are vulnerable to padding oracle attacks. First and foremost, use AEAD schemes such as AES-GCM or XChaCha20-Poly1305 if possible.

Modes such as Galois/Counter Mode (GCM) fail spectacularly when the IV (also called nonce) is reused: A single repeated nonce allows an adversary to recover the authentication subkey and learn the XOR of the two messages with the same nonce. If you use GCM, therefore, make sure to use a fresh nonce for each message. For details on generating fresh nonces for GCM, read NIST SP 800-38D.

To remediate vulnerable code using non-random IVs in CBC mode, always generate the IV using a secure random number generator for each encryption operation. The IV must be unpredictable and unique to mitigate the threats posed by static, reused, or predictable IVs. Always ensure the IV is stored or transmitted alongside the ciphertext, as it is needed for decryption.

For the previous C# example, you can use RandomNumberGenerator to create appropriate IVs:

    public static (byte[] IV, byte[] Ciphertext) EncryptWithRandomIV(string plaintext, byte[] Key)
    {
        // ... checks ommitted
        byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);

        using (Aes aes = Aes.Create())
        {
            aes.Key = Key;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            // FIXED : Let the library generate random IV
            aes.GenerateIV();
            byte[] iv = aes.IV;

            using (ICryptoTransform encryptor = aes.CreateEncryptor())
            {
                byte[] ciphertext = encryptor.TransformFinalBlock(plaintextBytes, 0, plaintextBytes.Length);
                // The random IV is needed for decryption
                return (iv, ciphertext);
            }
        }
    }

Aes.GenerateIV() uses a cryptographically secure random number generator to generate a random unique IV. Note that the IV must be set during decryption and needs to be passed (albeit in clear text) alongside the ciphertext.

References