# AES-GCM Nonce Reuse in Authenticated Encryption

Language: Python
Severity: Critical
CWE: CWE-323

## Source
7

## Flow
7-12, 7-17

## Sink
12, 17

## Vulnerable Code
```python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

class IoTDeviceSecureComm:
    def __init__(self):
        self.master_key = AESGCM.generate_key(bit_length=256)
        self.cipher = AESGCM(self.master_key)
        self.device_nonce = os.urandom(12)
    
    def encrypt_sensor_telemetry(self, device_id, temperature, humidity, pressure):
        telemetry_payload = f"{device_id}|{temperature}|{humidity}|{pressure}".encode()
        encrypted_data = self.cipher.encrypt(self.device_nonce, telemetry_payload, None)
        return encrypted_data
    
    def encrypt_command(self, device_id, command, params):
        cmd_payload = f"CMD:{device_id}:{command}:{params}".encode()
        encrypted_cmd = self.cipher.encrypt(self.device_nonce, cmd_payload, None)
        return encrypted_cmd

iot_comm = IoTDeviceSecureComm()
telemetry1 = iot_comm.encrypt_sensor_telemetry("SENSOR_001", 22.5, 65.3, 1013.2)
telemetry2 = iot_comm.encrypt_sensor_telemetry("SENSOR_001", 23.1, 64.8, 1012.9)
command = iot_comm.encrypt_command("SENSOR_001", "REBOOT", "force=true")
```

## Explanation

The code reuses the same nonce (self.device_nonce) for multiple AES-GCM encryption operations. AES-GCM is a nonce-based authenticated encryption scheme that requires a unique nonce for every encryption with the same key. Reusing a nonce catastrophically breaks the security guarantees, allowing attackers to recover the authentication key and potentially decrypt messages or forge authenticated ciphertexts.

## Remediation

The fix removes the cached instance-level nonce and instead generates a fresh random 12-byte nonce for every encryption operation via a dedicated `_generate_nonce()` method. The nonce is prepended to the ciphertext so the receiver can extract it for decryption, which is the standard practice for AES-GCM. This ensures that no two encryption operations ever reuse the same nonce with the same key.

## Secure Code
```python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

class IoTDeviceSecureComm:
    def __init__(self):
        self.master_key = AESGCM.generate_key(bit_length=256)
        self.cipher = AESGCM(self.master_key)
    
    def _generate_nonce(self):
        return os.urandom(12)
    
    def encrypt_sensor_telemetry(self, device_id, temperature, humidity, pressure):
        telemetry_payload = f"{device_id}|{temperature}|{humidity}|{pressure}".encode()
        nonce = self._generate_nonce()
        encrypted_data = self.cipher.encrypt(nonce, telemetry_payload, None)
        return nonce + encrypted_data
    
    def encrypt_command(self, device_id, command, params):
        cmd_payload = f"CMD:{device_id}:{command}:{params}".encode()
        nonce = self._generate_nonce()
        encrypted_cmd = self.cipher.encrypt(nonce, cmd_payload, None)
        return nonce + encrypted_cmd
    
    def decrypt_message(self, encrypted_message):
        nonce = encrypted_message[:12]
        ciphertext = encrypted_message[12:]
        return self.cipher.decrypt(nonce, ciphertext, None)

iot_comm = IoTDeviceSecureComm()
telemetry1 = iot_comm.encrypt_sensor_telemetry("SENSOR_001", 22.5, 65.3, 1013.2)
telemetry2 = iot_comm.encrypt_sensor_telemetry("SENSOR_001", 23.1, 64.8, 1012.9)
command = iot_comm.encrypt_command("SENSOR_001", "REBOOT", "force=true")
```
