use std::path::Path;
use std::sync::Arc;
use tessarikv_format::{Cipher, FileKind, FileSealer, RootKey, SealHeader};
use crate::options::Encryption;
use crate::{Error, Result};
#[derive(Debug)]
pub(crate) struct Sealing {
encryption: Encryption,
cipher: Cipher,
}
impl Sealing {
pub(crate) fn new(encryption: &Encryption, cipher: Option<Cipher>) -> Self {
Self {
encryption: encryption.clone(),
cipher: cipher.unwrap_or_else(Cipher::preferred),
}
}
pub(crate) fn key_id(&self) -> u32 {
self.encryption.key_id()
}
pub(crate) fn new_file(&self, kind: FileKind) -> Result<(SealHeader, Arc<FileSealer>)> {
let key_id = self.encryption.key_id();
let header = SealHeader::generate(self.cipher, key_id).map_err(|_| Error::Unsupported {
what: "encrypting a file without the operating system's random source",
})?;
let root = self.root_key(key_id)?;
Ok((header, Arc::new(FileSealer::new(&root, &header, kind))))
}
pub(crate) fn open_file(
&self,
header: &[u8],
kind: FileKind,
path: &Path,
) -> Result<Arc<FileSealer>> {
let header = SealHeader::decode(header).map_err(|error| corruption(path, &error))?;
let root = self.root_key(header.key_id)?;
Ok(Arc::new(FileSealer::new(&root, &header, kind)))
}
fn root_key(&self, key_id: u32) -> Result<RootKey> {
self.encryption
.provider()
.root_key(key_id)
.ok_or(Error::KeyNotFound { key_id })
}
}
pub(crate) fn corruption(path: &Path, error: &tessarikv_format::Error) -> Error {
Error::Corruption {
what: "encrypted file",
path: Some(path.to_path_buf()),
offset: None,
detail: error.to_string(),
}
}