In encryption, when Cipher Block Chaining (CBC) is used, the Initialization Vector (IV) must be random and unpredictable. Otherwise, the encrypted value is vulnerable to crypto-analysis attacks such as the "Chosen-Plaintext Attack".

An IV value should be associated to one, and only one encryption cycle, because the IV's purpose is to ensure that the same plaintext encrypted twice will yield two different ciphertexts.

To that end, IV's should be:

This rule raises an issue when the IV is hard-coded.

Noncompliant Code Example

For PyCryptodome module:

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad

static_vector = b'x' * AES.block_size
cipher = AES.new(key, AES.MODE_CBC, static_vector)
cipher.encrypt(pad(data, AES.block_size))  # Noncompliant

For cryptography module:

from os import urandom
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

static_vector = b'x' * 16
cipher = Cipher(algorithms.AES(key), modes.CBC(static_vector))
cipher.encryptor()  # Noncompliant

Compliant Solution

For PyCryptodome module:

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad

random_vector = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, random_vector)
cipher.encrypt(pad(data, AES.block_size))

For cryptography module:

from os import urandom
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

random_vector = urandom(16)
cipher = Cipher(algorithms.AES(key), modes.CBC(random_vector))
cipher.encryptor()

See