Refactored cryp din/dout into functions.

This commit is contained in:
Caleb Garrett 2024-03-05 11:25:56 -05:00
parent ac06ca2fa0
commit 6e9e8eeb5f
2 changed files with 144 additions and 146 deletions

View file

@ -4,12 +4,35 @@ use core::cmp::min;
use core::marker::PhantomData; use core::marker::PhantomData;
use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
use crate::{interrupt, pac, peripherals, Peripheral}; use crate::interrupt::typelevel::Interrupt;
use crate::{dma::NoDma, interrupt, pac, peripherals, Peripheral};
const DES_BLOCK_SIZE: usize = 8; // 64 bits const DES_BLOCK_SIZE: usize = 8; // 64 bits
const AES_BLOCK_SIZE: usize = 16; // 128 bits const AES_BLOCK_SIZE: usize = 16; // 128 bits
static CRYP_WAKER: AtomicWaker = AtomicWaker::new();
/// CRYP interrupt handler.
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let bits = T::regs().misr().read();
if bits.inmis() {
T::regs().imscr().modify(|w| w.set_inim(false));
CRYP_WAKER.wake();
}
if bits.outmis() {
T::regs().imscr().modify(|w| w.set_outim(false));
CRYP_WAKER.wake();
}
}
}
/// This trait encapsulates all cipher-specific behavior/ /// This trait encapsulates all cipher-specific behavior/
pub trait Cipher<'c> { pub trait Cipher<'c> {
/// Processing block size. Determined by the processor and the algorithm. /// Processing block size. Determined by the processor and the algorithm.
@ -32,7 +55,7 @@ pub trait Cipher<'c> {
fn prepare_key(&self, _p: &pac::cryp::Cryp) {} fn prepare_key(&self, _p: &pac::cryp::Cryp) {}
/// Performs any cipher-specific initialization. /// Performs any cipher-specific initialization.
fn init_phase(&self, _p: &pac::cryp::Cryp) {} fn init_phase<T: Instance, D>(&self, _p: &pac::cryp::Cryp, _cryp: &Cryp<T, D>) {}
/// Called prior to processing the last data block for cipher-specific operations. /// Called prior to processing the last data block for cipher-specific operations.
fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] {
@ -40,9 +63,10 @@ pub trait Cipher<'c> {
} }
/// Called after processing the last data block for cipher-specific operations. /// Called after processing the last data block for cipher-specific operations.
fn post_final_block( fn post_final_block<T: Instance, D>(
&self, &self,
_p: &pac::cryp::Cryp, _p: &pac::cryp::Cryp,
_cryp: &Cryp<T, D>,
_dir: Direction, _dir: Direction,
_int_data: &mut [u8; AES_BLOCK_SIZE], _int_data: &mut [u8; AES_BLOCK_SIZE],
_temp1: [u32; 4], _temp1: [u32; 4],
@ -425,7 +449,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
p.cr().modify(|w| w.set_algomode3(true)); p.cr().modify(|w| w.set_algomode3(true));
} }
fn init_phase(&self, p: &pac::cryp::Cryp) { fn init_phase<T: Instance, D>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, D>) {
p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_gcm_ccmph(0));
p.cr().modify(|w| w.set_crypen(true)); p.cr().modify(|w| w.set_crypen(true));
while p.cr().read().crypen() {} while p.cr().read().crypen() {}
@ -453,9 +477,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
} }
#[cfg(cryp_v2)] #[cfg(cryp_v2)]
fn post_final_block( fn post_final_block<T: Instance, D>(
&self, &self,
p: &pac::cryp::Cryp, p: &pac::cryp::Cryp,
cryp: &Cryp<T, D>,
dir: Direction, dir: Direction,
int_data: &mut [u8; AES_BLOCK_SIZE], int_data: &mut [u8; AES_BLOCK_SIZE],
_temp1: [u32; 4], _temp1: [u32; 4],
@ -471,17 +496,9 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
} }
p.cr().modify(|w| w.set_crypen(true)); p.cr().modify(|w| w.set_crypen(true));
p.cr().modify(|w| w.set_gcm_ccmph(3)); p.cr().modify(|w| w.set_gcm_ccmph(3));
let mut index = 0;
let end_index = Self::BLOCK_SIZE; cryp.write_bytes_blocking(Self::BLOCK_SIZE, int_data);
while index < end_index { cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data);
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&int_data[index..index + 4]);
p.din().write_value(u32::from_ne_bytes(in_word));
index += 4;
}
for _ in 0..4 {
p.dout().read();
}
} }
} }
} }
@ -532,7 +549,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
p.cr().modify(|w| w.set_algomode3(true)); p.cr().modify(|w| w.set_algomode3(true));
} }
fn init_phase(&self, p: &pac::cryp::Cryp) { fn init_phase<T: Instance, D>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, D>) {
p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_gcm_ccmph(0));
p.cr().modify(|w| w.set_crypen(true)); p.cr().modify(|w| w.set_crypen(true));
while p.cr().read().crypen() {} while p.cr().read().crypen() {}
@ -560,9 +577,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
} }
#[cfg(cryp_v2)] #[cfg(cryp_v2)]
fn post_final_block( fn post_final_block<T: Instance, D>(
&self, &self,
p: &pac::cryp::Cryp, p: &pac::cryp::Cryp,
cryp: &Cryp<T, D>,
dir: Direction, dir: Direction,
int_data: &mut [u8; AES_BLOCK_SIZE], int_data: &mut [u8; AES_BLOCK_SIZE],
_temp1: [u32; 4], _temp1: [u32; 4],
@ -578,17 +596,9 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
} }
p.cr().modify(|w| w.set_crypen(true)); p.cr().modify(|w| w.set_crypen(true));
p.cr().modify(|w| w.set_gcm_ccmph(3)); p.cr().modify(|w| w.set_gcm_ccmph(3));
let mut index = 0;
let end_index = Self::BLOCK_SIZE; cryp.write_bytes_blocking(Self::BLOCK_SIZE, int_data);
while index < end_index { cryp.read_bytes_blocking(Self::BLOCK_SIZE, int_data);
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&int_data[index..index + 4]);
p.din().write_value(u32::from_ne_bytes(in_word));
index += 4;
}
for _ in 0..4 {
p.dout().read();
}
} }
} }
} }
@ -697,18 +707,11 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
p.cr().modify(|w| w.set_algomode3(true)); p.cr().modify(|w| w.set_algomode3(true));
} }
fn init_phase(&self, p: &pac::cryp::Cryp) { fn init_phase<T: Instance, D>(&self, p: &pac::cryp::Cryp, cryp: &Cryp<T, D>) {
p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_gcm_ccmph(0));
let mut index = 0; cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0);
let end_index = index + Self::BLOCK_SIZE;
// Write block in
while index < end_index {
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&self.block0[index..index + 4]);
p.din().write_value(u32::from_ne_bytes(in_word));
index += 4;
}
p.cr().modify(|w| w.set_crypen(true)); p.cr().modify(|w| w.set_crypen(true));
while p.cr().read().crypen() {} while p.cr().read().crypen() {}
} }
@ -744,9 +747,10 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
} }
#[cfg(cryp_v2)] #[cfg(cryp_v2)]
fn post_final_block( fn post_final_block<T: Instance, D>(
&self, &self,
p: &pac::cryp::Cryp, p: &pac::cryp::Cryp,
cryp: &Cryp<T, D>,
dir: Direction, dir: Direction,
int_data: &mut [u8; AES_BLOCK_SIZE], int_data: &mut [u8; AES_BLOCK_SIZE],
temp1: [u32; 4], temp1: [u32; 4],
@ -774,8 +778,8 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
let int_word = u32::from_le_bytes(int_bytes); let int_word = u32::from_le_bytes(int_bytes);
in_data[i] = int_word; in_data[i] = int_word;
in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i];
p.din().write_value(in_data[i]);
} }
cryp.write_words_blocking(Self::BLOCK_SIZE, &in_data);
} }
} }
} }
@ -845,16 +849,31 @@ pub enum Direction {
} }
/// Crypto Accelerator Driver /// Crypto Accelerator Driver
pub struct Cryp<'d, T: Instance> { pub struct Cryp<'d, T: Instance, D = NoDma> {
_peripheral: PeripheralRef<'d, T>, _peripheral: PeripheralRef<'d, T>,
indma: PeripheralRef<'d, D>,
outdma: PeripheralRef<'d, D>,
} }
impl<'d, T: Instance> Cryp<'d, T> { impl<'d, T: Instance, D> Cryp<'d, T, D> {
/// Create a new CRYP driver. /// Create a new CRYP driver.
pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self { pub fn new(
peri: impl Peripheral<P = T> + 'd,
indma: impl Peripheral<P = D> + 'd,
outdma: impl Peripheral<P = D> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
) -> Self {
T::enable_and_reset(); T::enable_and_reset();
into_ref!(peri); into_ref!(peri, indma, outdma);
let instance = Self { _peripheral: peri }; let instance = Self {
_peripheral: peri,
indma: indma,
outdma: outdma,
};
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
instance instance
} }
@ -929,7 +948,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
// Flush in/out FIFOs // Flush in/out FIFOs
T::regs().cr().modify(|w| w.fflush()); T::regs().cr().modify(|w| w.fflush());
ctx.cipher.init_phase(&T::regs()); ctx.cipher.init_phase(&T::regs(), self);
self.store_context(&mut ctx); self.store_context(&mut ctx);
@ -985,15 +1004,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
if ctx.aad_buffer_len < C::BLOCK_SIZE { if ctx.aad_buffer_len < C::BLOCK_SIZE {
// The buffer isn't full and this is the last buffer, so process it as is (already padded). // The buffer isn't full and this is the last buffer, so process it as is (already padded).
if last_aad_block { if last_aad_block {
let mut index = 0; self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer);
let end_index = C::BLOCK_SIZE;
// Write block in
while index < end_index {
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
T::regs().din().write_value(u32::from_ne_bytes(in_word));
index += 4;
}
// Block until input FIFO is empty. // Block until input FIFO is empty.
while !T::regs().sr().read().ifem() {} while !T::regs().sr().read().ifem() {}
@ -1008,15 +1019,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
} }
} else { } else {
// Load the full block from the buffer. // Load the full block from the buffer.
let mut index = 0; self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer);
let end_index = C::BLOCK_SIZE;
// Write block in
while index < end_index {
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
T::regs().din().write_value(u32::from_ne_bytes(in_word));
index += 4;
}
// Block until input FIFO is empty. // Block until input FIFO is empty.
while !T::regs().sr().read().ifem() {} while !T::regs().sr().read().ifem() {}
} }
@ -1032,33 +1035,13 @@ impl<'d, T: Instance> Cryp<'d, T> {
// Load full data blocks into core. // Load full data blocks into core.
let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE;
for block in 0..num_full_blocks { let start_index = len_to_copy;
let mut index = len_to_copy + (block * C::BLOCK_SIZE); let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks);
let end_index = index + C::BLOCK_SIZE; self.write_bytes_blocking(C::BLOCK_SIZE, &aad[start_index..end_index]);
// Write block in
while index < end_index {
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&aad[index..index + 4]);
T::regs().din().write_value(u32::from_ne_bytes(in_word));
index += 4;
}
// Block until input FIFO is empty.
while !T::regs().sr().read().ifem() {}
}
if last_aad_block { if last_aad_block {
if leftovers > 0 { if leftovers > 0 {
let mut index = 0; self.write_bytes_blocking(C::BLOCK_SIZE, &ctx.aad_buffer);
let end_index = C::BLOCK_SIZE;
// Write block in
while index < end_index {
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
T::regs().din().write_value(u32::from_ne_bytes(in_word));
index += 4;
}
// Block until input FIFO is empty.
while !T::regs().sr().read().ifem() {}
} }
// Switch to payload phase. // Switch to payload phase.
ctx.aad_complete = true; ctx.aad_complete = true;
@ -1125,25 +1108,11 @@ impl<'d, T: Instance> Cryp<'d, T> {
// Load data into core, block by block. // Load data into core, block by block.
let num_full_blocks = input.len() / C::BLOCK_SIZE; let num_full_blocks = input.len() / C::BLOCK_SIZE;
for block in 0..num_full_blocks { for block in 0..num_full_blocks {
let mut index = block * C::BLOCK_SIZE; let index = block * C::BLOCK_SIZE;
let end_index = index + C::BLOCK_SIZE;
// Write block in // Write block in
while index < end_index { self.write_bytes_blocking(C::BLOCK_SIZE, &input[index..index + 4]);
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&input[index..index + 4]);
T::regs().din().write_value(u32::from_ne_bytes(in_word));
index += 4;
}
let mut index = block * C::BLOCK_SIZE;
let end_index = index + C::BLOCK_SIZE;
// Block until there is output to read.
while !T::regs().sr().read().ofne() {}
// Read block out // Read block out
while index < end_index { self.read_bytes_blocking(C::BLOCK_SIZE, &mut output[index..index + 4]);
let out_word: u32 = T::regs().dout().read();
output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
index += 4;
}
} }
// Handle the final block, which is incomplete. // Handle the final block, which is incomplete.
@ -1154,25 +1123,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
let mut index = 0; self.write_bytes_blocking(C::BLOCK_SIZE, &last_block);
let end_index = C::BLOCK_SIZE; self.read_bytes_blocking(C::BLOCK_SIZE, &mut intermediate_data);
// Write block in
while index < end_index {
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&last_block[index..index + 4]);
T::regs().din().write_value(u32::from_ne_bytes(in_word));
index += 4;
}
let mut index = 0;
let end_index = C::BLOCK_SIZE;
// Block until there is output to read.
while !T::regs().sr().read().ofne() {}
// Read block out
while index < end_index {
let out_word: u32 = T::regs().dout().read();
intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
index += 4;
}
// Handle the last block depending on mode. // Handle the last block depending on mode.
let output_len = output.len(); let output_len = output.len();
@ -1182,7 +1134,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
let mut mask: [u8; 16] = [0; 16]; let mut mask: [u8; 16] = [0; 16];
mask[..last_block_remainder].fill(0xFF); mask[..last_block_remainder].fill(0xFF);
ctx.cipher ctx.cipher
.post_final_block(&T::regs(), ctx.dir, &mut intermediate_data, temp1, mask); .post_final_block(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask);
} }
ctx.payload_len += input.len() as u64; ctx.payload_len += input.len() as u64;
@ -1213,28 +1165,21 @@ impl<'d, T: Instance> Cryp<'d, T> {
let payloadlen2: u32 = (ctx.payload_len * 8) as u32; let payloadlen2: u32 = (ctx.payload_len * 8) as u32;
#[cfg(cryp_v2)] #[cfg(cryp_v2)]
{ let footer: [u32; 4] = [
T::regs().din().write_value(headerlen1.swap_bytes()); headerlen1.swap_bytes(),
T::regs().din().write_value(headerlen2.swap_bytes()); headerlen2.swap_bytes(),
T::regs().din().write_value(payloadlen1.swap_bytes()); payloadlen1.swap_bytes(),
T::regs().din().write_value(payloadlen2.swap_bytes()); payloadlen2.swap_bytes(),
} ];
#[cfg(cryp_v3)] #[cfg(cryp_v3)]
{ let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2];
T::regs().din().write_value(headerlen1);
T::regs().din().write_value(headerlen2); self.write_words_blocking(C::BLOCK_SIZE, &footer);
T::regs().din().write_value(payloadlen1);
T::regs().din().write_value(payloadlen2);
}
while !T::regs().sr().read().ofne() {} while !T::regs().sr().read().ofne() {}
let mut full_tag: [u8; 16] = [0; 16]; let mut full_tag: [u8; 16] = [0; 16];
full_tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice()); self.read_bytes_blocking(C::BLOCK_SIZE, &mut full_tag);
full_tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
full_tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
full_tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE];
tag.copy_from_slice(&full_tag[0..TAG_SIZE]); tag.copy_from_slice(&full_tag[0..TAG_SIZE]);
@ -1325,6 +1270,51 @@ impl<'d, T: Instance> Cryp<'d, T> {
// Enable crypto processor. // Enable crypto processor.
T::regs().cr().modify(|w| w.set_crypen(true)); T::regs().cr().modify(|w| w.set_crypen(true));
} }
fn write_bytes_blocking(&self, block_size: usize, blocks: &[u8]) {
// Ensure input is a multiple of block size.
assert_eq!(blocks.len() % block_size, 0);
let mut index = 0;
let end_index = blocks.len();
while index < end_index {
let mut in_word: [u8; 4] = [0; 4];
in_word.copy_from_slice(&blocks[index..index + 4]);
T::regs().din().write_value(u32::from_ne_bytes(in_word));
index += 4;
if index % block_size == 0 {
// Block until input FIFO is empty.
while !T::regs().sr().read().ifem() {}
}
}
}
fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) {
assert_eq!((blocks.len() * 4) % block_size, 0);
let mut byte_counter: usize = 0;
for word in blocks {
T::regs().din().write_value(*word);
byte_counter += 4;
if byte_counter % block_size == 0 {
// Block until input FIFO is empty.
while !T::regs().sr().read().ifem() {}
}
}
}
fn read_bytes_blocking(&self, block_size: usize, blocks: &mut [u8]) {
// Block until there is output to read.
while !T::regs().sr().read().ofne() {}
// Ensure input is a multiple of block size.
assert_eq!(blocks.len() % block_size, 0);
// Read block out
let mut index = 0;
let end_index = blocks.len();
while index < end_index {
let out_word: u32 = T::regs().dout().read();
blocks[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
index += 4;
}
}
} }
pub(crate) mod sealed { pub(crate) mod sealed {

View file

@ -6,11 +6,19 @@ use aes_gcm::aead::{AeadInPlace, KeyInit};
use aes_gcm::Aes128Gcm; use aes_gcm::Aes128Gcm;
use defmt::info; use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::cryp::*; use embassy_stm32::dma::NoDma;
use embassy_stm32::Config; use embassy_stm32::{
bind_interrupts,
cryp::{self, *},
};
use embassy_stm32::{peripherals, Config};
use embassy_time::Instant; use embassy_time::Instant;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
CRYP => cryp::InterruptHandler<peripherals::CRYP>;
});
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! { async fn main(_spawner: Spawner) -> ! {
let config = Config::default(); let config = Config::default();
@ -19,7 +27,7 @@ async fn main(_spawner: Spawner) -> ! {
let payload: &[u8] = b"hello world"; let payload: &[u8] = b"hello world";
let aad: &[u8] = b"additional data"; let aad: &[u8] = b"additional data";
let hw_cryp = Cryp::new(p.CRYP); let hw_cryp = Cryp::new(p.CRYP, NoDma, NoDma, Irqs);
let key: [u8; 16] = [0; 16]; let key: [u8; 16] = [0; 16];
let mut ciphertext: [u8; 11] = [0; 11]; let mut ciphertext: [u8; 11] = [0; 11];
let mut plaintext: [u8; 11] = [0; 11]; let mut plaintext: [u8; 11] = [0; 11];