mod encrypted_entry;
mod encrypted_term;
pub(super) mod priv_state;
mod selector;
mod ste_plaintext_vec;
use crate::{ejsonpath::Selector, encryption::EncryptionError};
use crate::{
encryption::{BytesWithDescriptor, Plaintext},
zerokms::{self, encrypt, DataKeyWithTag, EncryptedRecord},
};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
pub use encrypted_entry::EncryptedEntry;
pub use ste_plaintext_vec::StePlaintextVec;
pub use encrypted_term::EncryptedSteVecTerm;
pub use selector::TokenizedSelector;
#[derive(Debug, Serialize, Deserialize)]
pub struct SteVec<const N: usize>(pub(super) Vec<EncryptedEntry<N>>);
impl<const N: usize> SteVec<N> {
pub fn into_root_ciphertext(self) -> Result<EncryptedRecord, EncryptionError> {
self.0
.into_iter()
.next()
.map(|enc| enc.record)
.ok_or_else(|| EncryptionError::InvalidValue("SteVec missing root record".to_string()))
}
pub fn root_ciphertext(&self) -> Result<&EncryptedRecord, EncryptionError> {
self.0
.first()
.map(|enc| &enc.record)
.ok_or_else(|| EncryptionError::InvalidValue("SteVec missing root record".to_string()))
}
}
impl IntoIterator for SteVec<16> {
type Item = EncryptedEntry<16>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
pub struct SteVecPendingEncryption<const N: usize>(Vec<EntryWithEncryptedTerm<N>>);
impl<const N: usize> SteVecPendingEncryption<N> {
pub fn encrypt(self, key: DataKeyWithTag) -> Result<SteVec<N>, zerokms::Error> {
self.0
.into_iter()
.map(|entry| entry.build_final(key.clone()))
.try_collect()
.map(SteVec)
}
pub fn into_query(self) -> SteQueryVec<N> {
SteQueryVec::from(self)
}
}
struct EntryWithEncryptedTerm<const N: usize> {
tokenized_selector: TokenizedSelector<N>,
term: EncryptedSteVecTerm,
plaintext: Plaintext,
parent_is_array: bool,
}
impl<const N: usize> EntryWithEncryptedTerm<N> {
fn build_final(self, key: DataKeyWithTag) -> Result<EncryptedEntry<N>, zerokms::Error> {
let bwd = BytesWithDescriptor::from((&self.plaintext, ""));
let ciphertext = encrypt(&bwd, key, None)?;
Ok(EncryptedEntry::new(
self.tokenized_selector,
self.term,
ciphertext,
self.parent_is_array,
))
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct QueryEntry<const N: usize>(
pub(super) TokenizedSelector<N>,
pub(super) EncryptedSteVecTerm,
);
impl<const N: usize> From<EntryWithEncryptedTerm<N>> for QueryEntry<N> {
fn from(entry: EntryWithEncryptedTerm<N>) -> Self {
Self(entry.tokenized_selector, entry.term)
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct SteQueryVec<const N: usize>(pub(super) Vec<QueryEntry<N>>);
impl<const N: usize> From<SteVecPendingEncryption<N>> for SteQueryVec<N> {
fn from(pending: SteVecPendingEncryption<N>) -> Self {
Self(pending.0.into_iter().map(QueryEntry::from).collect())
}
}
#[cfg(test)]
mod tests {
use crate::encryption::json_indexer::{
prefix_mac::{PrefixMac, UpdatePrefixMac},
ste_vec::{
encrypted_term::{EncryptedSteVecTerm, Mac},
EncryptedEntry, TokenizedSelector,
},
};
use recipher::key::Iv;
use std::fmt::Debug;
use uuid::Uuid;
#[macro_export]
macro_rules! boxed {
($($literal:expr),*) => {
&[$(Box::new($literal)),*]
};
}
#[macro_export]
macro_rules! assert_was_finalized_with {
($macca:expr, $($term:expr),*) => {
$macca.assert_was_finalized_with($crate::boxed!($($term),*))
};
}
#[derive(Default)]
pub struct TestPrefixMac {
pub pending_terms: Vec<Box<dyn Debug>>,
pub finalized_terms: Vec<Box<dyn Debug>>,
}
impl TestPrefixMac {
pub fn assert_was_finalized_with(&self, terms: &[Box<dyn Debug>]) {
let x = self
.finalized_terms
.iter()
.map(|term| format!("{term:?}"))
.collect::<Vec<_>>();
let y = terms
.iter()
.map(|term| format!("{term:?}"))
.collect::<Vec<_>>();
assert_eq!(x, y, "Expected MAC updates to be {y:#?}, got {x:#?}");
}
}
impl PrefixMac for TestPrefixMac {
fn finalize_reset<const N: usize>(&mut self) -> [u8; N] {
self.finalized_terms = self.pending_terms.drain(..).collect();
[0; N]
}
}
impl UpdatePrefixMac<String> for TestPrefixMac {
fn update(&mut self, value: String) {
self.pending_terms.push(Box::new(value));
}
}
impl UpdatePrefixMac<&str> for TestPrefixMac {
fn update(&mut self, value: &str) {
self.update(value.to_string());
}
}
impl UpdatePrefixMac<[u8; 16]> for TestPrefixMac {
fn update(&mut self, value: [u8; 16]) {
self.pending_terms.push(Box::new(value));
}
}
#[test]
fn test_serde_encrypted_entry() {
use crate::zerokms::EncryptedRecord;
let ciphertext = EncryptedRecord {
iv: Iv::default(),
ciphertext: vec![1; 32],
tag: vec![1; 16],
descriptor: "users/name".to_string(),
keyset_id: Some(Uuid::new_v4()),
};
let entry = EncryptedEntry::new(
TokenizedSelector([1; 16]),
EncryptedSteVecTerm::Mac(Mac::new(vec![2; 16])),
ciphertext,
false,
);
let serialized = serde_json::to_string(&entry).unwrap();
assert_eq!(
serde_json::from_str::<EncryptedEntry<16>>(&serialized).unwrap(),
entry
);
}
}