enigma-storage 0.0.1

Encrypted local storage for Enigma with mandatory at-rest encryption and cross-platform key vault providers.
Documentation
use crate::backends::SledBackend;
use crate::crypto::{decrypt_value, encrypt_value};
use crate::error::{EnigmaStorageError, Result};
use crate::key_provider::{KeyProvider, MasterKey};

pub struct EncryptedStore {
    backend: SledBackend,
    key: MasterKey,
    namespace: String,
}

impl EncryptedStore {
    pub fn open(path: &str, namespace: &str, provider: &dyn KeyProvider) -> Result<EncryptedStore> {
        let backend = SledBackend::open(path)?;
        let key = provider.get_or_create_master_key()?;
        Ok(EncryptedStore {
            backend,
            key,
            namespace: namespace.to_owned(),
        })
    }

    pub fn put(&self, key: &str, value: &[u8]) -> Result<()> {
        Self::validate_key(key)?;
        let ciphertext = encrypt_value(&self.key, &self.namespace, key, value)?;
        self.backend.insert(key, &ciphertext)
    }

    pub fn get(&self, key: &str) -> Result<Option<Vec<u8>>> {
        Self::validate_key(key)?;
        let stored = self.backend.get(key)?;
        match stored {
            Some(data) => {
                let value = decrypt_value(&self.key, &self.namespace, key, &data)?;
                Ok(Some(value))
            }
            None => Ok(None),
        }
    }

    pub fn delete(&self, key: &str) -> Result<bool> {
        Self::validate_key(key)?;
        self.backend.remove(key)
    }

    pub fn flush(&self) -> Result<()> {
        self.backend.flush()
    }

    fn validate_key(key: &str) -> Result<()> {
        if key.is_empty() || key.len() > 256 || key.chars().any(|c| c.is_control()) {
            return Err(EnigmaStorageError::InvalidKey);
        }
        Ok(())
    }
}