#[cfg(not(feature = "5340-net"))]
use crate::{
pac::{AAR, CCM},
slice_in_ram,
};
#[cfg(feature = "5340-net")]
use crate::{
pac::{AAR_NS as AAR, CCM_NS as CCM},
slice_in_ram,
};
use core::sync::atomic::{compiler_fence, Ordering};
#[cfg(not(any(feature = "51", feature = "5340-net")))]
use crate::pac::ccm::mode::{DATARATE_A, LENGTH_A};
#[cfg(feature = "5340-net")]
use crate::pac::ccm_ns::mode::{DATARATE_A, LENGTH_A};
const MINIMUM_SCRATCH_AREA_SIZE: usize = 43;
const HEADER_SIZE: usize = 3;
const LENGTH_HEADER_INDEX: usize = 1;
const MIC_SIZE: usize = 4;
const MAXIMUM_LENGTH_5BITS: usize = 31;
const MAXIMUM_COUNTER: u64 = 0x7F_FFFF_FFFF;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum DataRate {
_1Mbit,
#[cfg(not(feature = "51"))]
_2Mbit,
#[cfg(feature = "5340-net")]
_125Kbps,
#[cfg(feature = "5340-net")]
_500Kbps,
}
#[cfg(not(feature = "51"))]
impl From<DataRate> for DATARATE_A {
fn from(data_rate: DataRate) -> Self {
match data_rate {
DataRate::_1Mbit => DATARATE_A::_1MBIT,
DataRate::_2Mbit => DATARATE_A::_2MBIT,
#[cfg(feature = "5340-net")]
DataRate::_125Kbps => DATARATE_A::_125KBPS,
#[cfg(feature = "5340-net")]
DataRate::_500Kbps => DATARATE_A::_500KBPS,
}
}
}
#[derive(Debug, PartialEq)]
pub enum CcmError {
BufferNotInRAM,
EasyDMAError,
WrongPacketLength,
InsufficientScratchArea,
InvalidMIC,
}
#[derive(Debug, PartialEq)]
#[repr(C)]
pub struct CcmData {
key: [u8; 16],
packet_counter: [u8; 8],
direction: u8,
initialization_vector: [u8; 8],
}
impl CcmData {
pub fn new(key: [u8; 16], initialization_vector: [u8; 8]) -> Self {
Self {
key,
packet_counter: [0; 8],
direction: 0,
initialization_vector,
}
}
#[inline(always)]
pub fn set_key(&mut self, key: [u8; 16]) {
self.key = key;
}
#[inline(always)]
pub fn set_iv(&mut self, initialization_vector: [u8; 8]) {
self.initialization_vector = initialization_vector;
}
#[inline(always)]
pub fn set_direction(&mut self, direction: bool) {
self.direction = if direction { 1 } else { 0 };
}
pub fn increment_counter(&mut self) {
let mut counter = u64::from_le_bytes(self.packet_counter);
if counter < MAXIMUM_COUNTER {
counter += 1;
} else {
counter = 0;
}
self.packet_counter = counter.to_le_bytes();
}
pub fn decrement_counter(&mut self) {
let mut counter = u64::from_le_bytes(self.packet_counter);
if counter > 0 {
counter -= 1;
self.packet_counter = counter.to_le_bytes();
}
}
}
pub struct Ccm {
regs: CCM,
_aar: AAR,
}
impl Ccm {
pub fn init(regs: CCM, arr: AAR, data_rate: DataRate) -> Self {
arr.enable.write(|w| w.enable().disabled());
regs.intenclr
.write(|w| w.endcrypt().clear().endksgen().clear().error().clear());
regs.tasks_stop.write(|w| unsafe { w.bits(1) });
#[cfg(not(feature = "51"))]
regs.mode.write(|w| w.datarate().variant(data_rate.into()));
#[cfg(feature = "51")]
let _ = data_rate;
regs.enable.write(|w| w.enable().enabled());
Self { regs, _aar: arr }
}
pub fn encrypt_packet(
&mut self,
ccm_data: &mut CcmData,
clear_packet: &[u8],
cipher_packet: &mut [u8],
scratch: &mut [u8],
) -> Result<(), CcmError> {
if !(slice_in_ram(clear_packet) && slice_in_ram(cipher_packet) && slice_in_ram(scratch)) {
return Err(CcmError::BufferNotInRAM);
}
if clear_packet.len() < HEADER_SIZE || cipher_packet.len() < HEADER_SIZE {
return Err(CcmError::WrongPacketLength);
}
let payload_len = clear_packet[LENGTH_HEADER_INDEX] as usize;
if payload_len == 0 {
(&mut cipher_packet[..HEADER_SIZE]).copy_from_slice(&clear_packet[..HEADER_SIZE]);
return Ok(());
}
if clear_packet.len() < payload_len + HEADER_SIZE
|| cipher_packet.len() < payload_len + HEADER_SIZE + MIC_SIZE
|| payload_len + MIC_SIZE > u8::MAX as usize
{
return Err(CcmError::WrongPacketLength);
}
if scratch.len() < (payload_len + 16).max(MINIMUM_SCRATCH_AREA_SIZE) {
return Err(CcmError::InsufficientScratchArea);
}
#[cfg(feature = "51")]
{
if payload_len > MAXIMUM_LENGTH_5BITS - MIC_SIZE {
return Err(CcmError::WrongPacketLength);
}
}
#[cfg(not(feature = "51"))]
let length_variant = if payload_len <= MAXIMUM_LENGTH_5BITS - MIC_SIZE {
LENGTH_A::DEFAULT
} else {
#[cfg(any(
feature = "52840",
feature = "52833",
feature = "52811",
feature = "52810",
feature = "52805",
feature = "5340-net"
))]
self.regs
.maxpacketsize
.write(|w| unsafe { w.maxpacketsize().bits(payload_len as u8) });
LENGTH_A::EXTENDED
};
#[cfg(feature = "51")]
self.regs.mode.write(|w| w.mode().encryption());
#[cfg(not(feature = "51"))]
self.regs
.mode
.modify(|_, w| w.mode().encryption().length().variant(length_variant));
unsafe {
self.regs
.cnfptr
.write(|w| w.bits(ccm_data as *mut _ as u32));
self.regs
.inptr
.write(|w| w.bits(clear_packet.as_ptr() as u32));
self.regs
.outptr
.write(|w| w.bits(cipher_packet.as_mut_ptr() as u32));
self.regs
.scratchptr
.write(|w| w.bits(scratch.as_mut_ptr() as u32));
}
self.regs.events_endcrypt.reset();
self.regs.events_error.reset();
self.regs.events_endksgen.reset();
compiler_fence(Ordering::Release);
self.regs.tasks_ksgen.write(|w| unsafe { w.bits(1) });
while self.regs.events_endksgen.read().bits() == 0 {}
self.regs.tasks_crypt.write(|w| unsafe { w.bits(1) });
while self.regs.events_endcrypt.read().bits() == 0
&& self.regs.events_error.read().bits() == 0
{}
compiler_fence(Ordering::Acquire);
if self.regs.events_error.read().bits() == 1 {
return Err(CcmError::EasyDMAError);
}
ccm_data.increment_counter();
Ok(())
}
pub fn decrypt_packet(
&mut self,
ccm_data: &mut CcmData,
clear_packet: &mut [u8],
cipher_packet: &[u8],
scratch: &mut [u8],
) -> Result<(), CcmError> {
if !(slice_in_ram(clear_packet) && slice_in_ram(cipher_packet) && slice_in_ram(scratch)) {
return Err(CcmError::BufferNotInRAM);
}
if clear_packet.len() < HEADER_SIZE || cipher_packet.len() < HEADER_SIZE {
return Err(CcmError::WrongPacketLength);
}
let payload_len = cipher_packet[LENGTH_HEADER_INDEX] as usize;
if payload_len == 0 {
(&mut clear_packet[..HEADER_SIZE]).copy_from_slice(&cipher_packet[..HEADER_SIZE]);
return Ok(());
}
if payload_len < 5 {
return Err(CcmError::InvalidMIC);
}
if cipher_packet.len() < payload_len + HEADER_SIZE
|| clear_packet.len() < payload_len + HEADER_SIZE - MIC_SIZE
{
return Err(CcmError::WrongPacketLength);
}
if scratch.len() < (payload_len + 16).max(MINIMUM_SCRATCH_AREA_SIZE) {
return Err(CcmError::InsufficientScratchArea);
}
#[cfg(feature = "51")]
{
if payload_len > MAXIMUM_LENGTH_5BITS {
return Err(CcmError::WrongPacketLength);
}
}
#[cfg(not(feature = "51"))]
let length_variant = if payload_len <= MAXIMUM_LENGTH_5BITS {
LENGTH_A::DEFAULT
} else {
#[cfg(any(
feature = "52840",
feature = "52833",
feature = "52811",
feature = "52810",
feature = "52805",
feature = "5340-net"
))]
self.regs
.maxpacketsize
.write(|w| unsafe { w.maxpacketsize().bits(payload_len as u8) });
LENGTH_A::EXTENDED
};
#[cfg(feature = "51")]
self.regs.mode.write(|w| w.mode().decryption());
#[cfg(not(feature = "51"))]
self.regs
.mode
.modify(|_, w| w.mode().decryption().length().variant(length_variant));
unsafe {
self.regs
.cnfptr
.write(|w| w.bits(ccm_data as *mut _ as u32));
self.regs
.inptr
.write(|w| w.bits(cipher_packet.as_ptr() as u32));
self.regs
.outptr
.write(|w| w.bits(clear_packet.as_mut_ptr() as u32));
self.regs
.scratchptr
.write(|w| w.bits(scratch.as_mut_ptr() as u32));
}
self.regs.events_endcrypt.reset();
self.regs.events_error.reset();
self.regs.events_endksgen.reset();
compiler_fence(Ordering::Release);
self.regs.tasks_ksgen.write(|w| unsafe { w.bits(1) });
while self.regs.events_endksgen.read().bits() == 0 {}
self.regs.tasks_crypt.write(|w| unsafe { w.bits(1) });
while self.regs.events_endcrypt.read().bits() == 0
&& self.regs.events_error.read().bits() == 0
{}
compiler_fence(Ordering::Acquire);
if self.regs.events_error.read().bits() == 1 {
return Err(CcmError::EasyDMAError);
}
if self.regs.micstatus.read().micstatus().is_check_failed() {
return Err(CcmError::InvalidMIC);
}
ccm_data.increment_counter();
Ok(())
}
}