reticulum-rs-core 0.9.7

Core packet, identity, ratchet, and cryptographic primitives for the Reticulum network stack.
Documentation
use super::*;

#[cfg(feature = "std")]
impl FileKeyManager {
    pub fn new(root: impl Into<std::path::PathBuf>) -> Result<Self, RnsError> {
        let root = root.into();
        crate::secure_storage::ensure_private_directory(&root)
            .map_err(|_| RnsError::ConnectionError)?;
        Ok(Self { root })
    }

    fn path_for_key(&self, key_id: &str) -> Result<std::path::PathBuf, RnsError> {
        if !is_valid_key_id(key_id) {
            return Err(RnsError::InvalidArgument);
        }
        Ok(self.root.join(format!("{key_id}.key")))
    }
}

#[cfg(feature = "std")]
impl KeyManagerBackend for FileKeyManager {
    fn backend_id(&self) -> &'static str {
        "file"
    }

    fn get(&self, key_id: &str) -> Result<Option<StoredKey>, RnsError> {
        let path = self.path_for_key(key_id)?;
        if !path.exists() {
            return Ok(None);
        }
        let bytes = std::fs::read(path).map_err(|_| RnsError::ConnectionError)?;
        let key = rmp_serde::from_slice::<StoredKey>(&bytes).map_err(|_| RnsError::PacketError)?;
        Ok(Some(key))
    }

    fn put(&self, key: StoredKey) -> Result<(), RnsError> {
        let path = self.path_for_key(key.key_id.as_str())?;
        let bytes = rmp_serde::to_vec_named(&key).map_err(|_| RnsError::PacketError)?;
        crate::secure_storage::atomic_write_private(&path, &bytes)
            .map_err(|_| RnsError::ConnectionError)?;
        Ok(())
    }

    fn delete(&self, key_id: &str) -> Result<(), RnsError> {
        let path = self.path_for_key(key_id)?;
        match std::fs::remove_file(path) {
            Ok(_) => Ok(()),
            Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()),
            Err(_) => Err(RnsError::ConnectionError),
        }
    }

    fn list_ids(&self) -> Result<Vec<String>, RnsError> {
        let entries = std::fs::read_dir(&self.root).map_err(|_| RnsError::ConnectionError)?;
        let mut ids = Vec::new();
        for entry in entries {
            let entry = entry.map_err(|_| RnsError::ConnectionError)?;
            let path = entry.path();
            if path.extension().and_then(|extension| extension.to_str()) != Some("key") {
                continue;
            }
            if let Some(stem) = path.file_stem().and_then(|stem| stem.to_str()) {
                ids.push(String::from(stem));
            }
        }
        ids.sort();
        Ok(ids)
    }
}

pub trait OsKeyStoreHook {
    fn get(&self, key_id: &str) -> Result<Option<StoredKey>, RnsError>;
    fn put(&self, key: StoredKey) -> Result<(), RnsError>;
    fn delete(&self, key_id: &str) -> Result<(), RnsError>;
    fn list_ids(&self) -> Result<Vec<String>, RnsError>;
}

pub struct OsKeyStoreKeyManager<H> {
    hook: H,
}

impl<H> OsKeyStoreKeyManager<H> {
    pub fn new(hook: H) -> Self {
        Self { hook }
    }
}

impl<H: OsKeyStoreHook> KeyManagerBackend for OsKeyStoreKeyManager<H> {
    fn backend_id(&self) -> &'static str {
        "os-keystore"
    }

    fn get(&self, key_id: &str) -> Result<Option<StoredKey>, RnsError> {
        self.hook.get(key_id)
    }

    fn put(&self, key: StoredKey) -> Result<(), RnsError> {
        self.hook.put(key)
    }

    fn delete(&self, key_id: &str) -> Result<(), RnsError> {
        self.hook.delete(key_id)
    }

    fn list_ids(&self) -> Result<Vec<String>, RnsError> {
        self.hook.list_ids()
    }
}

pub trait HsmKeyStoreHook {
    fn get(&self, key_id: &str) -> Result<Option<StoredKey>, RnsError>;
    fn put(&self, key: StoredKey) -> Result<(), RnsError>;
    fn delete(&self, key_id: &str) -> Result<(), RnsError>;
    fn list_ids(&self) -> Result<Vec<String>, RnsError>;
}

pub struct HsmKeyManager<H> {
    hook: H,
}

impl<H> HsmKeyManager<H> {
    pub fn new(hook: H) -> Self {
        Self { hook }
    }
}

impl<H: HsmKeyStoreHook> KeyManagerBackend for HsmKeyManager<H> {
    fn backend_id(&self) -> &'static str {
        "hsm"
    }

    fn get(&self, key_id: &str) -> Result<Option<StoredKey>, RnsError> {
        self.hook.get(key_id)
    }

    fn put(&self, key: StoredKey) -> Result<(), RnsError> {
        self.hook.put(key)
    }

    fn delete(&self, key_id: &str) -> Result<(), RnsError> {
        self.hook.delete(key_id)
    }

    fn list_ids(&self) -> Result<Vec<String>, RnsError> {
        self.hook.list_ids()
    }
}