//! Typed wrappers around `crypto::{encrypt, decrypt}` for the new typed-item //! data model. Each function does JSON-serialize → encrypt or decrypt → JSON-parse. //! //! v1 helpers (encrypt_entry / decrypt_entry / encrypt_manifest with the old //! Manifest type) are intentionally NOT carried forward. The CLI rewrite in //! Plan 1B switches to the new helpers. use zeroize::Zeroizing; use crate::crypto::{decrypt, encrypt}; use crate::error::Result; use crate::item::Item; use crate::manifest::Manifest; use crate::settings::VaultSettings; pub fn encrypt_item(item: &Item, master_key: &Zeroizing<[u8; 32]>) -> Result> { let json = serde_json::to_vec(item)?; let plaintext = Zeroizing::new(json); encrypt(master_key, plaintext.as_slice()) } pub fn decrypt_item(encrypted: &[u8], master_key: &Zeroizing<[u8; 32]>) -> Result { let plaintext = decrypt(master_key, encrypted)?; let plaintext = Zeroizing::new(plaintext); let item: Item = serde_json::from_slice(&plaintext)?; Ok(item) } pub fn encrypt_manifest(manifest: &Manifest, master_key: &Zeroizing<[u8; 32]>) -> Result> { let json = serde_json::to_vec(manifest)?; let plaintext = Zeroizing::new(json); encrypt(master_key, plaintext.as_slice()) } pub fn decrypt_manifest(encrypted: &[u8], master_key: &Zeroizing<[u8; 32]>) -> Result { let plaintext = decrypt(master_key, encrypted)?; let plaintext = Zeroizing::new(plaintext); let manifest: Manifest = serde_json::from_slice(&plaintext)?; Ok(manifest) } pub fn encrypt_settings(settings: &VaultSettings, master_key: &Zeroizing<[u8; 32]>) -> Result> { let json = serde_json::to_vec(settings)?; let plaintext = Zeroizing::new(json); encrypt(master_key, plaintext.as_slice()) } pub fn decrypt_settings(encrypted: &[u8], master_key: &Zeroizing<[u8; 32]>) -> Result { let plaintext = decrypt(master_key, encrypted)?; let plaintext = Zeroizing::new(plaintext); let settings: VaultSettings = serde_json::from_slice(&plaintext)?; Ok(settings) } #[cfg(test)] mod tests { use super::*; use crate::item_types::{ItemCore, SecureNoteCore}; fn key() -> Zeroizing<[u8; 32]> { Zeroizing::new([0x33u8; 32]) } #[test] fn item_round_trip() { let item = Item::new("note".into(), ItemCore::SecureNote(SecureNoteCore { body: Zeroizing::new("hello".into()), })); let bytes = encrypt_item(&item, &key()).unwrap(); let decoded = decrypt_item(&bytes, &key()).unwrap(); assert_eq!(decoded.title, "note"); } #[test] fn manifest_round_trip() { let mut m = Manifest::new(); let item = Item::new("x".into(), ItemCore::SecureNote(SecureNoteCore::default())); m.upsert(&item); let bytes = encrypt_manifest(&m, &key()).unwrap(); let decoded = decrypt_manifest(&bytes, &key()).unwrap(); assert_eq!(decoded.items.len(), 1); } #[test] fn settings_round_trip() { let s = VaultSettings::default(); let bytes = encrypt_settings(&s, &key()).unwrap(); let decoded = decrypt_settings(&bytes, &key()).unwrap(); assert_eq!(decoded.attachment_caps.per_attachment_max_bytes, s.attachment_caps.per_attachment_max_bytes); } }