# SHA-1 Length Extension in Homemade MAC Verification

Language: Python
Severity: Critical
CWE: CWE-327

## Source
9

## Flow
9-11

## Sink
11

## Vulnerable Code
```python
import hashlib

def verify_iot_command(device_id, command, signature, secret_key):
    expected_sig = hashlib.sha1((secret_key + device_id + command).encode()).hexdigest()
    if signature == expected_sig:
        return True
    return False

def execute_device_action(device_id, command, signature):
    SECRET = "iot_master_key_2024"
    if verify_iot_command(device_id, command, signature, SECRET):
        exec(command)
        return {"status": "executed", "device": device_id}
    return {"status": "unauthorized"}
```

## Explanation

The code uses a homemade MAC scheme with SHA-1 concatenation (secret+data) which is vulnerable to length extension attacks, allowing attackers to append malicious commands without knowing the secret key. Additionally, the exec() function directly executes arbitrary commands without sanitization, enabling command injection once signature validation is bypassed.

## Remediation

The fix replaces the vulnerable SHA-1 prefix-based MAC with HMAC-SHA256, which is not susceptible to length extension attacks and uses constant-time comparison via hmac.compare_digest to prevent timing attacks. The dangerous exec() call is replaced with a whitelist of allowed commands mapped to safe handler functions, eliminating arbitrary code execution entirely.

## Secure Code
```python
import hmac
import hashlib

ALLOWED_COMMANDS = {
    "status": lambda device_id: {"status": "online", "device": device_id},
    "reboot": lambda device_id: {"status": "rebooting", "device": device_id},
    "shutdown": lambda device_id: {"status": "shutting_down", "device": device_id},
    "get_temperature": lambda device_id: {"status": "temp_read", "device": device_id},
    "toggle_power": lambda device_id: {"status": "power_toggled", "device": device_id}
}

def verify_iot_command(device_id, command, signature, secret_key):
    message = (device_id + command).encode()
    expected_sig = hmac.new(secret_key.encode(), message, hashlib.sha256).hexdigest()
    if hmac.compare_digest(signature, expected_sig):
        return True
    return False

def execute_device_action(device_id, command, signature):
    SECRET = "iot_master_key_2024"
    if not device_id.isalnum():
        return {"status": "invalid_device_id"}
    command = command.strip()
    if command not in ALLOWED_COMMANDS:
        return {"status": "invalid_command", "allowed": list(ALLOWED_COMMANDS.keys())}
    if verify_iot_command(device_id, command, signature, SECRET):
        result = ALLOWED_COMMANDS[command](device_id)
        return {"status": "executed", "device": device_id, "result": result}
    return {"status": "unauthorized"}
```
