const MASTER_KEY_LEN: usize = 32;
const STORAGE_KEY_LEN: usize = 32;
#[derive(Debug, PartialEq)]
pub struct MasterKey {
pub inner: [u8; MASTER_KEY_LEN],
}
impl MasterKey {
pub fn generate() -> Self {
use rand::Rng;
let mut rng = rand::thread_rng();
let mut inner = [0_u8; MASTER_KEY_LEN];
rng.fill(&mut inner);
Self { inner }
}
pub fn from_slice(
slice: &[u8],
) -> Result<Self, std::array::TryFromSliceError> {
let inner = slice.try_into()?;
Ok(Self { inner })
}
}
impl From<MasterKey> for Vec<u8> {
fn from(val: MasterKey) -> Self {
val.inner.to_vec()
}
}
#[derive(Debug, PartialEq)]
pub struct StorageServiceKey {
pub inner: [u8; STORAGE_KEY_LEN],
}
impl StorageServiceKey {
pub fn from_master_key(master_key: &MasterKey) -> Self {
use hmac::{Hmac, Mac};
use sha2::Sha256;
type HmacSha256 = Hmac<Sha256>;
const KEY: &[u8] = b"Storage Service Encryption";
let mut mac = HmacSha256::new_from_slice(&master_key.inner).unwrap();
mac.update(KEY);
let result = mac.finalize();
let inner: [u8; STORAGE_KEY_LEN] = result.into_bytes().into();
Self { inner }
}
pub fn from_slice(
slice: &[u8],
) -> Result<Self, std::array::TryFromSliceError> {
let inner = slice.try_into()?;
Ok(Self { inner })
}
}
impl From<StorageServiceKey> for Vec<u8> {
fn from(val: StorageServiceKey) -> Self {
val.inner.to_vec()
}
}
pub trait MasterKeyStore {
fn fetch_master_key(&self) -> Option<MasterKey>;
fn fetch_storage_service_key(&self) -> Option<StorageServiceKey>;
fn store_master_key(&self, master_key: Option<&MasterKey>);
fn store_storage_service_key(
&self,
storage_key: Option<&StorageServiceKey>,
);
}
mod tests {
#[test]
fn derive_storage_key_from_master_key() {
use super::{MasterKey, StorageServiceKey};
use base64::prelude::*;
let master_key_bytes = BASE64_STANDARD
.decode("9hquLIIZmom8fHF7H8pbUAreawmPLEqli5ceJ94pFkU=")
.unwrap();
let storage_key_bytes = BASE64_STANDARD
.decode("QMgZ5RGTLFTr4u/J6nypaJX6DKDlSgMw8vmxU6gxnvI=")
.unwrap();
assert_eq!(master_key_bytes.len(), 32);
assert_eq!(storage_key_bytes.len(), 32);
let master_key = MasterKey::from_slice(&master_key_bytes).unwrap();
let storage_key = StorageServiceKey::from_master_key(&master_key);
assert_eq!(master_key.inner, master_key_bytes.as_slice());
assert_eq!(storage_key.inner, storage_key_bytes.as_slice());
}
}