# Hardcoded Symmetric Key Exposure in Fernet Encryption

Language: Python
Severity: Critical
CWE: CWE-798

## Source
5

## Flow
5

## Sink
5

## Vulnerable Code
```python
from cryptography.fernet import Fernet
import boto3

def encrypt_iot_telemetry(device_id, sensor_data):
    DEVICE_MASTER_KEY = b'zK8vN2pQrT9xL4mW6hF3jD5sA7cE1bY0uI8oP6gH2nM='
    cipher = Fernet(DEVICE_MASTER_KEY)
    payload = f"{device_id}|{sensor_data['temp']}|{sensor_data['humidity']}"
    encrypted_payload = cipher.encrypt(payload.encode())
    s3_client = boto3.client('s3')
    s3_client.put_object(Bucket='iot-telemetry-encrypted', Key=f'device_{device_id}.enc', Body=encrypted_payload)
    return {'status': 'uploaded', 'device': device_id}
```

## Explanation

The code contains a hardcoded Fernet symmetric encryption key (DEVICE_MASTER_KEY) directly embedded in the source code. This key is used to encrypt sensitive IoT telemetry data, but since it's hardcoded, anyone with access to the source code or decompiled binary can decrypt all encrypted data, rendering the encryption useless.

## Remediation

The fix removes the hardcoded encryption key and instead retrieves it securely at runtime from AWS Secrets Manager using a per-device secret path. This ensures the key is never exposed in source code, version control, or compiled artifacts, and allows for per-device key rotation without code changes.

## Secure Code
```python
from cryptography.fernet import Fernet
import boto3
import os


def get_device_encryption_key(device_id):
    """Retrieve the encryption key from AWS Secrets Manager."""
    session = boto3.session.Session()
    secrets_client = session.client(service_name='secretsmanager')
    secret_response = secrets_client.get_secret_value(SecretId=f'iot/device-master-key/{device_id}')
    return secret_response['SecretString'].encode()


def encrypt_iot_telemetry(device_id, sensor_data):
    device_key = get_device_encryption_key(device_id)
    cipher = Fernet(device_key)
    payload = f"{device_id}|{sensor_data['temp']}|{sensor_data['humidity']}"
    encrypted_payload = cipher.encrypt(payload.encode())
    s3_client = boto3.client('s3')
    s3_client.put_object(Bucket='iot-telemetry-encrypted', Key=f'device_{device_id}.enc', Body=encrypted_payload)
    return {'status': 'uploaded', 'device': device_id}
```
