Keys
Chapter 32: Key Management & Wallets
Section titled “Chapter 32: Key Management & Wallets”Overview
Section titled “Overview”Proper key management is the foundation of blockchain security. The private keys that control access to blockchain accounts are the most critical assets in any blockchain infrastructure. A single key compromise can result in complete loss of funds, while key loss means permanent inaccessibility. This chapter covers comprehensive strategies for secure key generation, storage, and management for both development and production blockchain operations.
32.1 Understanding Key Types
Section titled “32.1 Understanding Key Types”Private Keys
Section titled “Private Keys”Private keys are the fundamental cryptographic secrets that control blockchain accounts. They are typically 256-bit numbers represented as 64 hexadecimal characters.
Private Key Structure:┌─────────────────────────────────────────┐│ Private Key (256-bit / 32 bytes) ││ Format: 64 hex characters (0-9, a-f) ││ Example: ││ 8f2a559...3a7e0c5d8a2b4f9e1c3a6d9... │└─────────────────────────────────────────┘| Property | Value |
|---|---|
| Length | 256 bits (32 bytes) |
| Format | 64 hex characters |
| Entropy | ~10^77 combinations |
| Security Level | Quantum-resistant |
Public Keys
Section titled “Public Keys”Public keys are derived from private keys using elliptic curve cryptography and can be shared freely.
Private Key → Public Key (ECDSA secp256k1) ↓8f2a559... → 02a50eb66887d1fe3... 04d9f2a2a4f4c5... (uncompressed)| Key Type | Shareable | Derivable |
|---|---|---|
| Private Key | Never | No |
| Public Key | Yes | From private only |
| Address | Yes | From public key |
Key Formats
Section titled “Key Formats”| Format | Description | Example |
|---|---|---|
| Hex | Raw hexadecimal | 8f2a559...3a7e |
| Keystore | Encrypted JSON | UTC--2024-01-01--xxxx.json |
| Mnemonic | 12-24 word phrase | abandon apple... |
| Base64 | Encoded binary | jypoYXNkZjo= |
Keystore File (JSON)
Section titled “Keystore File (JSON)”{ "address": "0x1234567890abcdef1234567890abcdef12345678", "crypto": { "cipher": "aes-128-ctr", "ciphertext": "a8b3c4d5...", "cipherparams": { "iv": "aabbccdd11223344556677889900aabbcc" }, "kdf": "scrypt", "kdfparams": { "dklen": 32, "n": 262144, "r": 8, "p": 1, "salt": "saltvalue1234567890abcdef" }, "mac": "macvalue1234567890abcdef..." }, "id": "uuid-string", "version": 3}Mnemonic Phrases
Section titled “Mnemonic Phrases”Mnemonic codes (BIP-39) convert entropy into human-readable words:
| Word Count | Entropy | Security |
|---|---|---|
| 12 words | 128 bits | Good |
| 24 words | 256 bits | Excellent |
Mnemonic to Key Derivation:
Word List (BIP-39) → BIP-32 HD Key → Ethereum Key ↓ ↓ ↓[abandon, apple, ..., zoo] → Master Key → m/44'/60'/0'/0/0 ↓ Account Address32.2 Creating Keys
Section titled “32.2 Creating Keys”Using Geth
Section titled “Using Geth”# Create new account (will prompt for password)geth account new
# Create with password filegeth account new --password /path/to/password.txt
# Create multiple accountsgeth account new --password /path/to/pass1.txtgeth account new --password /path/to/pass2.txt
# List existing accountsgeth account list
# Update account passwordgeth account update 0x...
# Import private keygeth account import /path/to/private-key-fileUsing Geth with Hardware Wallet
Section titled “Using Geth with Hardware Wallet”# List connected hardware walletsgeth account list --keystore /path/to/hardware
# Use with hardware wallet (requires unlock)geth --keystore /path/to/hardware \ --ledger \ --new-accountUsing Ethereum Keys (Python)
Section titled “Using Ethereum Keys (Python)”# Install eth-keyspip install eth-keys eth-keyfile
# Create key programmaticallypython3 << 'EOF'from eth_keys import keys
# Generate new private keyprivate_key = keys.PrivateKey()print(f"Private Key: {private_key.hex()}")print(f"Public Key: {private_key.public_key.hex()}")print(f"Address: {private_key.public_key.to_checksum_address()}")EOFUsing Web3.py
Section titled “Using Web3.py”pip install web3
python3 << 'EOF'from web3 import Web3
# Generate random accountaccount = Web3().eth.account.create()print(f"Address: {account.address}")print(f"Private Key: {account.key.hex()}")EOFUsing Cast (Foundry)
Section titled “Using Cast (Foundry)”# Generate random walletcast wallet new
# Create from mnemoniccast wallet import "mnemonic..."
# Sign transactioncast send <to> <value> --private-key <key> --rpc-url <url>32.3 Key Security Best Practices
Section titled “32.3 Key Security Best Practices”Production Security Principles
Section titled “Production Security Principles”┌─────────────────────────────────────────────────────────────┐│ KEY SECURITY HIERARCHY │├─────────────────────────────────────────────────────────────┤│ ││ Level 1: Development/Test Keys ││ ┌─────────────────────────────────────────────────────┐ ││ │ • File-based keystore with encryption │ ││ │ • Stored in encrypted filesystem │ ││ │ • Regular rotation (monthly) │ ││ └─────────────────────────────────────────────────────┘ ││ ││ Level 2: Staging/Testing Keys ││ ┌─────────────────────────────────────────────────────┐ ││ │ • Hardware security module (HSM) │ ││ │ • Multi-signature required │ ││ │ • Encrypted backup storage │ ││ └─────────────────────────────────────────────────────┘ ││ ││ Level 3: Production Keys (Validators) ││ ┌─────────────────────────────────────────────────────┐ ││ │ • Hardware wallets (Ledger, Trezor) │ ││ │ • HSM with key sharding │ ││ │ • Multi-party computation (MPC) │ ││ │ • Geographic distribution │ ││ └─────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────┘Essential Security Rules
Section titled “Essential Security Rules”-
Never share private keys
- Don’t commit to version control
- Don’t send over unencrypted channels
- Don’t log or display in plain text
-
Use hardware wallets for significant value
- Ledger hardware wallets
- Trezor devices
- AWS CloudHSM
- Azure Key Vault HSM
-
Maintain secure backups
- Multiple encrypted copies
- Geographic separation
- Test restoration regularly
-
Implement key separation
- Different keys for different purposes
- Operational vs. signing keys
- Staging vs. production keys
-
Enable multi-signature
- Require multiple approvals for large transactions
- Use Gnosis Safe for Ethereum
- Implement timelock delays
Access Control Matrix
Section titled “Access Control Matrix”| Role | Can Sign | Can View | Can Export | Can Backup |
|---|---|---|---|---|
| Operator | Yes | Address Only | No | No |
| Auditor | No | Yes | No | No |
| Admin | No | Yes | No | Yes |
| Security Officer | Yes | Yes | Encrypted Only | Yes |
32.4 Key Storage
Section titled “32.4 Key Storage”Directory Structure
Section titled “Directory Structure”/data/ethereum/├── keystore/ # Encrypted keystore files│ ├── UTC--2024-01-01T00-00-00.000Z--0x1234...abcd.json│ ├── UTC--2024-01-15T00-00-00.000Z--0x5678...efgh.json│ └── ...├── nodekey # Node's private key (P2P)├── obtuse/ # Light client keys└── trustdb/ # Trusted node keysEncrypted Filesystem
Section titled “Encrypted Filesystem”# Create encrypted directory (LUKS)sudo cryptsetup luksFormat /dev/sdb1sudo cryptsetup luksOpen /dev/sdb1 eth_keyssudo mkfs.ext4 /dev/mapper/eth_keyssudo mount /dev/mapper/eth_keys /data/ethereum/keystore
# Or use encfs (FUSE-based)sudo apt-get install encfsencfs /encrypted/keys /keystoreEnvironment Variables
Section titled “Environment Variables”# Set private key via environment variableexport PRIVATE_KEY="0xabcd..."
# In your applicationconst privateKey = process.env.PRIVATE_KEY;⚠️ WARNING: Environment variables can leak through:
- Process listing (
ps aux) - Log files
- Docker container inspection
- Error reporting systems
Secrets Management
Section titled “Secrets Management”# Using HashiCorp Vaultvault write secret/ethereum/key @key.json
# Retrieve at runtimevault read -field=key secret/ethereum/key
# Using AWS Secrets Manageraws secretsmanager get-secret-value \ --secret-id ethereum/production-key \ --query SecretString \ --output text32.5 Hardware Wallets
Section titled “32.5 Hardware Wallets”Ledger Integration
Section titled “Ledger Integration”# Install ledger librarypip install ledgereth
# Get address from Ledgerledgereth --address
# Sign transactionledgereth --transaction tx.jsonTrezor Integration
Section titled “Trezor Integration”# Install trezor librarypip install trezor
# Get address from Trezortrezorctl get-address --address-n 0/0
# Sign transactiontrezorctl sign-tx --file tx.jsonHSM (Hardware Security Module)
Section titled “HSM (Hardware Security Module)”# Using PKCS#11 with YubiHSMyubihsm> put asecret 0 label="eth_key" domains=1,2 keytype=ecdsa params=1 algorithm=ecc_secp256k1
# Sign transaction with HSMpkcs11-tool --module /usr/lib/yubihsm-pkcs11.so \ --login --pin=123456 \ --sign -m ECDSA \ --input-file tx-digest.bin \ --output-file signature.binAWS CloudHSM
Section titled “AWS CloudHSM”# Generate key in CloudHSMkey_mgmt_util Gensk -k 1 -m 12345678ABCD...
# Sign using CloudHSMgengetattr_QSN -k 1 -m 12345678ABCD... -d 32 -s input.txt -S signature.bin32.6 Key Rotation
Section titled “32.6 Key Rotation”Regular Rotation Schedule
Section titled “Regular Rotation Schedule”Key Rotation Policy:
┌─────────────┬──────────────┬──────────────┐│ Key Type │ Rotation │ Notes │├─────────────┼──────────────┼──────────────┤│ Development │ Weekly │ Easy to ││ │ │ regenerate │├─────────────┼──────────────┼──────────────┤│ Staging │ Monthly │ Coordinate ││ │ │ with releases│├─────────────┼──────────────┼──────────────┤│ Production │ Quarterly │ Requires ││ (Hot) │ │ planning │├─────────────┼──────────────┼──────────────┤│ Production │ Annually │ Full audit ││ (Cold) │ │ required │└─────────────┴──────────────┴──────────────┘Rotation Process
Section titled “Rotation Process”# Step 1: Create new keygeth account new --password /path/to/new_password.txt
# Step 2: Transfer funds (if applicable)geth attach http://localhost:8545> eth.sendTransaction({from: "0xOLD...", to: "0xNEW...", value: web3.toWei(10, "ether")})
# Step 3: Update configurations to use new key# Edit systemd service files# Update environment variables# Refresh any cached references
# Step 4: Securely delete old keyshred -u /path/to/old/keystore/file.json
# Step 5: Verify everything worksgeth account listAutomated Rotation Script
Section titled “Automated Rotation Script”#!/bin/bashOLD_KEY_PATH="/data/ethereum/keystore/UTC--2024-01-01--old.json"NEW_PASSWORD="/path/to/new_password.txt"NEW_KEY_PATH="/data/ethereum/keystore/"
# Generate new keyecho "Creating new key..."NEW_KEY=$(geth account new --password $NEW_PASSWORD | grep "Address:" | cut -d'{' -f2 | cut -d'}' -f1)
echo "New address: $NEW_KEY"
# Archive old keyif [ -f "$OLD_KEY_PATH" ]; then mv "$OLD_KEY_PATH" "/data/ethereum/keystore/archive/" echo "Old key archived"fi
# Update alias (symlink)ln -sf "$NEW_KEY_PATH" "/data/ethereum/keystore/current"
# Restart servicessystemctl restart geth
echo "Key rotation complete"32.7 Key Recovery
Section titled “32.7 Key Recovery”Recovery from Mnemonic
Section titled “Recovery from Mnemonic”# Using mnemonicspip install eth-account
python3 << 'EOF'from eth_account import Account
# Recover from 12-word mnemonicmnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"account = Account.from_mnemonic(mnemonic)print(f"Address: {account.address}")
# Derive specific pathaccount = Account.from_mnemonic(mnemonic, account_path="m/44'/60'/0'/0/1")print(f"Second account: {account.address}")EOFRecovery from Keystore
Section titled “Recovery from Keystore”# Decrypt keystore filepip install eth-keyfile
python3 << 'EOF'import getpassimport jsonfrom eth_keyfile import decode_keyfile
# Decrypt keystorewith open('keystore.json', 'rb') as f: password = getpass.getpass('Enter password: ') private_key = decode_keyfile(f.read(), password.encode()) print(f"Private key: {private_key.hex()}")EOFBackup Verification
Section titled “Backup Verification”#!/bin/bashBACKUP_DIR="/backup/ethereum/keystore"
echo "Verifying key backup integrity..."
# Check all keystore filesfor file in $BACKUP_DIR/*.json; do echo "Checking $file..."
# Validate JSON format if ! jq empty "$file" 2>/dev/null; then echo "ERROR: Invalid JSON in $file" exit 1 fi
# Check address exists address=$(jq -r '.address' "$file") echo " Address: $address"done
echo "All backup keys verified successfully"32.8 Validator-Specific Key Management
Section titled “32.8 Validator-Specific Key Management”Validator Keys Architecture
Section titled “Validator Keys Architecture”Validator Key Structure:
┌─────────────────────────────────────────────────────────────┐│ VALIDATOR KEYS │├─────────────────────────────────────────────────────────────┤│ ││ ┌──────────────────────────────────────────────────────┐ ││ │ Signing Key (nodekey) │ ││ │ • Used for P2P networking │ ││ │ • Can be rotated │ ││ │ • Low security impact if compromised │ ││ └──────────────────────────────────────────────────────┘ ││ ││ ┌──────────────────────────────────────────────────────┐ ││ │ Validator Private Key │ ││ │ • Signs blocks/proposals │ ││ │ • Must be highly secured │ ││ │ • Often stored in HSM │ ││ └──────────────────────────────────────────────────────┘ ││ ││ ┌──────────────────────────────────────────────────────┐ ││ │ Withdrawal Key │ ││ │ • Controls stake/withdrawals │ ││ │ • Cold storage recommended │ ││ │ • Rarely used (only for major operations) │ ││ └──────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────┘Ethereum 2.0 Validator Keys
Section titled “Ethereum 2.0 Validator Keys”# Generate validator keys (Eth2)eth2valtools mnemonic-entropy > mnemonic.txt
# Or use standard 24-wordeth2valtools mnemonic
# Create validator keyseth2valtools eth1-credebial \ --mnemonic="your 24 word mnemonic" \ --validation-keys-dir=/validator/keys \ --deposit-data-dir=/validator/deposit \ --validators-mnemonic-path=/validator/mnemonic.txt
# Secure mnemonic# Store in secure location (safe, HSM)Cosmos Validator Keys
Section titled “Cosmos Validator Keys”# Generate Tendermint validator keygaiad init validator --home /etc/gaia
# Get validator keycat /etc/gaia/config/priv_validator_key.json
# Get public keygaiad tendermint show-validator --home /etc/gaia
# Backup (CRITICAL)cp /etc/gaia/config/priv_validator_key.json /backup/secure/cp /etc/gaia/config/priv_validator_key.json /backup/secondary/32.9 Key Audit & Compliance
Section titled “32.9 Key Audit & Compliance”Key Inventory
Section titled “Key Inventory”#!/bin/bashecho "=== Ethereum Key Audit ==="echo "Date: $(date)"echo ""
# List all keystore filesecho "Active Keys:"for f in /data/ethereum/keystore/UTC--*.json; do addr=$(jq -r '.address' "$f") created=$(jq -r '.version' "$f") echo " $addr - Created: $created"done
echo ""echo "Archive Keys:"for f in /data/ethereum/keystore/archive/UTC--*.json; do addr=$(jq -r '.address' "$f") echo " $addr (archived)"done
echo ""echo "Hardware Wallets:"ledgereth --list
echo ""echo "Key Usage Summary:"echo " Production: $(ls /data/ethereum/keystore/UTC--*prod*.json | wc -l)"echo " Staging: $(ls /data/ethereum/keystore/UTC--*staging*.json | wc -l)"echo " Development: $(ls /data/ethereum/keystore/UTC--*dev*.json | wc -l)"Access Logging
Section titled “Access Logging”# Enable audit logging for key accessexport KEY_AUDIT_LOG="/var/log/ethereum/key-access.log"
# Log key usagelog_key_access() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $USER - $1 - $2" >> $KEY_AUDIT_LOG}
# Usagelog_key_access "sign" "0x1234...abcd"log_key_access "export" "0x1234...abcd"32.10 Emergency Procedures
Section titled “32.10 Emergency Procedures”Compromised Key Response
Section titled “Compromised Key Response”#!/bin/bashCOMPROMISED_ADDRESS="$1"NETWORK="$2" # mainnet, testnet, etc.
if [ -z "$COMPROMISED_ADDRESS" ]; then echo "Usage: $0 <address> <network>" exit 1fi
echo "EMERGENCY: Key compromised - $COMPROMISED_ADDRESS"
# 1. Transfer remaining fundsecho "Step 1: Transferring remaining funds..."geth attach http://localhost:8545# Manual intervention required:# > eth.sendTransaction({from: "$COMPROMISED_ADDRESS", to: "0xNEW...", value: ...})
# 2. Revoke authorizations (if validator)echo "Step 2: Revoking validator authorizations..."
# 3. Notify teamecho "Step 3: Sending incident notification..."# send_alert "Key compromised: $COMPROMISED_ADDRESS"
# 4. Archive compromised keyecho "Step 4: Archiving compromised key..."mkdir -p /compromised/$(date +%Y%m%d)mv /data/ethereum/keystore/*$COMPROMISED_ADDRESS* /compromised/$(date +%Y%m%d)/
# 5. Document incidentecho "Step 5: Documenting incident..."echo "$(date): Key $COMPROMISED_ADDRESS compromised" >> /var/log/security/incidents.log
echo "Emergency procedures initiated"Lost Key Recovery
Section titled “Lost Key Recovery”# Recovery from mnemonicpython3 << 'EOF'from eth_account import Account
mnemonic = input("Enter your 24-word mnemonic: ")account = Account.from_mnemonic(mnemonic)print(f"Recovered address: {account.address}")print(f"Private key: {account.key.hex()}")EOFSummary
Section titled “Summary”- Private keys are the foundation of blockchain security - protect them at all costs
- Use hardware wallets for production/validator keys
- Implement key rotation on regular schedules
- Maintain encrypted backups in geographically separated locations
- Use secrets management systems for production environments
- Implement multi-signature for high-value transactions
- Have emergency procedures ready for key compromise scenarios
- Keep detailed audit logs of all key operations
- Separate keys by environment and use case
Next Chapter
Section titled “Next Chapter”In Chapter 33: Network Security, we’ll explore network-level security measures.
Last Updated: 2026-02-22