use std::collections::HashMap;
use std::future::Future;
use std::sync::Arc;
use tokio::sync::Mutex;
use zeroize::Zeroizing;
use crate::error::DataError;
pub type DataKey = Zeroizing<Vec<u8>>;
pub type WrappedDataKey = Vec<u8>;
pub type KeyAlias = str;
pub(crate) mod private {
pub trait Sealed {}
}
pub trait KeyProvider: private::Sealed + Send + Sync {
fn generate_data_key(
&self,
alias: &KeyAlias,
) -> impl Future<Output = Result<(DataKey, WrappedDataKey, String), DataError>> + Send;
fn unwrap_data_key(
&self,
wrapped: &WrappedDataKey,
alias: &KeyAlias,
version: &str,
) -> impl Future<Output = Result<DataKey, DataError>> + Send;
}
pub struct StaticDevKeyProvider {
keys: Arc<Mutex<HashMap<String, Zeroizing<Vec<u8>>>>>,
}
impl StaticDevKeyProvider {
#[must_use]
pub fn new() -> Self {
let mut keys = HashMap::new();
keys.insert("default".to_string(), Zeroizing::new(vec![0x42u8; 32]));
Self {
keys: Arc::new(Mutex::new(keys)),
}
}
async fn kek_for(&self, alias: &str) -> Zeroizing<Vec<u8>> {
let mut map = self.keys.lock().await;
if let Some(k) = map.get(alias) {
return k.clone();
}
let mut key = vec![0u8; 32];
for (i, b) in alias.bytes().enumerate() {
key[i % 32] ^= b;
}
key[0] |= 0x01;
let kek = Zeroizing::new(key);
map.insert(alias.to_string(), kek.clone());
kek
}
}
impl Default for StaticDevKeyProvider {
fn default() -> Self {
Self::new()
}
}
impl private::Sealed for StaticDevKeyProvider {}
impl KeyProvider for StaticDevKeyProvider {
fn generate_data_key(
&self,
alias: &KeyAlias,
) -> impl Future<Output = Result<(DataKey, WrappedDataKey, String), DataError>> + Send {
let alias = alias.to_string();
let keys = Arc::clone(&self.keys);
async move {
use rand::RngCore;
let mut dek = vec![0u8; 32];
rand::rngs::OsRng.fill_bytes(&mut dek);
let dek = Zeroizing::new(dek);
let provider = StaticDevKeyProvider {
keys: Arc::clone(&keys),
};
let kek = provider.kek_for(&alias).await;
let wrapped: Vec<u8> = dek
.iter()
.zip(kek.iter().cycle())
.map(|(d, k)| d ^ k)
.collect();
Ok((dek, wrapped, "v1".to_string()))
}
}
fn unwrap_data_key(
&self,
wrapped: &WrappedDataKey,
alias: &KeyAlias,
_version: &str,
) -> impl Future<Output = Result<DataKey, DataError>> + Send {
let alias = alias.to_string();
let wrapped = wrapped.clone();
let keys = Arc::clone(&self.keys);
async move {
let provider = StaticDevKeyProvider {
keys: Arc::clone(&keys),
};
let kek = provider.kek_for(&alias).await;
let dek: Vec<u8> = wrapped
.iter()
.zip(kek.iter().cycle())
.map(|(w, k)| w ^ k)
.collect();
Ok(Zeroizing::new(dek))
}
}
}