pub const WEP40_KEY_LENGTH: usize = 5;
pub const WEP104_KEY_LENGTH: usize = 13;
pub const TKIP_KEY_LENGTH: usize = 16;
pub const AES_128_KEY_LENGTH: usize = 16;
pub const AES_256_KEY_LENGTH: usize = 32;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MultiLengthKey<'a, const SHORT: usize, const LONG: usize> {
Short(&'a [u8; SHORT]),
Long(&'a [u8; LONG]),
}
impl<const SHORT: usize, const LONG: usize> MultiLengthKey<'_, SHORT, LONG> {
pub const fn key_length(&self) -> usize {
if let Self::Short(_) = self {
SHORT
} else {
LONG
}
}
pub const fn key(&self) -> &[u8] {
match self {
Self::Short(key) => key.as_slice(),
Self::Long(key) => key.as_slice(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum KeyType {
Pairwise,
Group,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AesCipherParameters<'a> {
pub key: MultiLengthKey<'a, AES_128_KEY_LENGTH, AES_256_KEY_LENGTH>,
pub key_type: KeyType,
pub mfp_enabled: bool,
pub spp_enabled: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CipherParameters<'a> {
Wep(MultiLengthKey<'a, WEP40_KEY_LENGTH, WEP104_KEY_LENGTH>),
Tkip(&'a [u8; TKIP_KEY_LENGTH], KeyType),
Ccmp(AesCipherParameters<'a>),
}
impl CipherParameters<'_> {
pub const fn aes_cipher_parameters(&self) -> Option<&AesCipherParameters<'_>> {
match self {
CipherParameters::Ccmp(parameters) => Some(parameters),
_ => None,
}
}
pub fn is_256_bit_key(&self) -> bool {
self.aes_cipher_parameters()
.is_none_or(|aes_cipher_parameters| {
aes_cipher_parameters.key.key_length() == AES_256_KEY_LENGTH
})
}
pub const fn is_wep_104(&self) -> bool {
if let CipherParameters::Wep(key) = self {
key.key_length() == WEP104_KEY_LENGTH
} else {
false
}
}
pub fn is_spp_enabled(&self) -> bool {
self.aes_cipher_parameters()
.is_none_or(|aes_cipher_parameters| aes_cipher_parameters.spp_enabled)
}
pub fn is_mfp_enabled(&self) -> bool {
self.aes_cipher_parameters()
.is_none_or(|aes_cipher_parameters| aes_cipher_parameters.mfp_enabled)
}
pub fn key_type(&self) -> Option<KeyType> {
self.aes_cipher_parameters()
.map(|aes_cipher_parameters| aes_cipher_parameters.key_type)
.or(if let CipherParameters::Tkip(_, key_type) = self {
Some(*key_type)
} else {
None
})
}
pub const fn key(&self) -> &[u8] {
match self {
Self::Wep(key) => key.key(),
Self::Tkip(key, _) => key.as_slice(),
_ => self.aes_cipher_parameters().unwrap().key.key(),
}
}
pub const fn is_aead(&self) -> bool {
matches!(self, Self::Wep(_))
}
pub fn is_pairwise(&self) -> bool {
if let Some(key_type) = self.key_type() {
key_type == KeyType::Pairwise
} else {
true
}
}
pub fn is_group(&self) -> bool {
if let Some(key_type) = self.key_type() {
key_type == KeyType::Group
} else {
true
}
}
pub const fn algorithm(&self) -> u8 {
match self {
Self::Wep(_) => 1,
Self::Tkip(_, _) => 2,
Self::Ccmp(_) => 3,
}
}
pub fn mic_length(&self) -> usize {
self.aes_cipher_parameters()
.map_or(0, |aes_cipher_parameters| {
aes_cipher_parameters.key.key_length()
})
}
}