{"title":"AES-GCM Nonce Reuse Leading to Keystream Disclosure","language":"Python","severity":"Critical","cwe":"CWE-323","source_lines":[8],"flow_lines":[8,12],"sink_lines":[12],"vulnerable_code":"from cryptography.hazmat.primitives.ciphers.aead import AESGCM\nimport os\n\nclass IoTSensorEncryptor:\n    def __init__(self):\n        self.master_key = AESGCM.generate_key(bit_length=256)\n        self.cipher = AESGCM(self.master_key)\n        self.device_nonce = os.urandom(12)\n    \n    def encrypt_telemetry(self, sensor_data, device_id):\n        associated = f\"device:{device_id}\".encode()\n        encrypted = self.cipher.encrypt(self.device_nonce, sensor_data.encode(), associated)\n        return encrypted.hex()\n    \n    def transmit_batch(self, readings):\n        return [self.encrypt_telemetry(reading['temp'], reading['id']) for reading in readings]","explanation":"The nonce is generated once during initialization (line 8) and stored as an instance variable, then reused for every encryption operation (line 12). AES-GCM requires a unique nonce for each encryption with the same key; reusing nonces catastrophically breaks confidentiality by allowing attackers to recover the keystream and decrypt all messages.","remediation":"The fix generates a fresh random 12-byte nonce for each encryption operation instead of reusing a single instance-level nonce. The nonce is prepended to the ciphertext so the receiver can extract it for decryption. This ensures AES-GCM's requirement of nonce uniqueness per key is satisfied.","secure_code":"from cryptography.hazmat.primitives.ciphers.aead import AESGCM\nimport os\n\nclass IoTSensorEncryptor:\n    def __init__(self):\n        self.master_key = AESGCM.generate_key(bit_length=256)\n        self.cipher = AESGCM(self.master_key)\n    \n    def encrypt_telemetry(self, sensor_data, device_id):\n        nonce = os.urandom(12)\n        associated = f\"device:{device_id}\".encode()\n        encrypted = self.cipher.encrypt(nonce, sensor_data.encode(), associated)\n        return (nonce + encrypted).hex()\n    \n    def transmit_batch(self, readings):\n        return [self.encrypt_telemetry(reading['temp'], reading['id']) for reading in readings]"}