use super::{DataKeyWithTag, DecryptError, RecordWithNonce, RetrieveKeyPayload};
use crate::zerokms::EncryptedRecord;
use recipher::key::Iv;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use zerokms_protocol::DecryptionPolicy;
#[cfg_attr(test, derive(PartialEq, Eq))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyHeader {
#[serde(with = "serde_bytes")]
pub iv: Iv,
#[serde(with = "serde_bytes")]
pub tag: Vec<u8>,
pub descriptor: String,
#[serde(default, rename = "dataset_id")]
pub keyset_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub decryption_policy: Option<DecryptionPolicy>,
}
impl KeyHeader {
pub fn new(
key: &DataKeyWithTag,
descriptor: impl Into<String>,
keyset_id: Option<Uuid>,
) -> Self {
Self {
iv: key.key.iv,
tag: key.tag.clone(),
descriptor: descriptor.into(),
keyset_id,
decryption_policy: key.decryption_policy.clone(),
}
}
pub fn retrieve_key_payload(&self) -> RetrieveKeyPayload<'_> {
let payload = RetrieveKeyPayload::new(self.iv, self.descriptor.as_str(), &self.tag);
if let Some(policy) = &self.decryption_policy {
return payload.with_decryption_policy(policy.clone());
}
payload
}
pub fn record_with_selector(&self, ciphertext: Vec<u8>, selector: [u8; 16]) -> RecordWithNonce {
RecordWithNonce {
record: EncryptedRecord {
iv: self.iv,
ciphertext,
tag: self.tag.clone(),
descriptor: self.descriptor.clone(),
keyset_id: self.keyset_id,
decryption_policy: self.decryption_policy.clone(),
},
selector,
}
}
pub fn to_mp_bytes(&self) -> Result<Vec<u8>, DecryptError> {
rmp_serde::to_vec(&self).map_err(DecryptError::SerializeError)
}
pub fn to_mp_base85(&self) -> Result<String, DecryptError> {
self.to_mp_bytes().map(|v| base85::encode(&v))
}
pub fn from_mp_bytes(bytes: &[u8]) -> Result<Self, DecryptError> {
rmp_serde::from_slice(bytes).map_err(DecryptError::DeserializeError)
}
pub fn from_mp_base85(base85str: &str) -> Result<Self, DecryptError> {
let bytes = base85::decode(base85str)?;
Self::from_mp_bytes(&bytes)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn header() -> KeyHeader {
KeyHeader {
iv: Iv::default(),
tag: vec![1; 16],
descriptor: "users/profile".to_string(),
keyset_id: Some(Uuid::new_v4()),
decryption_policy: None,
}
}
#[test]
fn test_key_header_mp_base85_round_trip() {
let header = header();
let encoded = header.to_mp_base85().unwrap();
assert_eq!(KeyHeader::from_mp_base85(&encoded).unwrap(), header);
}
#[test]
fn test_record_with_selector_reassembly() {
let header = header();
let assembled = header.record_with_selector(vec![7; 32], [9; 16]);
assert_eq!(assembled.selector, [9; 16]);
assert_eq!(assembled.record.ciphertext, vec![7; 32]);
assert_eq!(assembled.record.iv, header.iv);
assert_eq!(assembled.record.tag, header.tag);
assert_eq!(assembled.record.descriptor, header.descriptor);
assert_eq!(assembled.record.keyset_id, header.keyset_id);
}
}