# Cryptographic Weakness via Hardcoded IV in AES-CBC Encryption

Language: Python
Severity: High
CWE: CWE-330

## Source
9

## Flow
9-11

## Sink
11

## Vulnerable Code
```python
from Crypto.Cipher import AES
import base64
def encrypt_telemetry_payload(sensor_data: str, dev_secret: bytes) -> str:
    FIXED_IV = b'\x1a\x2b\x3c\x4d\x5e\x6f\x7a\x8b\x9c\xad\xbe\xcf\xd0\xe1\xf2\x03'
    padded = sensor_data.ljust((len(sensor_data) // 16 + 1) * 16)
    cipher = AES.new(dev_secret, AES.MODE_CBC, FIXED_IV)
    raw_ct = cipher.encrypt(padded.encode('utf-8'))
    return base64.b64encode(raw_ct).decode('utf-8')
```

## Explanation

A hardcoded, static IV (FIXED_IV) is defined at line 4 and directly passed to AES.new() at line 6 for every encryption operation. In AES-CBC mode, reusing the same IV with the same key across multiple encryptions breaks semantic security: identical plaintext blocks produce identical ciphertext blocks, enabling pattern analysis, replay attacks, and potentially plaintext recovery across all IoT devices sharing this codebase.

## Remediation

The fix replaces the hardcoded static IV with a cryptographically secure random IV generated via get_random_bytes(16) on every encryption call. The random IV is prepended to the ciphertext before base64 encoding so the decryption side can extract the first 16 bytes as the IV. This ensures that even identical plaintexts produce different ciphertexts, restoring semantic security for AES-CBC mode.

## Secure Code
```python
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import base64

def encrypt_telemetry_payload(sensor_data: str, dev_secret: bytes) -> str:
    iv = get_random_bytes(16)
    padded = sensor_data.ljust((len(sensor_data) // 16 + 1) * 16)
    cipher = AES.new(dev_secret, AES.MODE_CBC, iv)
    raw_ct = cipher.encrypt(padded.encode('utf-8'))
    return base64.b64encode(iv + raw_ct).decode('utf-8')
```
