use crate::endpoint_crypto_container::EndpointRatchetConstructor;
use crate::misc::CryptError;
use bytes::BytesMut;
use citadel_pqcrypto::bytes_in_place::EzBuffer;
use citadel_pqcrypto::constructor_opts::ConstructorOpts;
use citadel_pqcrypto::PostQuantumContainer;
use citadel_types::crypto::SecurityLevel;
use entropy_bank::EntropyBank;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::fmt::Debug;
pub mod entropy_bank;
pub mod mono;
pub mod ratchet_manager;
pub mod stacked;
pub trait Ratchet:
Debug + Serialize + for<'a> Deserialize<'a> + Clone + Send + Sync + 'static
{
type Constructor: EndpointRatchetConstructor<Self> + Serialize + for<'a> Deserialize<'a>;
fn get_cid(&self) -> u64 {
self.get_message_pqc_and_entropy_bank_at_layer(None)
.expect("StackedRatchet::get_cid")
.1
.cid
}
fn version(&self) -> u32 {
self.get_message_pqc_and_entropy_bank_at_layer(None)
.expect("StackedRatchet::version")
.1
.version
}
fn has_verified_packets(&self) -> bool {
let max = self.message_ratchet_count();
for n in 0..max {
if let Ok((pqc, _entropy_bank)) =
self.get_message_pqc_and_entropy_bank_at_layer(Some(n))
{
if pqc.has_verified_packets() {
return true;
}
}
}
self.get_scramble_pqc_and_entropy_bank()
.0
.has_verified_packets()
}
fn reset_ara(&self) {
let max = self.message_ratchet_count();
for n in 0..max {
if let Ok((pqc, _entropy_bank)) =
self.get_message_pqc_and_entropy_bank_at_layer(Some(n))
{
pqc.reset_counters();
}
}
self.get_scramble_pqc_and_entropy_bank().0.reset_counters()
}
fn get_default_security_level(&self) -> SecurityLevel;
fn get_message_pqc_and_entropy_bank_at_layer(
&self,
idx: Option<usize>,
) -> Result<(&PostQuantumContainer, &EntropyBank), CryptError>;
fn get_scramble_pqc_and_entropy_bank(&self) -> (&PostQuantumContainer, &EntropyBank);
fn get_next_constructor_opts(&self) -> Vec<ConstructorOpts>;
fn protect_message_packet<T: EzBuffer>(
&self,
security_level: Option<SecurityLevel>,
header_len_bytes: usize,
packet: &mut T,
) -> Result<(), CryptError<String>> {
let idx = self.verify_level(security_level)?;
for n in 0..=idx {
let (pqc, entropy_bank) = self.get_message_pqc_and_entropy_bank_at_layer(Some(n))?;
entropy_bank.protect_packet(pqc, header_len_bytes, packet)?;
}
Ok(())
}
fn validate_message_packet<H: AsRef<[u8]>, T: EzBuffer>(
&self,
security_level: Option<SecurityLevel>,
header: H,
packet: &mut T,
) -> Result<(), CryptError<String>> {
let idx = self.verify_level(security_level)?;
for n in (0..=idx).rev() {
let (pqc, entropy_bank) = self.get_message_pqc_and_entropy_bank_at_layer(Some(n))?;
entropy_bank.validate_packet_in_place_split(pqc, &header, packet)?;
}
Ok(())
}
fn next_alice_constructor(&self) -> Option<Self::Constructor> {
Self::Constructor::new_alice(
self.get_next_constructor_opts(),
self.get_cid(),
self.version().wrapping_add(1),
)
}
fn local_encrypt<'a, T: Into<Cow<'a, [u8]>>>(
&self,
contents: T,
security_level: SecurityLevel,
) -> Result<Vec<u8>, CryptError> {
let idx = self.verify_level(Some(security_level))?;
let mut data = contents.into();
for n in 0..=idx {
let (pqc, entropy_bank) = self.get_message_pqc_and_entropy_bank_at_layer(Some(n))?;
data = Cow::Owned(entropy_bank.local_encrypt(pqc, &data)?);
}
Ok(data.into_owned())
}
fn local_decrypt<'a, T: Into<Cow<'a, [u8]>>>(
&self,
contents: T,
security_level: SecurityLevel,
) -> Result<Vec<u8>, CryptError> {
let mut data = contents.into();
if data.is_empty() {
return Ok(vec![]);
}
let idx = self.verify_level(Some(security_level))?;
for n in (0..=idx).rev() {
let (pqc, entropy_bank) = self.get_message_pqc_and_entropy_bank_at_layer(Some(n))?;
data = Cow::Owned(entropy_bank.local_decrypt(pqc, &data)?);
}
Ok(data.into_owned())
}
fn message_ratchet_count(&self) -> usize;
fn verify_level(
&self,
security_level: Option<SecurityLevel>,
) -> Result<usize, CryptError<String>> {
let security_level = security_level.unwrap_or(SecurityLevel::Standard);
let message_ratchet_count = self.message_ratchet_count();
if security_level.value() as usize >= message_ratchet_count {
log::warn!(target: "citadel", "OOB: Security value: {}, max: {} (default: {:?})|| Version: {}", security_level.value() as usize, message_ratchet_count- 1, self.get_default_security_level(), self.version());
Err(CryptError::OutOfBoundsError)
} else {
Ok(security_level.value() as usize)
}
}
fn validate_message_packet_in_place_split<H: AsRef<[u8]>>(
&self,
security_level: Option<SecurityLevel>,
header: H,
packet: &mut BytesMut,
) -> Result<(), CryptError<String>> {
let idx = self.verify_level(security_level)?;
for n in (0..=idx).rev() {
let (pqc, entropy_bank) = self.get_message_pqc_and_entropy_bank_at_layer(Some(n))?;
entropy_bank.validate_packet_in_place_split(pqc, &header, packet)?;
}
Ok(())
}
fn decrypt<T: AsRef<[u8]>>(&self, contents: T) -> Result<Vec<u8>, CryptError<String>> {
let (pqc, entropy_bank) = self.get_message_pqc_and_entropy_bank_at_layer(None)?;
entropy_bank.decrypt(pqc, contents)
}
fn encrypt<T: AsRef<[u8]>>(&self, contents: T) -> Result<Vec<u8>, CryptError<String>> {
let (pqc, entropy_bank) = self.get_message_pqc_and_entropy_bank_at_layer(None)?;
entropy_bank.encrypt(pqc, contents)
}
}