# Vault System Documentation ## Overview The Self vault system provides secure storage and management of multiple encrypted cryptographic keys. It enables users to maintain multiple digital identities, each with its own key pair, while ensuring all private keys remain encrypted and under user control. ## Architecture ### Core Components ```mermaid graph TB VM[Vault Manager] --> V[Vault] VM --> VE[Vault Entry] V --> LS[Local Storage] VE --> EPK[Encrypted Private Key] VE --> MD[Metadata] subgraph "Encryption Layer" EPK --> AES[AES-256-GCM] AES --> PBKDF2[PBKDF2 Key Derivation] end subgraph "Storage Layer" LS --> JSON[JSON Format] JSON --> B64[Base64 Encoding] end ``` ### Data Structures #### Vault Entry ```rust #[derive(Debug, Clone, Serialize, Deserialize)] pub struct VaultEntry { pub id: String, // Unique identifier (UUID) pub name: String, // User-friendly name pub email: String, // Associated email address pub public_key: String, // Hex-encoded public key pub encrypted_private_key: EncryptedPrivateKey, // Encrypted private key pub created_at: String, // ISO 8601 timestamp } ``` #### Vault Configuration ```rust #[derive(Debug, Clone, Serialize, Deserialize)] pub struct VaultConfig { pub app_name: String, // Application identifier pub storage_key: String, // LocalStorage key prefix pub auto_lock_timeout: u32, // Auto-lock timeout in minutes } ``` ## Vault Operations ### Creating a New Vault Entry ```rust impl Vault { pub fn store_keypair( name: &str, email: &str, keypair: &KeyPair, password: &str, ) -> Result { // Generate unique ID let id = Uuid::new_v4().to_string(); // Encrypt private key let encrypted_private_key = encrypt_private_key(&keypair.private_key, password)?; // Create vault entry let entry = VaultEntry { id: id.clone(), name: name.to_string(), email: email.to_string(), public_key: keypair.public_key.clone(), encrypted_private_key, created_at: Utc::now().to_rfc3339(), }; // Store in vault self.add_entry(entry)?; Ok(id) } } ``` ### Retrieving Keys from Vault ```rust impl Vault { pub fn retrieve_keypair(password: &str) -> Result<(String, String), VaultError> { // Get primary identity from storage let storage = web_sys::window() .and_then(|w| w.local_storage().ok().flatten()) .ok_or(VaultError::StorageNotAvailable)?; let vault_data = storage .get_item("self_vault") .map_err(|_| VaultError::StorageError)? .ok_or(VaultError::NoKeysStored)?; let vault: VaultData = serde_json::from_str(&vault_data) .map_err(|_| VaultError::InvalidVaultFormat)?; // Find primary identity let entry = vault.entries .values() .next() .ok_or(VaultError::NoKeysStored)?; // Decrypt private key let private_key = decrypt_private_key(&entry.encrypted_private_key, password)?; Ok((private_key, entry.public_key.clone())) } } ``` ### Listing Vault Entries ```rust impl VaultManager { pub fn list_identities(&self) -> Vec { self.vault_data .entries .values() .map(|entry| IdentitySummary { id: entry.id.clone(), name: entry.name.clone(), email: entry.email.clone(), public_key: entry.public_key.clone(), created_at: entry.created_at.clone(), }) .collect() } } ``` ## Vault Manager Component ### Component State ```rust pub struct VaultManager { vault_data: VaultData, selected_identity: Option, password_input: String, show_password_input: bool, loading: bool, error_message: Option, show_create_form: bool, new_identity_name: String, new_identity_email: String, } ``` ### Key Management Operations #### Adding New Identity ```rust fn handle_create_identity(&mut self, ctx: &Context) { if self.new_identity_name.trim().is_empty() || self.new_identity_email.trim().is_empty() { self.error_message = Some("Name and email are required".to_string()); return; } let name = self.new_identity_name.clone(); let email = self.new_identity_email.clone(); let password = self.password_input.clone(); let link = ctx.link().clone(); wasm_bindgen_futures::spawn_local(async move { match generate_keypair() { Ok(keypair) => { match Vault::store_keypair(&name, &email, &keypair, &password) { Ok(id) => { link.send_message(VaultMsg::IdentityCreated(id)); } Err(e) => { link.send_message(VaultMsg::Error(format!("Failed to store identity: {}", e))); } } } Err(e) => { link.send_message(VaultMsg::Error(format!("Failed to generate keys: {}", e))); } } }); } ``` #### Selecting Identity ```rust fn handle_select_identity(&mut self, identity_id: String, ctx: &Context) { if self.password_input.trim().is_empty() { self.error_message = Some("Password required to access identity".to_string()); return; } self.loading = true; self.selected_identity = Some(identity_id.clone()); let password = self.password_input.clone(); let link = ctx.link().clone(); wasm_bindgen_futures::spawn_local(async move { match Vault::decrypt_identity(&identity_id, &password) { Ok(keypair) => { link.send_message(VaultMsg::IdentitySelected(keypair)); } Err(e) => { link.send_message(VaultMsg::Error(format!("Failed to decrypt identity: {}", e))); } } }); } ``` ## Storage Format ### Vault Data Structure ```json { "version": "1.0", "created_at": "2024-01-01T00:00:00Z", "entries": { "uuid-1": { "id": "uuid-1", "name": "Primary Identity", "email": "user@example.com", "public_key": "04a1b2c3d4e5f6...", "encrypted_private_key": { "encrypted_data": "base64-ciphertext", "nonce": "base64-nonce", "salt": "base64-salt" }, "created_at": "2024-01-01T00:00:00Z" }, "uuid-2": { "id": "uuid-2", "name": "Work Identity", "email": "work@company.com", "public_key": "04b2c3d4e5f6a1...", "encrypted_private_key": { "encrypted_data": "base64-ciphertext-2", "nonce": "base64-nonce-2", "salt": "base64-salt-2" }, "created_at": "2024-01-02T00:00:00Z" } } } ``` ### Storage Keys - **Primary Vault**: `self_vault` - Main vault storage - **Active Identity**: `self_active_identity` - Currently selected identity ID - **Session Data**: `self_session` - Temporary session information ## Security Model ### Encryption Strategy 1. **Individual Key Encryption**: Each private key encrypted separately 2. **Unique Salts**: Each key uses its own random salt 3. **Password-Based Access**: Same password can decrypt all keys in vault 4. **No Master Key**: No single key encrypts the entire vault ### Password Management ```rust impl VaultManager { fn validate_password(&self, password: &str) -> Result<(), VaultError> { if password.len() < 8 { return Err(VaultError::WeakPassword("Password must be at least 8 characters".to_string())); } // Additional password strength checks let has_upper = password.chars().any(|c| c.is_uppercase()); let has_lower = password.chars().any(|c| c.is_lowercase()); let has_digit = password.chars().any(|c| c.is_numeric()); if !has_upper || !has_lower || !has_digit { return Err(VaultError::WeakPassword( "Password must contain uppercase, lowercase, and numeric characters".to_string() )); } Ok(()) } } ``` ### Access Control ```rust pub enum VaultAccess { ReadOnly, // Can view public information only Decrypt, // Can decrypt and use private keys Manage, // Can add/remove identities } impl VaultManager { pub fn check_access(&self, required_access: VaultAccess) -> bool { match required_access { VaultAccess::ReadOnly => true, VaultAccess::Decrypt => self.is_unlocked(), VaultAccess::Manage => self.is_unlocked() && self.has_management_privileges(), } } } ``` ## Error Handling ### Vault Error Types ```rust #[derive(Debug, Clone)] pub enum VaultError { StorageNotAvailable, StorageError, NoKeysStored, InvalidVaultFormat, EncryptionFailed(String), DecryptionFailed(String), WeakPassword(String), IdentityNotFound(String), DuplicateIdentity(String), InvalidKeyFormat, } impl fmt::Display for VaultError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { VaultError::StorageNotAvailable => write!(f, "Browser storage not available"), VaultError::StorageError => write!(f, "Failed to access storage"), VaultError::NoKeysStored => write!(f, "No keys found in vault"), VaultError::InvalidVaultFormat => write!(f, "Invalid vault data format"), VaultError::EncryptionFailed(msg) => write!(f, "Encryption failed: {}", msg), VaultError::DecryptionFailed(msg) => write!(f, "Decryption failed: {}", msg), VaultError::WeakPassword(msg) => write!(f, "Weak password: {}", msg), VaultError::IdentityNotFound(id) => write!(f, "Identity not found: {}", id), VaultError::DuplicateIdentity(email) => write!(f, "Identity already exists: {}", email), VaultError::InvalidKeyFormat => write!(f, "Invalid key format"), } } } ``` ## User Interface ### Vault Manager UI Components #### Identity List ```rust fn render_identity_list(&self, ctx: &Context) -> Html { let identities = self.list_identities(); html! {
{"Stored Identities"}
{for identities.iter().map(|identity| { let identity_id = identity.id.clone(); html! {
{&identity.name}

{&identity.email}

{"Created: "}{&identity.created_at}
} })}
} } ``` #### Create Identity Form ```rust fn render_create_form(&self, ctx: &Context) -> Html { html! {
{"Create New Identity"}
} } ``` ## Integration with Other Components ### Registration Integration ```rust // Auto-store generated keys during registration impl Registration { fn complete_registration(&mut self, ctx: &Context) { if let (Some(keypair), Some(password)) = (&self.generated_keypair, &self.password) { // Store in vault automatically match Vault::store_keypair( &self.name, &self.email, keypair, password ) { Ok(id) => { web_sys::console::log_1(&format!("Identity stored in vault: {}", id).into()); } Err(e) => { web_sys::console::log_1(&format!("Failed to store in vault: {}", e).into()); } } } } } ``` ### Login Integration ```rust // Select identity from vault for login impl Login { fn load_from_vault(&mut self, identity_id: &str, password: &str) -> Result<(), String> { match Vault::decrypt_identity(identity_id, password) { Ok(keypair) => { self.current_keypair = Some(keypair); Ok(()) } Err(e) => Err(format!("Failed to load identity: {}", e)) } } } ``` ## Backup and Recovery ### Export Functionality ```rust impl VaultManager { pub fn export_vault(&self, password: &str) -> Result { // Verify password can decrypt at least one identity self.verify_vault_password(password)?; // Export vault data (still encrypted) let export_data = ExportData { version: "1.0".to_string(), exported_at: Utc::now().to_rfc3339(), vault: self.vault_data.clone(), }; serde_json::to_string_pretty(&export_data) .map_err(|_| VaultError::StorageError) } pub fn import_vault(&mut self, import_data: &str, password: &str) -> Result<(), VaultError> { let export_data: ExportData = serde_json::from_str(import_data) .map_err(|_| VaultError::InvalidVaultFormat)?; // Verify password can decrypt imported identities for entry in export_data.vault.entries.values() { decrypt_private_key(&entry.encrypted_private_key, password)?; } // Merge with existing vault for (id, entry) in export_data.vault.entries { self.vault_data.entries.insert(id, entry); } self.save_vault() } } ``` ### Recovery Options 1. **Password Recovery**: Not possible - passwords are not stored 2. **Vault Export**: Users must export vault data regularly 3. **Individual Key Backup**: Each private key can be backed up separately 4. **Seed Phrase**: Future enhancement for deterministic key generation ## Performance Considerations ### Optimization Strategies 1. **Lazy Loading**: Load vault data only when needed 2. **Caching**: Cache decrypted keys in memory during session 3. **Batch Operations**: Group multiple vault operations 4. **Background Sync**: Sync vault changes in background ### Memory Management ```rust impl Drop for VaultManager { fn drop(&mut self) { // Clear sensitive data from memory self.password_input.zeroize(); if let Some(ref mut keypair) = self.cached_keypair { keypair.private_key.zeroize(); } } } ``` ## Future Enhancements ### Planned Features 1. **Hierarchical Deterministic Keys**: BIP32-style key derivation 2. **Hardware Token Integration**: WebAuthn support 3. **Vault Synchronization**: Cross-device vault sync 4. **Biometric Authentication**: WebAuthn biometric support 5. **Key Rotation**: Automatic key rotation policies 6. **Audit Trail**: Comprehensive logging of vault operations ### Advanced Security Features 1. **Multi-Factor Authentication**: Additional authentication factors 2. **Time-Based Access**: Temporary key access permissions 3. **Geolocation Restrictions**: Location-based access controls 4. **Device Binding**: Tie vault access to specific devices