A keystore in KERI is an encrypted data store that securely holds the private keys for a collection of AIDs (Autonomic Identifiers), providing the foundational cryptographic key management layer for KERI-based identity systems.
Related Concepts
No related concepts available
Comprehensive Explanation
keystore
Structure Definition
A keystore in the KERI (Key Event Receipt Infrastructure) ecosystem is a specialized encrypted data store designed to securely manage the private cryptographic keys that control AIDs (Autonomic Identifiers). Unlike general-purpose key storage systems, a KERI keystore is purpose-built to support the unique requirements of KERI's autonomic identity architecture, including key rotation, pre-rotation commitments, and hierarchical deterministic key derivation.
Architectural Role
The keystore serves as the foundational security component in KERI's decentralized key management infrastructure. According to Document 2, it is explicitly distinguished from the broader concept of a wallet, with the wallet being a superset that includes the keystore plus additional databases for KEL (Key Event Log) storage and credential management.
Implementation Notes
Critical Implementation Considerations
Encryption and Security
Passcode Strength: The keystore's security fundamentally depends on passcode strength. Implementations should:
Use key stretching (PBKDF2, Argon2) to resist brute-force attacks
Never store passcodes in plaintext
Support hardware-backed keystores (TPM, Secure Enclave) where available
Default Locked State: As documented in Document 44, keystores must be encrypted by default. Any implementation that stores keys in plaintext should be explicitly marked as insecure and limited to development use.
Memory Protection: Private keys should:
Be decrypted only when needed for signing operations
Be cleared from memory immediately after use
Never be written to swap or core dumps
Use memory locking (mlock) where supported
Storage Backend Selection
LMDB Advantages: The reference implementation's choice of LMDB provides:
Zero-copy reads: Keys accessed directly from memory-mapped files
Concurrent access: Multiple readers without blocking
Crash recovery: Automatic recovery from system failures
Alternative Backends: Other implementations may use:
SQLite: Better for complex queries, slightly slower
RocksDB: Better for write-heavy workloads
IndexedDB: For browser-based keystores
Hardware wallets: For maximum security
When choosing a backend, prioritize:
ACID transaction support (critical for key rotation)
Encryption-at-rest capability
Performance for signing operations
Platform compatibility
Deterministic Key Generation
The salt-based key derivation enables key recovery but requires careful implementation:
Salt Management:
This architectural separation reflects KERI's modular design philosophy: the keystore focuses exclusively on cryptographic key material protection, while higher-level components handle event logs, credentials, and protocol operations. This separation enables:
Clear security boundaries between key material and derived data
Modular replacement of storage backends without affecting protocol logic
Graduated security policies where key material receives stronger protection than event logs
Simplified audit of cryptographic operations
Core Components
A KERI keystore manages several categories of cryptographic material:
Private Keys: The keystore's primary responsibility is securing the private keys that provide control authority over AIDs. These include:
In the Python implementation (KERIpy), the keystore is organized around the Hab (Habitat) abstraction. As described in Document 9:
"A Hab is a keystore for one identifier. It stores key material and all other data associated with a single AID."
This one-to-one relationship between Hab and AID provides:
Isolation: Each identifier's keys are stored separately
Scalability: Multiple identifiers can be managed independently
Security: Compromise of one Hab doesn't affect others
Multiple Habs are organized within a Habery, which serves as a collection manager for keystores. This two-level architecture (Habery containing multiple Habs) enables efficient management of multiple identities while maintaining strong isolation between them.
Data Format
Storage Technology
The reference implementation uses LMDB (Lightning Memory-Mapped Database) as the underlying storage engine. As documented in Document 9:
"The Python implementation in KERIpy, also used by KERIA, uses LMDB to store key material and all other data."
LMDB provides several advantages for keystore implementation:
Performance Characteristics:
Memory-mapped I/O: Direct memory access without system call overhead
Zero-copy reads: Data accessed directly from mapped memory
ACID transactions: Atomic updates with crash recovery
Concurrent readers: Multiple read operations without blocking
Security Properties:
File-level encryption: Can be combined with filesystem encryption
Atomic writes: Prevents partial key material exposure during crashes
Compact storage: Efficient space utilization for cryptographic primitives
Encryption Layer
The keystore implements encryption-at-rest using a passcode-derived key. According to Document 44:
"The default status a KERI data store is in once it has been created using a passcode; it is by default encrypted."
This locked state is the default security posture, ensuring that:
KERI keystores support deterministic key generation from a cryptographic seed. As explained in Document 1:
"The salt value, combined with other context including the keystore's aeid (authentication encryption identifier), deterministically generates all key-pairs belonging to an identifier. This means that with the same salt and context, the same keys will always be produced."
This deterministic property enables:
Key recovery: Regenerating keys from the original salt
Backup simplicity: Only the salt needs secure backup
Reproducibility: Testing with known key sequences
Directory Structure
When initialized, a KERI keystore creates three directory structures, as shown in Document 1:
Keystore initialization is the first operation in any KERI workflow. The KLI (KERI Command Line Interface) provides the kli init command for this purpose. From Document 1:
--config-file: JSON file with witness and other configuration
--nopasscode: Development-only flag to skip encryption (insecure)
The initialization process:
Creates directory structure at /usr/local/var/keri/
Generates encryption key from passcode using key stretching
Initializes LMDB database with encrypted storage
Stores salt for key derivation
Loads witness configuration if provided
Passcode Management
Secure passcode handling is critical for keystore security. Document 4 describes three storage options:
1. Insecure (Development Only):
./scripts/source.sh --insecure
Stores passcode in plaintext on filesystem. Never use in production.
2. macOS Keychain Integration:
./scripts/source.sh --kc
Stores passcode in macOS Keychain with OS-level encryption and access control.
3. 1Password Integration:
./scripts/source.sh --op
Stores passcode in 1Password vault with enterprise-grade security.
The document emphasizes:
"The vLEI ecosystem treats both salt (used to create deterministic public/private key pairs) and passcode as vital components equivalent in importance to private keys."
Generates key pairs using the keystore's salt and derivation context
Creates inception event with initial keys and configuration
Stores private keys in encrypted keystore
Publishes event to configured witnesses
Returns AID prefix (self-certifying identifier)
The keystore maintains the relationship between:
The AID prefix (public identifier)
The controlling private keys (secret material)
The key state history (rotation events)
Key Rotation
KERI's pre-rotation mechanism requires the keystore to manage both current and future keys. As explained in Document 28:
"With pre-rotation: The cryptographic commitment (a digest of the public keys) for the next key set is embedded within the current key establishment event. The next keys can be generated and secured in advance, separate from the currently active operational keys."
The keystore's role in rotation:
Pre-Rotation Phase:
Generate next key pairs during inception or previous rotation
Compute key digests for commitment
Store next private keys securely (never exposed until rotation)
Include digests in current establishment event
Rotation Execution:
Retrieve next private keys from keystore
Sign rotation event with current keys
Expose next public keys in rotation event
Generate new next keys for future rotation
Update key state in keystore
This process ensures that:
Current keys can be compromised without affecting rotation capability
Next keys remain protected until needed
Rotation authority is cryptographically committed in advance