> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Keystore Security

> Security properties, threats, and best practices for Web3 Secret Storage

## Overview

Keystore security relies on password strength, KDF parameters, and proper handling. Understanding the security model helps make informed decisions about parameter selection and usage patterns.

## Security Properties

### What Keystore Protects

* **Private key confidentiality**: Key cannot be recovered without password
* **Password verification**: Wrong passwords are detected via MAC
* **Data integrity**: Modifications to ciphertext are detected

### What Keystore Does NOT Protect

* **Weak passwords**: Low-entropy passwords can be brute-forced
* **Memory attacks**: Key exists in plaintext in memory during use
* **Side-channel attacks**: Timing, power analysis (mostly mitigated)
* **Keyloggers/malware**: Password can be captured during entry

## Password Security

### Password Strength Requirements

The keystore is only as secure as the password:

| Password Type           | Entropy    | Time to Crack (scrypt N=262144) |
| ----------------------- | ---------- | ------------------------------- |
| "password"              | \~20 bits  | Instant                         |
| "correcthorse"          | \~40 bits  | Hours                           |
| "correct-horse-battery" | \~60 bits  | Years                           |
| Random 16 chars         | \~80 bits  | Centuries                       |
| Random 24 chars         | \~120 bits | Heat death of universe          |

**Recommendations:**

* Minimum 16 characters
* Use passphrase (4+ random words) or random characters
* Include mixed case, numbers, symbols
* Never reuse passwords across keystores

### Password Attacks

**Dictionary Attack:**

```
Attacker tries common passwords:
password, 123456, qwerty, ...
```

**Mitigation:** Use random passwords, avoid dictionary words.

**Brute Force Attack:**

```
Attacker tries all combinations:
a, b, c, ..., aa, ab, ac, ...
```

**Mitigation:** Use long passwords (16+ chars).

**Rainbow Table Attack:**

```
Attacker uses precomputed hashes
```

**Mitigation:** Salt prevents this (built into keystore).

## KDF Security

### Scrypt (Recommended)

Scrypt is **memory-hard**, making it resistant to parallel attacks:

```typescript theme={null}
// Default parameters
const keystore = await Keystore.encrypt(privateKey, password, {
  kdf: 'scrypt',
  scryptN: 262144,  // 2^18 - CPU/memory cost
  scryptR: 8,       // Block size
  scryptP: 1        // Parallelization
});
```

**Security properties:**

* **Memory-hard**: Requires \~256 MB RAM per attempt
* **GPU-resistant**: Memory bandwidth limits parallelization
* **ASIC-resistant**: Hard to build specialized hardware

**Memory requirement:** `128 * N * r * p` bytes

* Default: `128 * 262144 * 8 * 1 = 256 MB`

### PBKDF2 (Less Secure)

PBKDF2 is **not memory-hard**, making it vulnerable to parallel attacks:

```typescript theme={null}
const keystore = await Keystore.encrypt(privateKey, password, {
  kdf: 'pbkdf2',
  pbkdf2C: 262144  // Iterations
});
```

**Security concerns:**

* **GPU-parallelizable**: Attackers can try millions of passwords/second
* **ASIC-parallelizable**: Custom hardware can be built
* **Lower security per iteration**: Compared to scrypt

<Warning>
  Use PBKDF2 only when scrypt is unavailable or too slow. Increase iterations (1M+) for better security.
</Warning>

### KDF Parameter Guidelines

| Use Case     | KDF    | Parameters | Time    | Security  |
| ------------ | ------ | ---------- | ------- | --------- |
| Testing      | Scrypt | N=1024     | \~50ms  | Low       |
| Mobile       | Scrypt | N=16384    | \~200ms | Medium    |
| Desktop      | Scrypt | N=262144   | \~3s    | High      |
| Cold storage | Scrypt | N=1048576  | \~15s   | Very High |
| Legacy       | PBKDF2 | c=1000000  | \~2s    | Medium    |

## Attack Scenarios

### Stolen Keystore File

**Scenario:** Attacker obtains keystore JSON file.

**Attack:** Offline password cracking

```
For each candidate password:
  1. Derive key using KDF
  2. Compute MAC
  3. Compare with stored MAC
```

**Defense:**

* Strong password (16+ chars, high entropy)
* High KDF parameters (N=262144+)
* Don't store keystores on shared/cloud storage without additional encryption

### Timing Attack on MAC

**Scenario:** Attacker measures time to verify passwords.

**Attack:** Learn partial MAC by timing differences

```
password1: 0.100s (first byte wrong)
password2: 0.101s (first byte correct)
```

**Defense:** Constant-time MAC comparison (built-in)

```typescript theme={null}
// All comparisons take the same time
function constantTimeEqual(a, b) {
  let result = 0;
  for (let i = 0; i < a.length; i++) {
    result |= a[i] ^ b[i];  // No early exit
  }
  return result === 0;
}
```

