# Vault Implementation Plan > **Design Principle:** > **The vault crate will provide both a stateless (context-passing) API and an ergonomic session-based API.** > This ensures maximum flexibility for both library developers and application builders, supporting both functional and stateful usage patterns. ## 1. Architecture Overview The `vault` crate is a modular, async, and WASM-compatible cryptographic keystore. It manages an encrypted keyspace (multiple keypairs), provides cryptographic APIs, and persists all data via the `kvstore` trait. The design ensures all sensitive material is encrypted at rest and is portable across native and browser environments. **Core Components:** - **Vault:** Main manager for encrypted keyspace and cryptographic operations. - **KeyPair:** Represents individual asymmetric keypairs (e.g., secp256k1, Ed25519). - **Symmetric Encryption Module:** Handles encryption/decryption and key derivation. - **SessionManager (Optional):** Maintains current context (e.g., selected keypair) for user sessions. - **KVStore:** Async trait for backend-agnostic persistence (sled on native, IndexedDB on WASM). --- ## Using Both Stateless and Session-Based APIs You can design the vault crate to support both stateless and session-based (stateful) usage patterns. This gives maximum flexibility to both library developers and application builders. ### Stateless API - All operations require explicit context (unlocked keyspace, keypair, etc.) as arguments. - No hidden or global state; maximally testable and concurrency-friendly. - Example: ```rust let keyspace = vault.unlock_keyspace("personal", b"password").await?; let signature = keyspace.sign("key1", &msg).await?; ``` ### Session Manager API - Maintains in-memory state of unlocked keyspaces and current selections. - Provides ergonomic methods for interactive apps (CLI, desktop, browser). - Example: ```rust let mut session = SessionManager::new(); session.unlock_keyspace("personal", b"password", &vault)?; session.select_keypair("key1"); let signature = session.current_keypair().unwrap().sign(&msg)?; session.logout(); // wipes all secrets from memory ``` ### How They Work Together - The **stateless API** is the core, always available and used internally by the session manager. - The **session manager** is a thin, optional layer that wraps the stateless API for convenience. - Applications can choose which pattern fits their needs, or even mix both (e.g., use stateless for background jobs, session manager for user sessions). ### Benefits - **Flexibility:** Library users can pick the best model for their use case. - **Security:** Session manager can enforce auto-lock, timeouts, and secure memory wiping. - **Simplicity:** Stateless API is easy to test and reason about, while session manager improves UX for interactive flows. ### Commitment: Provide Both APIs - **Both stateless and session-based APIs will be provided in the vault crate.** - Stateless API: For backend, automation, or library contexts—explicit, functional, and concurrency-friendly. - Session manager API: For UI/UX-focused applications—ergonomic, stateful, and user-friendly. --- ## 2. Data Model ### VaultMetadata & Keyspace Model ```rust struct VaultMetadata { name: String, keyspaces: Vec, // ... other vault-level metadata (optionally encrypted) } struct KeyspaceMetadata { name: String, salt: [u8; 16], // Unique salt for this keyspace encrypted_blob: Vec, // All keypairs & secrets, encrypted with keyspace password // ... other keyspace metadata } // The decrypted contents of a keyspace: struct KeyspaceData { keypairs: Vec, // ... other keyspace-level metadata } struct KeyEntry { id: String, key_type: KeyType, private_key: Vec, // Only present in memory after decryption public_key: Vec, metadata: Option, } enum KeyType { Secp256k1, Ed25519, // ... } ``` - The vault contains a list of keyspaces, each with its own salt and encrypted blob. - Each keyspace is unlocked independently using its password and salt. - Key material is never stored unencrypted; only decrypted in memory after unlocking a keyspace. --- ## 3. API Design (Keyspace Model) ### Vault ```rust impl Vault { async fn open(store: S) -> Result; async fn list_keyspaces(&self) -> Result, VaultError>; async fn create_keyspace(&mut self, name: &str, password: &[u8]) -> Result<(), VaultError>; async fn delete_keyspace(&mut self, name: &str) -> Result<(), VaultError>; async fn unlock_keyspace(&mut self, name: &str, password: &[u8]) -> Result<(), VaultError>; async fn lock_keyspace(&mut self, name: &str); // ... } ``` ### Keyspace Management ```rust impl Keyspace { fn is_unlocked(&self) -> bool; fn name(&self) -> &str; async fn create_key(&mut self, key_type: KeyType, name: &str) -> Result; async fn list_keys(&self) -> Result, VaultError>; async fn sign(&self, key_id: &str, msg: &[u8]) -> Result; async fn encrypt(&self, key_id: &str, plaintext: &[u8]) -> Result; async fn decrypt(&self, key_id: &str, ciphertext: &[u8]) -> Result, VaultError>; async fn change_password(&mut self, old: &[u8], new: &[u8]) -> Result<(), VaultError>; // ... } ``` ### SessionManager ```rust impl SessionManager { fn select_key(&mut self, key_id: &str); fn current_key(&self) -> Option<&KeyPair>; } ``` ### Symmetric Encryption Module - Derives a master key from password and salt (e.g., PBKDF2 or scrypt). - Encrypts/decrypts vault data with AES-GCM or ChaCha20Poly1305. --- ## 4. Implementation Plan 1. **Define Data Structures** - VaultData, KeyEntry, KeyType, KeyMetadata, etc. 2. **Implement Symmetric Encryption** - Password-based key derivation (PBKDF2/scrypt) - AES-GCM or ChaCha20Poly1305 encryption 3. **Vault Logic** - open, unlock, encrypt/decrypt, manage keypairs - persist encrypted blob in kvstore 4. **KeyPair Management** - Generate, import, export, sign, verify 5. **Session Management** - Track selected key/context 6. **Error Handling** - VaultError enum for crypto, storage, and logic errors 7. **WASM Interop** - Use wasm-bindgen to expose async APIs as JS Promises - Ensure all crypto crates are WASM-compatible 8. **Testing** - Native and WASM tests for all APIs --- ## Design Decisions: Old Implementation, Current Plan, Open Questions, and Recommendations | Area | Old Implementation | Current Plan | Decision Left/Open | Recommendation & Rationale | |------|--------------------|--------------|--------------------|----------------------------| | **KDF** | PBKDF2-HMAC-SHA256 | PBKDF2 or scrypt (WASM-compatible) | Which as default? Both supported? Per-keyspace choice? | **Use scrypt as default** for new keyspaces (stronger against GPU attacks) | **Symmetric Encryption** | ChaCha20Poly1305 | AES-256-GCM or ChaCha20Poly1305 | Which default? Both supported? Per-keyspace choice? | **ChaCha20Poly1305 recommended** for WASM and cross-platform. | **Key Types** | secp256k1, Ed25519 | secp256k1, Ed25519 | Add more? Custom key types? | **Keep secp256k1 and Ed25519 as default.** | | **Metadata Encryption** | Unencrypted vault metadata | Unencrypted keyspace metadata | Option to encrypt metadata? | **Unencrypted vault metadata** for simplicity. | | **Session Manager Features** | No session manager, manual unlock | Optional session manager | Timeout, auto-lock, secure wipe, multi-user? | **Implement optional session manager with timeout and secure memory wipe**. | | **Password Change/Recovery** | Manual re-encrypt, no recovery | API for password change | Re-encrypt all? Recovery/MFA? | **Re-encrypt keyspace on password change.** | | **WASM/Native Crypto** | Native only | WASM-compatible crates | Native-only features? | **Require WASM compatibility for all core features.** | | **Keyspace Sharing/Export** | Manual export/import, share password | Share keyspace password | Explicit export/import flows? Auditing? | **Add explicit export/import APIs.** Log/audit sharing if privacy is a concern. | | **Multi-user/Access Control** | Single password per vault | Single password per keyspace | ACL, threshold unlock? | **Single password per keyspace is simplest.** | | **Metadata/Tagging** | Minimal metadata, no tags | Basic metadata, optional tags | Required/custom tags? Usage stats? | **Support custom tags and creation date** for keyspaces/keys. | | **Storage Structure** | Single JSON file (vault) | Keyspaces as blobs in vault metadata | Store as separate kvstore records? | **Recommend storing each keyspace as a separate record** in kvstore for easier backup/sync/restore. | | **Error Handling** | Basic error codes | VaultError enum | Granular or coarse? WASM/JS exposure? | **Define granular error types** and expose user-friendly errors for WASM/JS. | --- **Legend:** - **Old Implementation:** What was done in the previous (legacy) design. - **Current Plan:** What is currently proposed in this implementation plan. - **Decision Left/Open:** What remains to be finalized or clarified. - **Recommendation & Rationale:** What is recommended for the new implementation and why, especially if it differs from the old approach. --- ## 5. File/Module Structure (Recommended) ``` vault/ ├── src/ │ ├── lib.rs # Vault API and main logic │ ├── data.rs # Data models: VaultData, KeyEntry, etc. │ ├── crypto.rs # Symmetric/asymmetric crypto, key derivation │ ├── session.rs # SessionManager │ ├── error.rs # VaultError and error handling │ └── utils.rs # Helpers, serialization, etc. ├── tests/ │ ├── native.rs # Native (sled) tests │ └── wasm.rs # WASM (IndexedDB) tests └── ... ``` --- ## 6. Cryptography: Crates and Algorithms **Crates:** - [`aes-gcm`](https://crates.io/crates/aes-gcm): AES-GCM authenticated encryption (WASM-compatible) - [`chacha20poly1305`](https://crates.io/crates/chacha20poly1305): ChaCha20Poly1305 authenticated encryption (WASM-compatible) - [`pbkdf2`](https://crates.io/crates/pbkdf2): Password-based key derivation (WASM-compatible) - [`scrypt`](https://crates.io/crates/scrypt): Alternative KDF, strong and WASM-compatible - [`k256`](https://crates.io/crates/k256): secp256k1 ECDSA (Ethereum keys) - [`ed25519-dalek`](https://crates.io/crates/ed25519-dalek): Ed25519 keypairs - [`rand_core`](https://crates.io/crates/rand_core): Randomness, WASM-compatible - [`getrandom`](https://crates.io/crates/getrandom): Platform-agnostic RNG **Algorithm Choices:** - **Vault Encryption:** - AES-256-GCM (default, via `aes-gcm`) - Optionally ChaCha20Poly1305 (via `chacha20poly1305`) - **Password Key Derivation:** - PBKDF2-HMAC-SHA256 (via `pbkdf2`) - Optionally scrypt (via `scrypt`) - **Asymmetric Keypairs:** - secp256k1 (via `k256`) for Ethereum/EVM - Ed25519 (via `ed25519-dalek`) for general-purpose signatures - **Randomness:** - Use `rand_core` and `getrandom` for secure RNG in both native and WASM **Feature-to-Algorithm Mapping:** | Feature | Crate(s) | Algorithm(s) | |------------------------|-----------------------|---------------------------| | Vault encryption | aes-gcm, chacha20poly1305 | AES-256-GCM, ChaCha20Poly1305 | | Password KDF | pbkdf2, scrypt | PBKDF2-HMAC-SHA256, scrypt| | Symmetric encryption | aes-gcm, chacha20poly1305 | AES-256-GCM, ChaCha20Poly1305 | | secp256k1 keypairs | k256 | secp256k1 ECDSA | | Ed25519 keypairs | ed25519-dalek | Ed25519 | | Randomness | rand_core, getrandom | OS RNG | --- ## 7. WASM & Native Considerations - Use only WASM-compatible crypto crates (`aes-gcm`, `chacha20poly1305`, `k256`, `ed25519-dalek`, etc). - Use `wasm-bindgen`/`wasm-bindgen-futures` for browser interop. - Use `tokio::task::spawn_blocking` for blocking crypto on native. - All APIs are async and runtime-agnostic. --- ## 6. Future Extensions - Multi-user vaults (multi-password, access control) - Hardware-backed key storage (YubiKey, WebAuthn) - Key rotation and auditing - Pluggable crypto algorithms - Advanced metadata and tagging --- ## 7. References - See `docs/Architecture.md` and `docs/kvstore-vault-architecture.md` for high-level design and rationale. - Crypto patterns inspired by industry best practices (e.g., Wire, Signal, Bitwarden).