# AES-CTR Nonce Reuse Leading to Keystream Recovery

Language: Python
Severity: High
CWE: CWE-323

## Source
7

## Flow
7-10

## Sink
10

## Vulnerable Code
```python
from Crypto.Cipher import AES
import os

class IoTSensorEncryptor:
    def __init__(self):
        self.device_key = os.urandom(32)
        self.static_nonce = os.urandom(8)
    
    def transmit_telemetry(self, sensor_data):
        cipher = AES.new(self.device_key, AES.MODE_CTR, nonce=self.static_nonce)
        encrypted_payload = cipher.encrypt(sensor_data.encode())
        return encrypted_payload
    
    def send_batch_readings(self, readings_list):
        encrypted_batch = []
        for reading in readings_list:
            encrypted_batch.append(self.transmit_telemetry(reading))
        return encrypted_batch
```

## Explanation

The code initializes a static nonce once in __init__ (line 7) and reuses it for every encryption operation in transmit_telemetry (line 10). In AES-CTR mode, reusing the same nonce with the same key generates identical keystreams, allowing attackers to XOR multiple ciphertexts together to recover plaintext without knowing the key.

## Remediation

The fix removes the static nonce from the class initialization and instead generates a fresh random nonce for each encryption operation in transmit_telemetry. The nonce is prepended to the ciphertext so the receiver can extract it for decryption. This ensures a unique keystream is produced for every message, preventing the XOR attack on multiple ciphertexts.

## Secure Code
```python
from Crypto.Cipher import AES
import os

class IoTSensorEncryptor:
    def __init__(self):
        self.device_key = os.urandom(32)
    
    def transmit_telemetry(self, sensor_data):
        nonce = os.urandom(8)
        cipher = AES.new(self.device_key, AES.MODE_CTR, nonce=nonce)
        encrypted_payload = cipher.encrypt(sensor_data.encode())
        return nonce + encrypted_payload
    
    def send_batch_readings(self, readings_list):
        encrypted_batch = []
        for reading in readings_list:
            encrypted_batch.append(self.transmit_telemetry(reading))
        return encrypted_batch
```