### Memory Dump

**Scenario:** Attacker dumps process memory while wallet is unlocked.

**Attack:** Find private key in memory

**Defense:**

* Clear private key from memory when done
* Use hardware wallets for high-value keys
* Minimize time wallet is unlocked

```typescript theme={null}
// Best effort memory clearing (not guaranteed in JS)
function secureUse(keystore, password, callback) {
  let privateKey;
  try {
    privateKey = Keystore.decrypt(keystore, password);
    callback(privateKey);
  } finally {
    if (privateKey) {
      privateKey.fill(0);  // Zero out memory
    }
  }
}
```

### IV Corruption Attack

**Scenario:** Attacker modifies IV without detection.

**Attack:** Causes wrong decryption output

```
MAC = keccak256(macKey || ciphertext)
IV is NOT included in MAC!
```

**Defense:** Always verify decrypted key produces expected address

```typescript theme={null}
function safeDecrypt(keystore, password, expectedAddress) {
  const privateKey = Keystore.decrypt(keystore, password);

  const derivedAddress = deriveAddress(privateKey);
  if (derivedAddress !== expectedAddress) {
    privateKey.fill(0);  // Clear
    throw new Error('Keystore corrupted: address mismatch');
  }

  return privateKey;
}
```

## Best Practices

### Password Management

```typescript theme={null}
// DO: Use high-entropy passwords
const password = generateSecurePassword(24);  // Random 24 chars

// DON'T: Use weak passwords
const password = 'password123';  // Crackable in seconds
```

### KDF Parameter Selection

```typescript theme={null}
// DO: Use appropriate parameters for use case
const keystore = await Keystore.encrypt(privateKey, password, {
  kdf: 'scrypt',
  scryptN: 262144  // Production default
});

// DON'T: Use weak parameters in production
const keystore = await Keystore.encrypt(privateKey, password, {
  scryptN: 1024  // Only for testing!
});
```

### Keystore Storage

```typescript theme={null}
// DO: Encrypt keystore file at rest
await encryptFile(keystoreJson, filePassword);

// DO: Use secure storage APIs
await SecureStore.setItemAsync('keystore', keystoreJson);

// DON'T: Store in plaintext on cloud storage
await cloudStorage.upload('keystore.json', keystoreJson);
```

### Keystore Handling

```typescript theme={null}
// DO: Clear sensitive data
const privateKey = Keystore.decrypt(keystore, password);
try {
  // Use private key
} finally {
  privateKey.fill(0);  // Clear
}

// DON'T: Leave private key in memory
const privateKey = Keystore.decrypt(keystore, password);
// privateKey sits in memory indefinitely
```

### Error Handling

```typescript theme={null}
// DO: Generic error messages to users
catch (error) {
  console.log('Unable to unlock wallet');  // Don't reveal specifics
}

// DON'T: Reveal attack surface
catch (error) {
  console.log(error.message);  // "Invalid MAC" reveals timing info
}
```

## Security Checklist

Before deploying keystore encryption:

* [ ] Using strong passwords (16+ chars, high entropy)
* [ ] Using scrypt KDF (not PBKDF2) when possible
* [ ] KDF parameters appropriate for use case (N >= 16384)
* [ ] Keystore files encrypted at rest (if stored)
* [ ] Private keys cleared from memory after use
* [ ] Address verification after decryption
* [ ] Generic error messages to users
* [ ] No keystores in version control
* [ ] No keystores on unencrypted cloud storage
* [ ] Backup procedures documented and tested

## Compliance

### Standards Alignment

* **Web3 Secret Storage v3**: Full compliance
* **NIST SP 800-132**: PBKDF2 usage follows recommendations
* **OWASP**: Password hashing guidelines followed

### Known Limitations

1. **IV not in MAC**: Corrupted IV produces wrong output without error
2. **No key stretching metadata**: Can't verify KDF parameters were followed
3. **Password in memory**: Brief exposure during KDF computation

## Hardware Wallet Alternative

For high-value keys, consider hardware wallets instead of keystores:

| Feature            | Keystore             | Hardware Wallet         |
| ------------------ | -------------------- | ----------------------- |
| Key exposure       | In memory during use | Never leaves device     |
| Password attack    | Vulnerable           | PIN with attempt limits |
| Malware protection | Limited              | Strong                  |
| Cost               | Free                 | \$50-200                |
| Backup             | File + password      | Recovery phrase         |

<Tip>
  Use keystores for convenience (hot wallets) and hardware wallets for security (cold storage).
</Tip>

## References

* [Web3 Secret Storage Definition](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition)
* [Scrypt Paper](https://www.tarsnap.com/scrypt/scrypt.pdf)
* [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
* [NIST SP 800-132 (PBKDF)](https://csrc.nist.gov/publications/detail/sp/800-132/final)
