use crate::{
crypto::{
aead::AeadDecrypt,
buffer::{AadData, decryption::DecryptionBuffer},
key_derivation::KeyDerivation,
},
error::{Result, SframeError},
header::SframeHeader,
key::KeyStore,
};
use super::{
FrameBuffer, FrameValidation,
media_frame::{MediaFrame, MediaFrameView},
};
#[derive(Clone, Copy, Debug)]
pub struct EncryptedFrameView<'buf> {
header: SframeHeader,
meta_data: &'buf [u8],
header_buf: &'buf [u8],
cipher_text: &'buf [u8],
}
impl<'ibuf> EncryptedFrameView<'ibuf> {
pub fn try_new<D>(data: &'ibuf D) -> Result<Self>
where
D: AsRef<[u8]> + ?Sized,
{
EncryptedFrameView::try_with_meta_data(data, &[])
}
pub fn try_with_meta_data<D, M>(data: &'ibuf D, meta_data: &'ibuf M) -> Result<Self>
where
D: AsRef<[u8]> + ?Sized,
M: AsRef<[u8]> + ?Sized,
{
let header = SframeHeader::deserialize(data)?;
log::trace!("EncryptedFrame # {} with header {header}", header.counter());
let (header_buf, cipher_text) = data.as_ref().split_at(header.len());
Ok(Self {
header,
meta_data: meta_data.as_ref(),
header_buf,
cipher_text,
})
}
pub(super) fn with_header<D, M>(
header: SframeHeader,
data: &'ibuf D,
meta_data: &'ibuf M,
) -> Self
where
D: AsRef<[u8]> + ?Sized,
M: AsRef<[u8]> + ?Sized,
{
let (header_buf, cipher_text) = data.as_ref().split_at(header.len());
Self {
header,
meta_data: meta_data.as_ref(),
header_buf,
cipher_text,
}
}
pub fn header(&self) -> &SframeHeader {
&self.header
}
pub fn meta_data(&self) -> &[u8] {
self.meta_data
}
pub fn cipher_text(&self) -> &[u8] {
self.cipher_text
}
pub fn validate<V>(self, validator: &V) -> Result<Self>
where
V: FrameValidation + ?Sized,
{
log::trace!("Validating EncryptedFrame # {}", self.header.counter());
validator.validate(&self.header)?;
Ok(self)
}
pub fn decrypt<A, D>(&self, key_store: &impl KeyStore<A, D>) -> Result<MediaFrame>
where
A: AeadDecrypt<Secret = D::Secret>,
D: KeyDerivation,
{
let mut buffer = Vec::new();
let view = self.decrypt_into(key_store, &mut buffer)?;
Ok(MediaFrame::with_buffer(
view.counter(),
buffer,
self.meta_data.len(),
))
}
pub fn decrypt_into<'obuf, A, D>(
&self,
key_store: &impl KeyStore<A, D>,
buffer: &'obuf mut impl FrameBuffer,
) -> Result<MediaFrameView<'obuf>>
where
A: AeadDecrypt<Secret = D::Secret>,
D: KeyDerivation,
{
let counter = self.header().counter();
let key_id = self.header.key_id();
log::trace!("Trying to decrypt EncryptedFrame # {counter} with KeyId {key_id}");
let key = key_store
.get_key(key_id)
.ok_or(SframeError::MissingDecryptionKey(key_id))?;
let mut decryption_buffer = DecryptionBuffer::try_allocate(buffer, self, self.cipher_text)?;
key.decrypt(&mut decryption_buffer, counter)?;
let meta_len = self.meta_data.len();
decryption_buffer.truncate(key.cipher_suite(), meta_len);
let buffer_slice: &mut [u8] = decryption_buffer.into();
let (meta_data, payload) = buffer_slice.split_at(meta_len);
let media_frame = MediaFrameView::with_meta_data_and_ctr(counter, payload, meta_data);
Ok(media_frame)
}
}
impl AadData for EncryptedFrameView<'_> {
fn len(&self) -> usize {
self.header.len() + self.meta_data.len()
}
fn serialize(&self, buffer: &mut [u8]) -> Result<()> {
let (meta_data, header) = buffer.split_at_mut(self.meta_data.len());
meta_data.copy_from_slice(self.meta_data);
header.copy_from_slice(self.header_buf);
Ok(())
}
}
impl<'buf> TryFrom<&'buf [u8]> for EncryptedFrameView<'buf> {
type Error = SframeError;
fn try_from(data: &'buf [u8]) -> Result<Self> {
EncryptedFrameView::try_new(data)
}
}
impl<'buf> TryFrom<&'buf Vec<u8>> for EncryptedFrameView<'buf> {
type Error = SframeError;
fn try_from(data: &'buf Vec<u8>) -> Result<Self> {
EncryptedFrameView::try_new(data)
}
}
pub struct EncryptedFrame {
buffer: Vec<u8>,
header: SframeHeader,
meta_len: usize,
}
impl EncryptedFrame {
pub fn try_new<D>(data: D) -> Result<Self>
where
D: AsRef<[u8]>,
{
EncryptedFrame::try_with_meta_data(data, [])
}
pub fn try_with_meta_data<D, M>(data: D, meta_data: M) -> Result<Self>
where
D: AsRef<[u8]>,
M: AsRef<[u8]>,
{
let data = data.as_ref();
let meta_data = meta_data.as_ref();
let header = SframeHeader::deserialize(data)?;
log::trace!(
"EncryptedFrame # {} with header {}",
header.counter(),
header
);
let meta_len = meta_data.len();
let mut buffer = Vec::with_capacity(data.len() + meta_len);
buffer.extend(meta_data);
buffer.extend(data);
Ok(Self {
buffer,
header,
meta_len,
})
}
pub(super) fn from_buffer(buffer: Vec<u8>, header: SframeHeader, meta_len: usize) -> Self {
EncryptedFrame {
buffer,
header,
meta_len,
}
}
pub fn header(&self) -> &SframeHeader {
&self.header
}
pub fn meta_data(&self) -> &[u8] {
&self.buffer[..self.meta_len]
}
pub fn cipher_text(&self) -> &[u8] {
&self.buffer[self.meta_len + self.header.len()..]
}
pub fn validate<V>(self, validator: &V) -> Result<Self>
where
V: FrameValidation + ?Sized,
{
log::trace!("Validating EncryptedFrame # {}", self.header.counter());
validator.validate(&self.header)?;
Ok(self)
}
pub fn decrypt<A, D>(&self, key_store: &impl KeyStore<A, D>) -> Result<MediaFrame>
where
A: AeadDecrypt<Secret = D::Secret>,
D: KeyDerivation,
{
let view = EncryptedFrameView::with_header(
self.header,
&self.buffer[self.meta_len..],
self.meta_data(),
);
view.decrypt(key_store)
}
pub fn decrypt_into<'obuf, A, D>(
&self,
key_store: &impl KeyStore<A, D>,
buffer: &'obuf mut impl FrameBuffer,
) -> Result<MediaFrameView<'obuf>>
where
A: AeadDecrypt<Secret = D::Secret>,
D: KeyDerivation,
{
let view = EncryptedFrameView::with_header(
self.header,
&self.buffer[self.meta_len..],
self.meta_data(),
);
view.decrypt_into(key_store, buffer)
}
}
impl AsRef<[u8]> for EncryptedFrame {
fn as_ref(&self) -> &[u8] {
self.buffer.as_slice()
}
}
impl TryFrom<&[u8]> for EncryptedFrame {
type Error = SframeError;
fn try_from(data: &[u8]) -> Result<Self> {
EncryptedFrame::try_new(data)
}
}
impl TryFrom<&Vec<u8>> for EncryptedFrame {
type Error = SframeError;
fn try_from(data: &Vec<u8>) -> Result<Self> {
EncryptedFrame::try_new(data)
}
}
#[cfg(test)]
mod test {
use super::EncryptedFrameView;
use crate::{frame::encrypted_frame::EncryptedFrame, header::SframeHeader};
use pretty_assertions::assert_eq;
#[test]
fn new_encrypted_frame_view_with_meta_data() {
let meta_data = [42u8, 43u8];
let header = SframeHeader::new(42, 666);
let header_buf = Vec::from(&header);
let cipher_text = vec![6u8; 3];
let data = [header_buf.clone(), cipher_text.clone()].concat();
let frame_view = EncryptedFrameView::try_with_meta_data(&data, &meta_data).unwrap();
assert_eq!(frame_view.header(), &header);
assert_eq!(frame_view.cipher_text(), &cipher_text);
assert_eq!(frame_view.meta_data(), meta_data);
}
#[test]
fn new_encrypted_frame_with_meta_data() {
let meta_data = [42u8, 43u8];
let header = SframeHeader::new(42, 666);
let header_buf = Vec::from(&header);
let cipher_text = vec![6u8; 3];
let data = [header_buf.clone(), cipher_text.clone()].concat();
let frame = EncryptedFrame::try_with_meta_data(data, meta_data).unwrap();
assert_eq!(frame.header(), &header);
assert_eq!(frame.cipher_text(), &cipher_text);
assert_eq!(frame.meta_data(), meta_data);
}
}