use oxicrypto::{argon2id_derive, Argon2Params};
use oxistore_core::KvStore;
use crate::aead::AeadKind;
use crate::decorator::EncryptedKv;
use crate::error::EncryptError;
use crate::keys::StaticKey;
#[derive(Debug, Clone, Copy, Default)]
pub enum AeadChoice {
#[default]
XChaCha20Poly1305,
AesGcmSiv256,
}
#[derive(Debug)]
pub enum KeySource {
Raw([u8; 32]),
Passphrase {
passphrase: Vec<u8>,
salt: [u8; 32],
},
}
#[derive(Debug, Default)]
pub struct CipherBuilder {
aead: AeadChoice,
key_source: Option<KeySource>,
}
impl CipherBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn aead(mut self, a: AeadChoice) -> Self {
self.aead = a;
self
}
pub fn key(mut self, k: [u8; 32]) -> Self {
self.key_source = Some(KeySource::Raw(k));
self
}
pub fn passphrase(mut self, p: impl Into<Vec<u8>>, salt: [u8; 32]) -> Self {
self.key_source = Some(KeySource::Passphrase {
passphrase: p.into(),
salt,
});
self
}
pub fn build<S: KvStore>(
self,
store: S,
) -> Result<EncryptedKv<S, StaticKey, AeadKind>, EncryptError> {
let raw_key = self.resolve_key(false)?;
let key_provider = StaticKey::from_array(raw_key);
let kind = match self.aead {
AeadChoice::XChaCha20Poly1305 => AeadKind::XChaCha20Poly1305,
AeadChoice::AesGcmSiv256 => AeadKind::AesGcmSiv256,
};
Ok(EncryptedKv::with_aead(store, key_provider, kind))
}
pub fn build_test<S: KvStore>(
self,
store: S,
) -> Result<EncryptedKv<S, StaticKey, AeadKind>, EncryptError> {
let raw_key = self.resolve_key(true)?;
let key_provider = StaticKey::from_array(raw_key);
let kind = match self.aead {
AeadChoice::XChaCha20Poly1305 => AeadKind::XChaCha20Poly1305,
AeadChoice::AesGcmSiv256 => AeadKind::AesGcmSiv256,
};
Ok(EncryptedKv::with_aead(store, key_provider, kind))
}
fn resolve_key(&self, use_test_params: bool) -> Result<[u8; 32], EncryptError> {
match &self.key_source {
None => Err(EncryptError::InvalidKeyLength { got: 0 }),
Some(KeySource::Raw(k)) => Ok(*k),
Some(KeySource::Passphrase { passphrase, salt }) => {
let params = if use_test_params {
Argon2Params::TEST_PARAMS
} else {
Argon2Params {
m_cost: 65_536,
t_cost: 3,
p_cost: 1,
}
};
let mut key = [0u8; 32];
argon2id_derive(passphrase, salt.as_ref(), params, &mut key)
.map_err(|e| EncryptError::KeyDerivationFailed(e.to_string()))?;
Ok(key)
}
}
}
}