# Timing Attack via hmac.compare_digest Misuse

Language: Python
Severity: High
CWE: CWE-208

## Source
7

## Flow
6-7-8

## Sink
8

## Vulnerable Code
```python
import hmac
import hashlib
from flask import request, jsonify

def verify_iot_device_signature(device_id, payload, signature):
    secret_key = get_device_secret(device_id)
    expected_sig = hashlib.sha256(f"{device_id}:{payload}:{secret_key}".encode()).hexdigest()
    if signature == expected_sig:
        return jsonify({"status": "authenticated", "device_id": device_id})
    return jsonify({"status": "unauthorized"}), 401

@app.route('/iot/telemetry', methods=['POST'])
def receive_telemetry():
    dev_id = request.headers.get('X-Device-ID')
    sig = request.headers.get('X-Signature')
    data = request.get_json()
    return verify_iot_device_signature(dev_id, data.get('payload'), sig)
```

## Explanation

The code uses string equality comparison (==) instead of constant-time comparison (hmac.compare_digest) to verify signatures. This allows attackers to perform timing attacks by measuring response times to determine correct signature bytes one at a time, eventually reconstructing valid signatures without knowing the secret key.

## Remediation

The fix replaces the vulnerable string equality comparison (==) with hmac.compare_digest(), which performs constant-time comparison to prevent timing attacks. Additionally, the signature computation was changed from a plain SHA-256 hash (which included the secret in the message) to a proper HMAC construction using hmac.new(), which is the cryptographically correct way to create keyed message authentication codes. Input validation was also added to prevent NoneType errors.

## Secure Code
```python
import hmac
import hashlib
from flask import request, jsonify

def verify_iot_device_signature(device_id, payload, signature):
    secret_key = get_device_secret(device_id)
    expected_sig = hmac.new(secret_key.encode(), f"{device_id}:{payload}".encode(), hashlib.sha256).hexdigest()
    if hmac.compare_digest(signature, expected_sig):
        return jsonify({"status": "authenticated", "device_id": device_id})
    return jsonify({"status": "unauthorized"}), 401

@app.route('/iot/telemetry', methods=['POST'])
def receive_telemetry():
    dev_id = request.headers.get('X-Device-ID')
    sig = request.headers.get('X-Signature')
    if not dev_id or not sig:
        return jsonify({"status": "unauthorized"}), 401
    data = request.get_json()
    if not data or not data.get('payload'):
        return jsonify({"status": "bad_request"}), 400
    return verify_iot_device_signature(dev_id, data.get('payload'), sig)
```
