use core::convert::TryInto;
use core::marker::PhantomData;
use cc2538_pac::aes;
use super::Crypto;
use super::CryptoMode;
use super::NotSpecified;
pub mod keys;
use keys::AesKeys;
pub mod ccm;
pub mod ctr;
use ccm::AesCcm;
use ctr::AesCtr;
pub struct AesEngine<Type> {
_type: PhantomData<Type>,
}
pub struct AesCbc {}
pub struct AesCbcMac {}
pub struct AesEcb {}
pub struct AesGcm {}
impl Crypto<'_> {
#[inline]
fn workaround(&mut self) {
let aes = Self::aes();
aes.ctrl_int_cfg().write(|w| w.level().set_bit());
aes.ctrl_int_en()
.write(|w| w.dma_in_done().set_bit().result_av().set_bit());
}
#[inline]
fn set_mode(&mut self, mode: CryptoMode) {
let aes = Self::aes();
match mode {
CryptoMode::StoreKeys => {
aes.ctrl_alg_sel().write(|w| w.keystore().set_bit());
}
CryptoMode::HashAndTag => {
aes.ctrl_alg_sel()
.write(|w| w.tag().set_bit().hash().set_bit());
}
CryptoMode::Tag => {
aes.ctrl_alg_sel().write(|w| w.tag().set_bit());
}
CryptoMode::Hash => {
aes.ctrl_alg_sel().write(|w| w.hash().set_bit());
}
CryptoMode::Aes => {
aes.ctrl_alg_sel().write(|w| w.aes().set_bit());
}
}
}
#[inline]
fn enable_dma_channel0(&mut self) {
Self::aes().dmac_ch0_ctrl().write(|w| w.en().set_bit());
}
#[inline]
fn set_dma_channel0_ext_addr(&mut self, addr: u32) {
Self::aes()
.dmac_ch0_extaddr()
.write(|w| unsafe { w.addr().bits(addr) });
}
#[inline]
fn set_dma_channel0_dmalength(&mut self, length: u16) {
Self::aes()
.dmac_ch0_dmalength()
.write(|w| unsafe { w.dmalen().bits(length) });
}
#[inline]
fn enable_dma_channel1(&mut self) {
Self::aes().dmac_ch1_ctrl().write(|w| w.en().set_bit());
}
#[inline]
fn set_dma_channel1_ext_addr(&mut self, addr: u32) {
Self::aes()
.dmac_ch1_extaddr()
.write(|w| unsafe { w.addr().bits(addr) });
}
#[inline]
fn set_dma_channel1_dmalength(&mut self, length: u16) {
Self::aes()
.dmac_ch1_dmalength()
.write(|w| unsafe { w.dmalen().bits(length) });
}
#[inline]
fn enable_dma_path(&mut self) {
Self::aes().ctrl_alg_sel().modify(|_, w| w.aes().set_bit());
}
#[inline]
fn clear_events(&mut self) {
Self::aes().ctrl_int_clr().write(|w| w.result_av().set_bit());
}
#[inline]
fn is_completed(&self) -> bool {
Self::aes().ctrl_int_stat().read().result_av().bit_is_set()
}
#[inline]
fn set_key(&mut self, key_area: u32) {
Self::aes()
.key_store_read_area()
.modify(|_, w| unsafe { w.bits(key_area) });
}
#[inline]
fn key_is_set(&mut self) -> bool {
Self::aes().key_store_read_area().read().busy().bit_is_clear()
}
#[inline]
fn key_load_error(&mut self) -> bool {
Self::aes()
.ctrl_int_stat()
.read()
.key_st_rd_err()
.bit_is_set()
}
#[inline]
fn save_context(&mut self) {
Self::aes()
.aes_ctrl()
.modify(|_, w| w.save_context().set_bit());
}
#[inline]
fn write_dma0(&mut self, data: &[u8]) {
let aes = Self::aes();
aes.dmac_ch0_ctrl().modify(|_, w| w.en().set_bit());
aes.dmac_ch0_extaddr()
.modify(|_, w| unsafe { w.addr().bits(data.as_ptr() as u32) });
aes.dmac_ch0_dmalength()
.modify(|_, w| unsafe { w.dmalen().bits(data.len() as u16) });
while !aes.ctrl_int_stat().read().dma_in_done().bit_is_set() {}
}
#[inline]
fn write_dma1(&mut self, data: &[u8]) {
let aes = Self::aes();
aes.dmac_ch1_ctrl().modify(|_, w| w.en().set_bit());
aes.dmac_ch1_extaddr()
.modify(|_, w| unsafe { w.addr().bits(data.as_ptr() as u32) });
aes.dmac_ch1_dmalength()
.modify(|_, w| unsafe { w.dmalen().bits(data.len() as u16) });
while !aes.ctrl_int_stat().read().dma_in_done().bit_is_set() {}
}
fn write_iv(&mut self, iv: &[u8]) {
assert!(iv.len() == 16);
let mut iv_u32: [u32; 4] = [0; 4];
for (i, c) in iv.chunks(4).enumerate() {
iv_u32[i] = u32::from_le_bytes(c.try_into().unwrap());
}
let aes = Self::aes();
unsafe {
aes.aes_iv_0().write(|w| w.bits(iv_u32[0]));
aes.aes_iv_1().write(|w| w.bits(iv_u32[1]));
aes.aes_iv_2().write(|w| w.bits(iv_u32[2]));
aes.aes_iv_3().write(|w| w.bits(iv_u32[3]));
}
}
fn read_tag(&mut self, tag: &mut [u8]) {
assert!(tag.len() == 16);
let mut tag_u32 = [0u32; 4];
let aes = Self::aes();
tag_u32[0] = aes.aes_tag_out_0().read().bits();
tag_u32[1] = aes.aes_tag_out_1().read().bits();
tag_u32[2] = aes.aes_tag_out_2().read().bits();
tag_u32[3] = aes.aes_tag_out_3().read().bits();
for (i, c) in tag_u32.iter().enumerate() {
let b = c.to_le_bytes();
for j in 0..4 {
tag[i * 4 + j] = b[j];
}
}
}
pub fn load_key(&mut self, aes_keys: &AesKeys) {
if Self::is_aes_in_use() {
return; }
let aes = Self::aes();
self.workaround();
self.set_mode(CryptoMode::StoreKeys);
self.clear_events();
if aes.key_store_size().read().key_size().bits() != aes_keys.sizes as u8 {
unsafe {
aes.key_store_size()
.modify(|_, w| w.key_size().bits(aes_keys.sizes as u8));
}
}
let areas = ((0x1 << aes_keys.count) - 1) << aes_keys.start_area;
unsafe { aes.key_store_written_area().write(|w| w.bits(areas)) };
unsafe { aes.key_store_write_area().write(|w| w.bits(areas)) };
self.enable_dma_channel0();
self.set_dma_channel0_ext_addr(aes_keys.keys.as_ptr() as u32);
self.set_dma_channel0_dmalength((aes_keys.count << 4) as u16);
while !self.is_completed() {}
if aes.ctrl_int_stat().read().dma_bus_err().bit_is_set() {
aes.ctrl_int_clr().write(|w| w.dma_bus_err().set_bit());
return; }
if aes.ctrl_int_stat().read().key_st_wr_err().bit_is_set() {
aes.ctrl_int_clr().write(|w| w.key_st_wr_err().set_bit());
return;
}
aes.ctrl_int_clr()
.write(|w| w.dma_in_done().set_bit().result_av().set_bit());
aes.ctrl_alg_sel().write(|w| unsafe { w.bits(0) });
if (aes.key_store_written_area().read().bits() & areas) != areas {
return;
}
}
fn auth_crypt(
&mut self,
ctrl: impl FnOnce(&aes::RegisterBlock),
key_index: u32,
iv: Option<&[u8]>,
adata: Option<&[u8]>,
data_in: &[u8],
data_out: &[u8],
) {
if Self::is_aes_in_use() {
return;
}
let aes = Self::aes();
aes.ctrl_alg_sel().modify(|_, w| w.aes().set_bit());
aes.ctrl_int_clr()
.write(|w| w.dma_in_done().set_bit().result_av().set_bit());
self.set_key(key_index);
while !self.key_is_set() {}
if self.key_load_error() {
return;
}
if let Some(iv) = iv {
self.write_iv(iv);
}
ctrl(aes);
aes.aes_c_length_0()
.write(|w| unsafe { w.bits(data_in.len() as u32) });
aes.aes_c_length_1().write(|w| unsafe { w.bits(0) });
if let Some(adata) = adata {
aes.aes_auth_length()
.write(|w| unsafe { w.auth_length().bits(adata.len() as u32) });
if !adata.is_empty() {
self.write_dma0(adata);
if aes.ctrl_int_stat().read().dma_bus_err().bit_is_set() {
return;
}
aes.ctrl_int_clr().write(|w| w.dma_in_done().set_bit());
}
}
if !data_in.is_empty() {
self.write_dma0(data_in);
if !data_out.is_empty() {
self.write_dma1(data_out);
}
}
while !(aes.ctrl_int_stat().read().dma_bus_err().bit_is_set()
|| aes.ctrl_int_stat().read().key_st_rd_err().bit_is_set()
|| aes.ctrl_int_stat().read().key_st_wr_err().bit_is_set()
|| aes.ctrl_int_stat().read().result_av().bit_is_set())
{}
}
}