{"title":"AES-GCM Nonce Reuse Leading to Confidentiality and Integrity Breaks","language":"Python","severity":"Critical","cwe":"CWE-323","source_lines":[7],"flow_lines":[7,13],"sink_lines":[13],"vulnerable_code":"from cryptography.hazmat.primitives.ciphers.aead import AESGCM\nimport os\n\nclass IoTDeviceProvisioner:\n    def __init__(self):\n        self.master_key = AESGCM.generate_key(bit_length=256)\n        self.static_nonce = os.urandom(12)\n    \n    def encrypt_device_credentials(self, device_id, wifi_ssid, wifi_password):\n        cipher = AESGCM(self.master_key)\n        payload = f\"{device_id}|{wifi_ssid}|{wifi_password}\".encode()\n        encrypted_creds = cipher.encrypt(self.static_nonce, payload, None)\n        return encrypted_creds.hex()","explanation":"The code uses a static nonce (self.static_nonce) that is generated once in __init__ and reused for every encryption operation in encrypt_device_credentials. AES-GCM requires a unique nonce for each encryption with the same key, otherwise it breaks confidentiality and integrity guarantees, allowing attackers to decrypt messages and forge authenticated ciphertexts.","remediation":"The fix removes the static nonce stored as an instance variable and instead generates a fresh random 12-byte nonce for each encryption call. The nonce is prepended to the ciphertext so the decrypting party can extract it. This ensures that each encryption operation uses a unique nonce, preserving AES-GCM's confidentiality and integrity guarantees.","secure_code":"from cryptography.hazmat.primitives.ciphers.aead import AESGCM\nimport os\n\nclass IoTDeviceProvisioner:\n    def __init__(self):\n        self.master_key = AESGCM.generate_key(bit_length=256)\n    \n    def encrypt_device_credentials(self, device_id, wifi_ssid, wifi_password):\n        cipher = AESGCM(self.master_key)\n        nonce = os.urandom(12)\n        payload = f\"{device_id}|{wifi_ssid}|{wifi_password}\".encode()\n        encrypted_creds = cipher.encrypt(nonce, payload, None)\n        return (nonce + encrypted_creds).hex()"}