use crate::mac::DecodeError;
use byte::{BytesExt, TryRead, TryWrite, LE};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SecurityControl {
pub(crate) security_level: SecurityLevel,
pub(crate) key_id_mode: KeyIdentifierMode,
}
impl SecurityControl {
pub fn new(security_level: SecurityLevel) -> Self {
Self {
security_level,
key_id_mode: KeyIdentifierMode::None,
}
}
}
impl TryRead<'_> for SecurityControl {
fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
let offset = &mut 0;
let bits: u8 = bytes.read_with(offset, LE)?;
let security_level =
(bits & mask::SECURITY_LEVEL) >> offset::SECURITY_LEVEL;
let key_id_mode =
(bits & mask::KEY_IDENTIFIER_MODE) >> offset::KEY_IDENTIFIER_MODE;
let security_level = SecurityLevel::from_bits(security_level)
.ok_or(DecodeError::InvalidSecurityLevel(security_level))?;
let key_id_mode = KeyIdentifierMode::from_bits(key_id_mode)
.ok_or(DecodeError::InvalidKeyIdentifierMode(key_id_mode))?;
let control = SecurityControl {
security_level,
key_id_mode,
};
Ok((control, *offset))
}
}
impl TryWrite for SecurityControl {
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
let offset = &mut 0;
let bits = (self.security_level.to_bits() << offset::SECURITY_LEVEL)
| (self.key_id_mode.to_bits() << offset::KEY_IDENTIFIER_MODE);
bytes.write(offset, bits)?;
Ok(*offset)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SecurityLevel {
None = 0b000,
MIC32 = 0b001,
MIC64 = 0b010,
MIC128 = 0b011,
ENC = 0b100,
ENCMIC32 = 0b101,
ENCMIC64 = 0b110,
ENCMIC128 = 0b111,
}
impl SecurityLevel {
fn from_bits(bits: u8) -> Option<Self> {
match bits {
0b000 => Some(SecurityLevel::None),
0b001 => Some(SecurityLevel::MIC32),
0b010 => Some(SecurityLevel::MIC64),
0b011 => Some(SecurityLevel::MIC128),
0b100 => Some(SecurityLevel::ENC),
0b101 => Some(SecurityLevel::ENCMIC32),
0b110 => Some(SecurityLevel::ENCMIC64),
0b111 => Some(SecurityLevel::ENCMIC128),
_ => None,
}
}
pub(crate) fn to_bits(&self) -> u8 {
match self {
SecurityLevel::None => 0b000,
SecurityLevel::MIC32 => 0b001,
SecurityLevel::MIC64 => 0b010,
SecurityLevel::MIC128 => 0b011,
SecurityLevel::ENC => 0b100,
SecurityLevel::ENCMIC32 => 0b101,
SecurityLevel::ENCMIC64 => 0b110,
SecurityLevel::ENCMIC128 => 0b111,
}
}
pub fn get_mic_octet_size(&self) -> usize {
match self {
SecurityLevel::None | SecurityLevel::ENC => 0,
SecurityLevel::MIC32 | SecurityLevel::ENCMIC32 => 4,
SecurityLevel::MIC64 | SecurityLevel::ENCMIC64 => 8,
SecurityLevel::MIC128 | SecurityLevel::ENCMIC128 => 16,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum KeyIdentifierMode {
None = 0b00,
KeyIndex = 0b01,
KeySource4 = 0b10,
KeySource8 = 0b11,
}
impl KeyIdentifierMode {
fn from_bits(bits: u8) -> Option<Self> {
match bits {
0b00 => Some(KeyIdentifierMode::None),
0b01 => Some(KeyIdentifierMode::KeyIndex),
0b10 => Some(KeyIdentifierMode::KeySource4),
0b11 => Some(KeyIdentifierMode::KeySource8),
_ => None,
}
}
fn to_bits(&self) -> u8 {
match self {
KeyIdentifierMode::None => 0b00,
KeyIdentifierMode::KeyIndex => 0b01,
KeyIdentifierMode::KeySource4 => 0b10,
KeyIdentifierMode::KeySource8 => 0b11,
}
}
}
mod mask {
pub const SECURITY_LEVEL: u8 = 0x07;
pub const KEY_IDENTIFIER_MODE: u8 = 0x18;
}
mod offset {
pub const SECURITY_LEVEL: u8 = 0;
pub const KEY_IDENTIFIER_MODE: u8 = 3;
}