# Insecure Password Hashing via Unsalted MD5

Language: Python
Severity: High
CWE: CWE-327

## Source
9

## Flow
9-11

## Sink
11

## Vulnerable Code
```python
import hashlib
import boto3
from datetime import datetime

def provision_iot_device_credentials(device_id, admin_pin, device_type):
    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
    iot_table = dynamodb.Table('IoTDeviceRegistry')
    pin_hash = hashlib.md5(admin_pin.encode()).hexdigest()
    device_record = {
        'DeviceID': device_id,
        'DeviceType': device_type,
        'AdminPinHash': pin_hash,
        'ProvisionedAt': datetime.utcnow().isoformat(),
        'Status': 'active'
    }
    iot_table.put_item(Item=device_record)
    return {'success': True, 'device_id': device_id, 'hash': pin_hash}
```

## Explanation

The code uses MD5 without salt to hash sensitive admin PINs. MD5 is cryptographically broken and vulnerable to rainbow table attacks and collision attacks. Without salting, identical PINs produce identical hashes, enabling attackers who gain database access to quickly crack passwords using precomputed hash tables.

## Remediation

Replaced insecure unsalted MD5 hashing with bcrypt, which automatically generates a unique salt per hash and uses a computationally expensive key derivation function (with 12 rounds of work factor) that resists brute-force and rainbow table attacks. The hash is also no longer returned in the response to avoid unnecessary exposure of sensitive data.

## Secure Code
```python
import bcrypt
import boto3
from datetime import datetime

def provision_iot_device_credentials(device_id, admin_pin, device_type):
    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
    iot_table = dynamodb.Table('IoTDeviceRegistry')
    pin_hash = bcrypt.hashpw(admin_pin.encode(), bcrypt.gensalt(rounds=12)).decode('utf-8')
    device_record = {
        'DeviceID': device_id,
        'DeviceType': device_type,
        'AdminPinHash': pin_hash,
        'ProvisionedAt': datetime.utcnow().isoformat(),
        'Status': 'active'
    }
    iot_table.put_item(Item=device_record)
    return {'success': True, 'device_id': device_id}
```
