blob: 7ab4bf95b251372cd25c471510996cc2971668f7 [file] [log] [blame]
//! Support for the AES hardware block on OpenTitan
//!
//! https://docs.opentitan.org/hw/ip/aes/doc/
use kernel::common::cells::{OptionalCell, TakeCell};
use kernel::common::registers::{
register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
};
use kernel::common::StaticRef;
use kernel::debug;
use kernel::hil;
use kernel::hil::symmetric_encryption;
use kernel::hil::symmetric_encryption::{AES128_BLOCK_SIZE, AES128_KEY_SIZE};
use kernel::ReturnCode;
const MAX_LENGTH: usize = 128;
register_structs! {
pub AesRegisters {
(0x00 => key0: WriteOnly<u32>),
(0x04 => key1: WriteOnly<u32>),
(0x08 => key2: WriteOnly<u32>),
(0x0c => key3: WriteOnly<u32>),
(0x10 => key4: WriteOnly<u32>),
(0x14 => key5: WriteOnly<u32>),
(0x18 => key6: WriteOnly<u32>),
(0x1c => key7: WriteOnly<u32>),
(0x20 => data_in0: WriteOnly<u32>),
(0x24 => data_in1: WriteOnly<u32>),
(0x28 => data_in2: WriteOnly<u32>),
(0x2c => data_in3: WriteOnly<u32>),
(0x30 => data_out0: ReadOnly<u32>),
(0x34 => data_out1: ReadOnly<u32>),
(0x38 => data_out2: ReadOnly<u32>),
(0x3c => data_out3: ReadOnly<u32>),
(0x40 => ctrl: ReadWrite<u32, CTRL::Register>),
(0x44 => trigger: WriteOnly<u32, TRIGGER::Register>),
(0x48 => status: ReadOnly<u32, STATUS::Register>),
(0x4c => @END),
}
}
register_bitfields![u32,
CTRL [
OPERATION OFFSET(0) NUMBITS(1) [
Encrypting = 0,
Decrypting = 1
],
KEY_LEN OFFSET(1) NUMBITS(3) [
Key128 = 1,
Key192 = 2,
Key256 = 4
],
MANUAL_OPERATION OFFSET(4) NUMBITS(1) []
],
TRIGGER [
START OFFSET(0) NUMBITS(1) [],
KEY_CLEAR OFFSET(1) NUMBITS(1) [],
DATA_IN_CLEAR OFFSET(2) NUMBITS(1) [],
DATA_OUT_CLEAR OFFSET(3) NUMBITS(1) []
],
STATUS [
IDLE 0,
STALL 1,
OUTPUT_VALID 2,
INPUT_READY 3
]
];
// https://docs.opentitan.org/hw/top_earlgrey/doc/
const AES_BASE: StaticRef<AesRegisters> =
unsafe { StaticRef::new(0x41100000 as *const AesRegisters) };
pub struct Aes<'a> {
registers: StaticRef<AesRegisters>,
client: OptionalCell<&'a dyn hil::symmetric_encryption::Client<'a>>,
source: TakeCell<'a, [u8]>,
dest: TakeCell<'a, [u8]>,
}
impl<'a> Aes<'a> {
const fn new() -> Aes<'a> {
Aes {
registers: AES_BASE,
client: OptionalCell::empty(),
source: TakeCell::empty(),
dest: TakeCell::empty(),
}
}
fn clear(&self) {
let regs = self.registers;
regs.trigger.write(
TRIGGER::KEY_CLEAR::SET + TRIGGER::DATA_IN_CLEAR::SET + TRIGGER::DATA_OUT_CLEAR::SET,
);
}
fn configure(&self, encrypting: bool) {
let regs = self.registers;
let e = if encrypting {
CTRL::OPERATION::Encrypting
} else {
CTRL::OPERATION::Decrypting
};
// Set this in manual mode for the moment since automatic block mode
// does not appear to be working
regs.ctrl
.write(e + CTRL::KEY_LEN::Key128 + CTRL::MANUAL_OPERATION::SET);
}
fn idle(&self) -> bool {
let regs = self.registers;
regs.status.is_set(STATUS::IDLE)
}
fn input_ready(&self) -> bool {
let regs = self.registers;
regs.status.is_set(STATUS::INPUT_READY)
}
fn output_valid(&self) -> bool {
let regs = self.registers;
regs.status.is_set(STATUS::OUTPUT_VALID)
}
fn trigger(&self) {
let regs = self.registers;
regs.trigger.write(TRIGGER::START::SET);
}
fn read_block(&self, blocknum: usize) {
let regs = self.registers;
let blocknum = blocknum * AES128_BLOCK_SIZE;
loop {
if self.output_valid() {
break;
}
}
self.dest.map_or_else(
|| {
debug!("Called read_block() with no data");
},
|dest| {
for i in 0..4 {
// we work off an array of u8 so we need to assemble those
// back into a u32
let mut v = 0;
match i {
0 => v = regs.data_out0.get(),
1 => v = regs.data_out1.get(),
2 => v = regs.data_out2.get(),
3 => v = regs.data_out3.get(),
_ => {}
}
dest[blocknum + (i * 4) + 0] = (v >> 0) as u8;
dest[blocknum + (i * 4) + 1] = (v >> 8) as u8;
dest[blocknum + (i * 4) + 2] = (v >> 16) as u8;
dest[blocknum + (i * 4) + 3] = (v >> 24) as u8;
}
},
);
}
fn write_block(&self, blocknum: usize) {
let regs = self.registers;
let blocknum = blocknum * AES128_BLOCK_SIZE;
loop {
if self.input_ready() {
break;
}
}
self.source.map_or_else(
|| {
// This is the case that dest = source
self.dest.map_or_else(
|| {
debug!("Called write_block() with no data");
},
|dest| {
for i in 0..4 {
// we work off an array of u8 so we need to
// assemble those back into a u32
let mut v = dest[blocknum + (i * 4) + 0] as usize;
v |= (dest[blocknum + (i * 4) + 1] as usize) << 8;
v |= (dest[blocknum + (i * 4) + 2] as usize) << 16;
v |= (dest[blocknum + (i * 4) + 3] as usize) << 24;
match i {
0 => regs.data_in0.set(v as u32),
1 => regs.data_in1.set(v as u32),
2 => regs.data_in2.set(v as u32),
3 => regs.data_in3.set(v as u32),
_ => {}
}
}
},
)
},
|source| {
for i in 0..4 {
// we work off an array of u8 so we need to assemble
// those back into a u32
let mut v = source[blocknum + (i * 4) + 0] as usize;
v |= (source[blocknum + (i * 4) + 1] as usize) << 8;
v |= (source[blocknum + (i * 4) + 2] as usize) << 16;
v |= (source[blocknum + (i * 4) + 3] as usize) << 24;
match i {
0 => regs.data_in0.set(v as u32),
1 => regs.data_in1.set(v as u32),
2 => regs.data_in2.set(v as u32),
3 => regs.data_in3.set(v as u32),
_ => {}
}
}
},
);
}
fn set_key(&self, key: &[u8]) -> ReturnCode {
let regs = self.registers;
loop {
if self.idle() {
break;
}
}
if key.len() != AES128_KEY_SIZE {
return ReturnCode::EINVAL;
}
for i in 0..4 {
let mut k = key[i * 4 + 0] as usize;
k |= (key[i * 4 + 1] as usize) << 8;
k |= (key[i * 4 + 2] as usize) << 16;
k |= (key[i * 4 + 3] as usize) << 24;
match i {
0 => regs.key0.set(k as u32),
1 => regs.key1.set(k as u32),
2 => regs.key2.set(k as u32),
3 => regs.key3.set(k as u32),
_ => {}
}
}
// We must write the rest of the registers as well
regs.key4.set(0);
regs.key5.set(0);
regs.key6.set(0);
regs.key7.set(0);
ReturnCode::SUCCESS
}
fn do_crypt(&self, start_index: usize, stop_index: usize, wr_start_index: usize) {
// convert our indicies into the array into block numbers
// start and end are pointer for reading
// write is the pointer for writing
// Note that depending on whether or not we have separate source
// and dest buffers the write and read pointers may index into
// different arrays.
let start_block = start_index / AES128_BLOCK_SIZE;
let end_block = stop_index / AES128_BLOCK_SIZE;
let mut write_block = wr_start_index / AES128_BLOCK_SIZE;
for i in start_block..end_block {
self.write_block(write_block);
self.trigger();
self.read_block(i);
write_block = write_block + 1;
}
}
}
impl<'a> hil::symmetric_encryption::AES128<'a> for Aes<'a> {
fn enable(&self) {
self.configure(true);
}
fn disable(&self) {
self.clear();
}
fn set_client(&'a self, client: &'a dyn symmetric_encryption::Client<'a>) {
self.client.set(client);
}
fn set_iv(&self, _iv: &[u8]) -> ReturnCode {
// nothing because this is ECB
ReturnCode::SUCCESS
}
fn start_message(&self) {}
fn set_key(&self, key: &[u8]) -> ReturnCode {
self.set_key(key)
}
fn crypt(
&'a self,
source: Option<&'a mut [u8]>,
dest: &'a mut [u8],
start_index: usize,
stop_index: usize,
) -> Option<(ReturnCode, Option<&'a mut [u8]>, &'a mut [u8])> {
match stop_index.checked_sub(start_index) {
None => return Some((ReturnCode::EINVAL, source, dest)),
Some(s) => {
if s > MAX_LENGTH {
return Some((ReturnCode::EINVAL, source, dest));
}
if s % AES128_BLOCK_SIZE != 0 {
return Some((ReturnCode::EINVAL, source, dest));
}
}
}
self.dest.replace(dest);
// The crypt API has two cases: separate source and destination
// buffers and a single source buffer.
// If we don't have a separate source buffer, we overwrite the
// destination with the data. This means that read index and write
// index match
// If we do have a separate source buffer, we start writing from
// 0 and the read index is separate.
match source {
None => {
self.do_crypt(start_index, stop_index, start_index);
}
Some(src) => {
self.source.replace(src);
self.do_crypt(start_index, stop_index, 0);
}
}
self.client.map(|client| {
client.crypt_done(self.source.take(), self.dest.take().unwrap());
});
None
}
}
pub static mut AES: Aes<'static> = Aes::new();
impl kernel::hil::symmetric_encryption::AES128ECB for Aes<'_> {
fn set_mode_aes128ecb(&self, encrypting: bool) {
self.configure(encrypting);
}
}