diff --git a/vault/src/error.rs b/vault/src/error.rs index 56df3f5..1c2366b 100644 --- a/vault/src/error.rs +++ b/vault/src/error.rs @@ -3,12 +3,18 @@ pub enum Error { /// An error during cryptographic operations Crypto(CryptoError), + /// An error while performing an I/O operation + IOError(std::io::Error), + /// A corrupt keyspace is returned if a keyspace can't be decrypted + CorruptKeyspace, } impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Error::Crypto(e) => f.write_fmt(format_args!("crypto: {e}")), + Error::IOError(e) => f.write_fmt(format_args!("io: {e}")), + Error::CorruptKeyspace => f.write_str("corrupt keyspace"), } } } @@ -56,3 +62,9 @@ impl From for Error { Self::Crypto(value) } } + +impl From for Error { + fn from(value: std::io::Error) -> Self { + Self::IOError(value) + } +} diff --git a/vault/src/keyspace.rs b/vault/src/keyspace.rs index d121a55..86208a6 100644 --- a/vault/src/keyspace.rs +++ b/vault/src/keyspace.rs @@ -5,17 +5,17 @@ mod wasm; mod fallback; #[cfg(target_arch = "wasm32")] -use wasm::KeySpace as KS; +use wasm::KeySpace as Ks; #[cfg(not(target_arch = "wasm32"))] -use fallback::KeySpace as KS; +use fallback::KeySpace as Ks; use crate::{error::Error, key::Key}; /// A keyspace represents a group of stored cryptographic keys. The storage is encrypted, a /// password must be provided when opening the KeySpace to decrypt the keys. pub struct KeySpace { - store: KS, + store: Ks, } /// Wasm32 constructor diff --git a/vault/src/keyspace/fallback.rs b/vault/src/keyspace/fallback.rs index 851097f..cd8cca7 100644 --- a/vault/src/keyspace/fallback.rs +++ b/vault/src/keyspace/fallback.rs @@ -1,2 +1,72 @@ +use std::{collections::HashMap, io::Write, path::PathBuf}; + +use crate::{ + error::Error, + key::{Key, symmetric::SymmetricKey}, +}; + +/// Magic value used as header in decrypted keyspace files. +const KEYSPACE_MAGIC: [u8; 14] = [ + 118, 97, 117, 108, 116, 95, 107, 101, 121, 115, 112, 97, 99, 101, +]; //"vault_keyspace" + /// A KeySpace using the filesystem as storage -pub mod KeySpace {} +pub struct KeySpace { + /// Path to file on disk + path: PathBuf, + /// Decrypted keys held in the store + keystore: HashMap, + /// The encryption key used to encrypt/decrypt the storage. + encryption_key: SymmetricKey, +} + +impl KeySpace { + /// Opens the `KeySpace`. If it does not exist, it will be created. The provided encryption key + /// will be used for Encrypting and Decrypting the content of the KeySpace. + async fn open(path: PathBuf, encryption_key: SymmetricKey) -> Result { + /// If the path does not exist, create it first and write the encrypted magic header + if !path.exists() { + // Since we checked path does not exist, the only errors here can be actual IO errors + // (unless something else creates the same file at the same time). + let mut file = std::fs::File::create_new(path)?; + let content = encryption_key.encrypt(&KEYSPACE_MAGIC)?; + file.write_all(&content)?; + } + + // Load file, try to decrypt, verify magic header, deserialize keystore + let mut file = std::fs::File::open(path)?; + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer)?; + if buffer.len() < KEYSPACE_MAGIC.len() { + return Err(Error::CorruptKeyspace); + } + + if buffer[..KEYSPACE_MAGIC.len()] != KEYSPACE_MAGIC { + return Err(Error::CorruptKeyspace); + } + + // TODO: Actual deserialization + + todo!(); + } + + /// Get a [`Key`] previously stored under the provided name. + async fn get(&self, key: &str) -> Result, Error> { + todo!(); + } + + /// Store a [`Key`] under the provided name. + async fn set(&self, key: &str, value: Key) -> Result<(), Error> { + todo!(); + } + + /// Delete the [`Key`] stored under the provided name. + async fn delete(&self, key: &str) -> Result<(), Error> { + todo!(); + } + + /// Iterate over all stored [`keys`](Key) in the KeySpace + async fn iter(&self) -> Result, Error> { + todo!() + } +} diff --git a/vault/src/keyspace/wasm.rs b/vault/src/keyspace/wasm.rs index cc9ad8e..5c60ddf 100644 --- a/vault/src/keyspace/wasm.rs +++ b/vault/src/keyspace/wasm.rs @@ -1,2 +1,26 @@ +use crate::{error::Error, key::Key}; + /// KeySpace represents an IndexDB keyspace pub struct KeySpace {} + +impl KeySpace { + /// Get a [`Key`] previously stored under the provided name. + async fn get(&self, key: &str) -> Result, Error> { + todo!(); + } + + /// Store a [`Key`] under the provided name. + async fn set(&self, key: &str, value: Key) -> Result<(), Error> { + todo!(); + } + + /// Delete the [`Key`] stored under the provided name. + async fn delete(&self, key: &str) -> Result<(), Error> { + todo!(); + } + + /// Iterate over all stored [`keys`](Key) in the KeySpace + async fn iter(&self) -> Result, Error> { + todo!() + } +}