use super::{
KeyDescriptorLookup, KeyIdentifierMode, SecurityContext, SecurityControl,
};
use byte::{BytesExt, TryRead, TryWrite, LE};
use cipher::{consts::U16, BlockCipher, NewBlockCipher};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AuxiliarySecurityHeader {
pub control: SecurityControl,
pub(crate) frame_counter: u32,
pub key_identifier: Option<KeyIdentifier>,
}
impl AuxiliarySecurityHeader {
pub fn get_octet_size(&self) -> usize {
let length = 1
+ 4
+ match self.key_identifier {
Some(key_id) => match key_id.key_source {
Some(source) => match source {
KeySource::Short(_) => 5,
KeySource::Long(_) => 9,
},
None => 1,
},
None => 0,
};
length
}
pub fn new(
control: SecurityControl,
key_identifier: Option<KeyIdentifier>,
) -> Self {
Self {
control,
key_identifier,
frame_counter: 0,
}
}
pub unsafe fn new_unsafe(
control: SecurityControl,
key_identifier: Option<KeyIdentifier>,
frame_counter: u32,
) -> Self {
Self {
control,
key_identifier,
frame_counter,
}
}
pub fn get_frame_counter(&self) -> u32 {
self.frame_counter
}
}
impl TryRead<'_> for AuxiliarySecurityHeader {
fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
let offset = &mut 0;
let control: SecurityControl = bytes.read(offset)?;
let frame_counter = bytes.read_with(offset, LE)?;
let mut header = AuxiliarySecurityHeader {
control,
frame_counter,
key_identifier: None,
};
if control.key_id_mode != KeyIdentifierMode::None {
let mut key_identifier = KeyIdentifier {
key_source: None,
key_index: 0,
};
match control.key_id_mode {
KeyIdentifierMode::KeySource4 => {
key_identifier.key_source =
Some(KeySource::Short(bytes.read(offset)?));
}
KeyIdentifierMode::KeySource8 => {
key_identifier.key_source =
Some(KeySource::Long(bytes.read(offset)?));
}
_ => {}
}
let key_index = bytes.read(offset)?;
key_identifier.key_index = key_index;
header.key_identifier = Some(key_identifier);
}
Ok((header, *offset))
}
}
impl<AEADBLKCIPH, KEYDESCLO> TryWrite<&SecurityContext<AEADBLKCIPH, KEYDESCLO>>
for AuxiliarySecurityHeader
where
AEADBLKCIPH: NewBlockCipher + BlockCipher<BlockSize = U16>,
KEYDESCLO: KeyDescriptorLookup<AEADBLKCIPH::KeySize>,
{
fn try_write(
mut self,
bytes: &mut [u8],
sec_ctx: &SecurityContext<AEADBLKCIPH, KEYDESCLO>,
) -> byte::Result<usize> {
let offset = &mut 0;
self.control.key_id_mode = match self.key_identifier {
Some(key_id) => match key_id.key_source {
Some(key_source) => match key_source {
KeySource::Short(_) => KeyIdentifierMode::KeySource4,
KeySource::Long(_) => KeyIdentifierMode::KeySource8,
},
None => KeyIdentifierMode::KeyIndex,
},
None => KeyIdentifierMode::None,
};
bytes.write(offset, self.control)?;
bytes.write(offset, sec_ctx.frame_counter)?;
match self.key_identifier {
Some(key_identifier) => {
bytes.write(offset, key_identifier)?;
}
_ => {}
}
Ok(*offset)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct KeyIdentifier {
pub key_source: Option<KeySource>,
pub key_index: u8,
}
impl TryWrite for KeyIdentifier {
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
let offset = &mut 0;
match self.key_source {
Some(source) => match source {
KeySource::Short(src) => bytes.write(offset, src)?,
KeySource::Long(src) => bytes.write(offset, src)?,
},
_ => {}
}
bytes.write(offset, self.key_index)?;
Ok(*offset)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum KeySource {
Short(u32),
Long(u64),
}