diff --git a/BestPractices.md b/BestPractices.md new file mode 100644 index 0000000..dac436c --- /dev/null +++ b/BestPractices.md @@ -0,0 +1,174 @@ +# Offline Security Best Practices + +This tool is designed for offline use, but true security depends on the **environment** where you run it. Below are operational security recommendations for generating keys you can trust. + +## Air-Gapped Setup (Highest Security) + +For maximum security when generating production wallets, use an **air-gapped computer**—a device that has never been and will never be connected to any network. + +**Recommended procedure:** + +1. **Prepare a clean machine**: + - Use a dedicated laptop or bootable USB with a fresh Linux installation (e.g., Tails, Ubuntu Live USB) + - Never connect this device to WiFi, Ethernet, or Bluetooth [web:14] + - Physically disable network interfaces if possible (remove WiFi card, tape over Ethernet port) + +2. **Transfer dependencies offline**: + + ```bash + # On an online machine, download dependencies + pip download -r requirements.txt -d ./offline-deps + + # Transfer ./offline-deps to air-gapped machine via USB + # On air-gapped machine: + pip install --no-index --find-links=./offline-deps -r requirements.txt + ``` + +3. **Verify code integrity**: + - Check the git commit hash matches the version you reviewed + - Optionally run `pytest -v tests/test_vectors.py` on the air-gapped machine to verify derivation logic + +4. **Generate wallet**: + + ```bash + python ./src/pyhdwallet.py gen --pgp-pubkey-file pubkeys/recipient.asc --file --off-screen + ``` + +5. **Transfer output safely**: + - Copy only the `.wallet/*.zip` file to USB (never copy `pyhdwallet.py` or Python environment back to online machine) + - The ZIP is AES-encrypted; the inner `.asc` is PGP-encrypted [web:19] + +6. **Destroy or securely wipe** the USB after transfer if it contained unencrypted secrets + +### Threats Air-Gapping Mitigates + +- **Remote attacks**: Malware cannot exfiltrate keys over the network +- **Clipboard hijacking**: No clipboard manager or remote access tool can intercept data +- **Browser/OS telemetry**: No accidental upload of terminal history or crash dumps + +### Threats Air-Gapping Does NOT Fully Mitigate + +Research shows that sophisticated attackers with physical access can potentially exfiltrate data from air-gapped systems via covert channels (acoustic, electromagnetic, optical) [web:18]. However: + +- These attacks require physical proximity and pre-installed malware [web:18] +- For individual users (not nation-state targets), air-gapping remains highly effective +- Countermeasures: Use the machine in a secure location, inspect for unfamiliar USB devices, verify software integrity before installation [web:18] + +### Physical Security + +**Mnemonic handling:** + +- Write the mnemonic on paper immediately; never store it digitally on the air-gapped machine +- Use a metal backup (e.g., Cryptosteel) for fire/water resistance +- Split storage across multiple secure locations if desired (Shamir's Secret Sharing for advanced users) + +**Device handling:** + +- After generating the wallet, optionally wipe the air-gapped device or destroy the bootable USB +- If reusing the device, use secure-erase tools (not just `rm`) + +### Verification Through Testing + +**Why the test suite matters for trust:** + +The committed test suite (`tests/test_vectors.py`) allows you to verify that derivation logic hasn't been tampered with before generating production keys: + +```bash +# On the air-gapped machine, before generating your wallet: +pytest -v tests/test_vectors.py +``` + +If all tests pass, you have cryptographic proof that: + +- BIP39 seed derivation matches the well-known test vector ("abandon abandon..." → known seed) [file:2] +- Derivation paths produce addresses matching public BIP39/BIP44 test vectors +- PGP fingerprinting logic works correctly + +If tests fail, **do not generate keys**—the code may be compromised or buggy. + +### Entropy Sources + +**Built-in entropy (default):** + +- Python's `secrets.token_bytes()` uses OS-provided CSPRNG (`/dev/urandom` on Linux, `CryptGenRandom` on Windows) +- This is cryptographically secure for typical use + +**Additional user entropy (optional):** + +```bash +python ./src/pyhdwallet.py gen --dice-rolls "4 2 6 1 3 5 ..." --file +``` + +- Roll a die 50+ times and input the results +- Your dice rolls are mixed with OS entropy via SHA256 [file:2] +- Protects against potential CSPRNG backdoors (theoretical concern) + +### PGP Key Fingerprint Pinning + +Always use `--expected-fingerprint` when encrypting to a PGP key to prevent key substitution attacks [file:2]: + +```bash +# First, get and verify the fingerprint of your recipient key +python ./src/pyhdwallet.py fetchkey https://example.com/mykey.asc --out mykey.asc +# Manually verify fingerprint matches what you expect (check via another channel) + +# Then use it with pinning: +python ./src/pyhdwallet.py gen \ + --pgp-pubkey-file mykey.asc \ + --expected-fingerprint A27B96F2B169B5491013D2DA892B822C14A9AA18 \ + --file +``` + +Without `--expected-fingerprint`, an attacker who controls the filesystem could swap `mykey.asc` with their own key. + +### Operational Checklist + +Before generating production wallets: + +- [ ] Running on air-gapped machine or fresh Live USB +- [ ] Network physically disabled (no WiFi/Ethernet/Bluetooth) +- [ ] Code integrity verified (git commit hash + test suite passes) +- [ ] Using `--off-screen` to minimize terminal scrollback exposure +- [ ] Using `--file` to avoid leaving unencrypted files on disk +- [ ] Using `--pgp-pubkey-file` with `--expected-fingerprint` for key pinning +- [ ] Paper/metal backup prepared for mnemonic +- [ ] Output ZIP password stored separately from ZIP file +- [ ] Plan for USB secure wipe after transfer + +### Lower-Risk Scenarios + +Air-gapping is overkill for: + +- **Learning/testing**: Use your regular laptop with `--off-screen` and `--file` +- **Small amounts**: Generate on a clean, updated machine with minimal software +- **Testnet wallets**: Standard laptop is fine + +Air-gapping is recommended for: + +- **Life savings or business funds** +- **Long-term cold storage** (multi-year hold) +- **Institutional custody scenarios** + +### Trust But Verify + +The only way to fully trust this tool (or any wallet software) is to: + +1. **Read the source code** (`src/pyhdwallet.py` is ~1400 lines, single file) +2. **Verify test vectors** match published BIP39 test data +3. **Run the test suite** on your air-gapped machine +4. **Generate a test wallet** and verify addresses on a block explorer using a separate tool + +Never trust wallet software blindly—especially for significant funds + +--- +**Key additions:** + +1. **Air-gapped setup procedure** with offline dependency installation +2. **Threat model** (what air-gapping protects against and doesn't) +3. **Physical security** best practices for mnemonic backup +4. **Test suite as verification tool** before generating production keys +5. **Entropy sources** explanation (dice rolls for paranoid users) +6. **PGP fingerprint pinning** rationale +7. **Operational security checklist** for production use +8. **Risk-based guidance** (when air-gapping is overkill vs. essential) +9. **"Trust but verify"** philosophy for crypto software