Skip to content

hmac: introduce hmac driver #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 30, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
412 changes: 412 additions & 0 deletions src/hace_controller.rs

Large diffs are not rendered by default.

424 changes: 33 additions & 391 deletions src/hash.rs

Large diffs are not rendered by default.

249 changes: 249 additions & 0 deletions src/hmac.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
use crate::hace_controller::{ContextCleanup, HaceController, HashAlgo, HACE_SG_EN};
use core::convert::Infallible;
use proposed_traits::mac::*;

// MacAlgorithm implementation for HashAlgo
impl MacAlgorithm for HashAlgo {
const OUTPUT_BITS: usize = 512; // Maximum size for all variants
type MacOutput = [u8; 64]; // Use the maximum size for all variants
type Key = [u8; 64]; // Use the maximum size for all variants
}

pub trait IntoHashAlgo {
fn to_hash_algo() -> HashAlgo;
}

pub struct Digest48(pub [u8; 48]);

impl Default for Digest48 {
fn default() -> Self {
Digest48([0u8; 48])
}
}

impl AsRef<[u8]> for Digest48 {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

impl AsMut<[u8]> for Digest48 {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}

pub struct Digest64(pub [u8; 64]);
impl Default for Digest64 {
fn default() -> Self {
Digest64([0u8; 64])
}
}

impl AsRef<[u8]> for Digest64 {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

impl AsMut<[u8]> for Digest64 {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}

pub struct Sha1;
pub struct Sha224;
pub struct Sha256;
pub struct Sha384;
pub struct Sha512;

impl MacAlgorithm for Sha1 {
const OUTPUT_BITS: usize = 160;
type MacOutput = [u8; 20];
type Key = [u8; 64];
}

impl MacAlgorithm for Sha224 {
const OUTPUT_BITS: usize = 224;
type MacOutput = [u8; 28];
type Key = [u8; 64];
}

impl MacAlgorithm for Sha256 {
const OUTPUT_BITS: usize = 256;
type MacOutput = [u8; 32];
type Key = [u8; 32];
}

impl MacAlgorithm for Sha384 {
const OUTPUT_BITS: usize = 384;
type MacOutput = Digest48; // Use Digest48 for 384 bits
type Key = [u8; 48];
}

impl MacAlgorithm for Sha512 {
const OUTPUT_BITS: usize = 512;
type MacOutput = Digest64; // Use Digest64 for 512 bits
type Key = [u8; 64];
}

impl Default for Sha256 {
fn default() -> Self {
Sha256
}
}

impl Default for Sha384 {
fn default() -> Self {
Sha384
}
}

impl Default for Sha512 {
fn default() -> Self {
Sha512
}
}

impl IntoHashAlgo for Sha256 {
fn to_hash_algo() -> HashAlgo {
HashAlgo::SHA256
}
}

impl IntoHashAlgo for Sha384 {
fn to_hash_algo() -> HashAlgo {
HashAlgo::SHA384
}
}

impl IntoHashAlgo for Sha512 {
fn to_hash_algo() -> HashAlgo {
HashAlgo::SHA512
}
}

impl<'ctrl, A> MacInit<A> for HaceController<'ctrl>
where
A: MacAlgorithm + IntoHashAlgo,
A::MacOutput: Default + AsMut<[u8]>,
A::Key: AsRef<[u8]>,
{
type OpContext<'a>
= OpContextImpl<'a, 'ctrl, A>
where
Self: 'a; // Define your OpContext type here

fn init<'a>(&'a mut self, _algo: A, key: &A::Key) -> Result<Self::OpContext<'a>, Self::Error> {
self.algo = A::to_hash_algo();
self.ctx_mut().method = self.algo.hash_cmd();
self.copy_iv_to_digest();
self.ctx_mut().block_size = self.algo.block_size() as u32;
self.ctx_mut().bufcnt = 0;
self.ctx_mut().digcnt = [0; 2];
self.ctx_mut().buffer.fill(0);
self.ctx_mut().digest.fill(0);
self.ctx_mut().ipad.fill(0);
self.ctx_mut().opad.fill(0);
self.ctx_mut().key.fill(0);

if key.as_ref().len() > self.ctx_mut().key.len() {
// hash key if it is too long
self.hash_key(key);
} else {
self.ctx_mut().key[..key.as_ref().len()].copy_from_slice(key.as_ref());
self.ctx_mut().ipad[..key.as_ref().len()].copy_from_slice(key.as_ref());
self.ctx_mut().opad[..key.as_ref().len()].copy_from_slice(key.as_ref());
self.ctx_mut().key_len = key.as_ref().len() as u32;
}

for i in 0..self.ctx_mut().block_size as usize {
self.ctx_mut().ipad[i] ^= 0x36;
self.ctx_mut().opad[i] ^= 0x5c;
}

Ok(OpContextImpl {
controller: self,
_phantom: core::marker::PhantomData,
})
}
}

pub struct OpContextImpl<'a, 'ctrl, A: MacAlgorithm + IntoHashAlgo> {
pub controller: &'a mut HaceController<'ctrl>,
_phantom: core::marker::PhantomData<A>,
}

impl<A> ErrorType for OpContextImpl<'_, '_, A>
where
A: MacAlgorithm + IntoHashAlgo,
{
type Error = Infallible;
}

impl<A> MacOp for OpContextImpl<'_, '_, A>
where
A: MacAlgorithm + IntoHashAlgo,
A::MacOutput: Default + AsMut<[u8]>,
{
type Output = A::MacOutput;

fn update(&mut self, input: &[u8]) -> Result<(), Self::Error> {
let ctrl = &mut self.controller;
let algo = ctrl.algo;
let block_size = algo.block_size();
let digest_size = algo.digest_size();
let mut bufcnt: u32;

{
let ctx = ctrl.ctx_mut();
ctx.digcnt[0] = block_size as u64;
ctx.bufcnt = block_size as u32;

// H(ipad + input)
let ipad = &ctx.ipad[..block_size];
ctx.buffer[..algo.block_size()].copy_from_slice(ipad);
ctx.buffer[algo.block_size()..(algo.block_size() + input.len())].copy_from_slice(input);
ctx.digcnt[0] += input.len() as u64;
ctx.bufcnt += input.len() as u32;
ctx.method &= !HACE_SG_EN; // Disable SG mode for key hashing
}

ctrl.fill_padding(0);
bufcnt = ctrl.ctx_mut().bufcnt;
ctrl.copy_iv_to_digest();
ctrl.start_hash_operation(bufcnt);
let slice =
unsafe { core::slice::from_raw_parts(ctrl.ctx_mut().digest.as_ptr(), digest_size) };

// H(opad + H(opad + hash sum))
{
let ctx = ctrl.ctx_mut();
ctx.digcnt[0] = block_size as u64 + digest_size as u64;
ctx.bufcnt = block_size as u32 + digest_size as u32;
ctx.buffer[..block_size].copy_from_slice(&ctx.opad[..block_size]);
ctx.buffer[block_size..(block_size + digest_size)].copy_from_slice(slice);
}
ctrl.fill_padding(0);
bufcnt = ctrl.ctx_mut().bufcnt;
ctrl.copy_iv_to_digest();
ctrl.start_hash_operation(bufcnt);

Ok(())
}

fn finalize(self) -> Result<Self::Output, Self::Error> {
let digest_size = self.controller.algo.digest_size();
let ctx = self.controller.ctx_mut();

let slice = unsafe { core::slice::from_raw_parts(ctx.digest.as_ptr(), digest_size) };

let mut output = A::MacOutput::default();
output.as_mut()[..digest_size].copy_from_slice(slice);

self.controller.cleanup_context();

Ok(output) // Return the final output
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#![no_std]
pub mod uart;
pub mod watchdog;
pub mod hace_controller;
pub mod hash;
pub mod hmac;
pub mod ecdsa;
pub mod rsa;
pub mod tests;
7 changes: 4 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -9,12 +9,13 @@ use ast1060_pac::{Wdt, Wdt1};
use aspeed_ddk::watchdog::WdtController;

use fugit::MillisDurationU32 as MilliSeconds;
use aspeed_ddk::hash::Controller;
use aspeed_ddk::hace_controller::HaceController;
use aspeed_ddk::syscon::SysCon;
use aspeed_ddk::ecdsa::AspeedEcdsa;
use aspeed_ddk::rsa::AspeedRsa;

use aspeed_ddk::tests::functional::hash_test::run_hash_tests;
use aspeed_ddk::tests::functional::hmac_test::run_hmac_tests;
use aspeed_ddk::tests::functional::ecdsa_test::run_ecdsa_tests;
use aspeed_ddk::tests::functional::rsa_test::run_rsa_tests;
use panic_halt as _;
@@ -135,9 +136,9 @@ fn main() -> ! {
let mut syscon = SysCon::new(delay.clone(), scu);
syscon.enable_hace();

let mut hace_controller = Controller::new(hace);

let mut hace_controller = HaceController::new(&hace);
run_hash_tests(&mut uart_controller, &mut hace_controller);
run_hmac_tests(&mut uart_controller, &mut hace_controller);

// Enable RSA and ECC
syscon.enable_rsa_ecc();
66 changes: 59 additions & 7 deletions src/tests/functional/hash_test.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::hace_controller::HaceController;
use crate::hash::{IntoHashAlgo, Sha256, Sha384, Sha512};
use crate::uart::UartController;
use crate::hash::{Sha256, Sha384, Sha512, Controller, IntoHashAlgo};
use proposed_traits::digest::{DigestInit, DigestOp, DigestAlgorithm};
use core::any::TypeId;
use embedded_io::Write;


use proposed_traits::digest::{DigestAlgorithm, DigestInit, DigestOp};

fn print_hex_array(uart: &mut UartController, data: &[u8], bytes_per_line: usize) {
for (i, b) in data.iter().enumerate() {
@@ -36,23 +36,75 @@ fn print_input(uart: &mut UartController, algo: &str, input: &[u8]) {
writeln!(uart, "]:").unwrap();
}

pub fn run_hash_tests(uart: &mut UartController, hace: &mut Controller) {
pub fn run_hash_tests(uart: &mut UartController, hace: &mut HaceController) {
let input = *b"hello_world";

run_hash::<Sha256>(uart, hace, &input);
run_hash::<Sha384>(uart, hace, &input);
run_hash::<Sha512>(uart, hace, &input);
}

fn run_hash<A>(uart: &mut UartController, ctrl: &mut Controller, input: &[u8])
fn run_hash<A>(uart: &mut UartController, ctrl: &mut HaceController, input: &[u8])
where
A: DigestAlgorithm + IntoHashAlgo + Default,
A: DigestAlgorithm + IntoHashAlgo + Default + 'static,
A::DigestOutput: Default + AsRef<[u8]> + AsMut<[u8]>,
{
let mut ctx = ctrl.init(A::default()).unwrap();
ctx.update(input).unwrap();
let output = ctx.finalize().unwrap();

print_input(uart, core::any::type_name::<A>(), input);
writeln!(uart, "\r\nOutput:").unwrap();
print_hex_array(uart, output.as_ref(), 16);

let expected = if TypeId::of::<A>() == TypeId::of::<Sha256>() {
Some(
&[
// Expected SHA-256 hash of "hello_world"
0x35, 0x07, 0x2c, 0x1a, 0xe5, 0x46, 0x35, 0x0e, 0x0b, 0xfa, 0x7a, 0xb1, 0x1d, 0x49,
0xdc, 0x6f, 0x12, 0x9e, 0x72, 0xcc, 0xd5, 0x7e, 0xc7, 0xeb, 0x67, 0x12, 0x25, 0xbb,
0xd1, 0x97, 0xc8, 0xf1,
][..],
)
} else if TypeId::of::<A>() == TypeId::of::<Sha384>() {
Some(
&[
0x7f, 0x25, 0x1a, 0x65, 0xac, 0xbe, 0x92, 0xaf, 0x4c, 0x6a, 0x6d, 0x62, 0x4c, 0x08,
0x60, 0xd9, 0xbe, 0x77, 0x32, 0x9e, 0x10, 0xe5, 0xbe, 0xb3, 0xb9, 0x59, 0x4f, 0x79,
0x16, 0x12, 0x8c, 0xd9, 0x56, 0x10, 0xa4, 0xd8, 0x4e, 0x3a, 0x83, 0xa2, 0x4a, 0x72,
0x36, 0x2f, 0x6c, 0x8f, 0x9c, 0x46,
][..],
)
} else if TypeId::of::<A>() == TypeId::of::<Sha512>() {
Some(
&[
0x94, 0xf4, 0x27, 0xef, 0xef, 0xa7, 0x4c, 0x12, 0x30, 0xc3, 0xe9, 0x3c, 0x35, 0x10,
0x4d, 0xcb, 0xaa, 0x8f, 0xf7, 0x1b, 0xa4, 0x53, 0x75, 0x83, 0xed, 0x83, 0xc0, 0x44,
0x9d, 0x60, 0x7c, 0x4e, 0x61, 0xb3, 0x9c, 0x4c, 0x5e, 0xea, 0x55, 0x43, 0xe0, 0x1d,
0x76, 0xa6, 0x8e, 0x22, 0x3d, 0xa0, 0x2b, 0x50, 0x05, 0x30, 0xa8, 0x21, 0x56, 0x62,
0x5c, 0xb9, 0x6e, 0xe8, 0xc8, 0xc8, 0x0a, 0x85,
][..],
)
} else {
None
};

if let Some(expected) = expected {
if output.as_ref() == expected {
writeln!(uart, "\r\n{}: Test passed!", core::any::type_name::<A>()).unwrap();
} else {
writeln!(uart, "\r\n{}: Test failed!", core::any::type_name::<A>()).unwrap();
writeln!(uart, "Expected:").unwrap();
print_hex_array(uart, expected, 16);
writeln!(uart, "Got:").unwrap();
print_hex_array(uart, output.as_ref(), 16);
}
} else {
writeln!(
uart,
"\r\n{}: No expected value defined.",
core::any::type_name::<A>()
)
.unwrap();
}
}
116 changes: 116 additions & 0 deletions src/tests/functional/hmac_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use crate::hace_controller::HaceController;
use crate::hmac::{IntoHashAlgo, Sha256, Sha384, Sha512};
use crate::uart::UartController;
use core::any::TypeId;
use embedded_io::Write;
use proposed_traits::mac::{MacAlgorithm, MacInit, MacOp};

fn print_hex_array(uart: &mut UartController, data: &[u8], bytes_per_line: usize) {
for (i, b) in data.iter().enumerate() {
if i % bytes_per_line == 0 {
writeln!(uart, "\r").unwrap();
} else {
write!(uart, " ").unwrap();
}
write!(uart, "{:02x}", b).unwrap();
}
writeln!(uart).unwrap();
}

fn print_input(uart: &mut UartController, algo: &str, input: &[u8]) {
match core::str::from_utf8(input) {
Ok(ascii) => {
write!(uart, "\r\n{} of \"{}\" [", algo, ascii).unwrap();
}
Err(_) => {
write!(uart, "\r\n{} of [", algo).unwrap();
}
}

for (i, b) in input.iter().enumerate() {
if i > 0 {
write!(uart, ", ").unwrap();
}
write!(uart, "0x{:02x}", b).unwrap();
}
writeln!(uart, "]:").unwrap();
}

pub fn run_hmac_tests(uart: &mut UartController, hace: &mut HaceController) {
let key256 = [0xb; 32];
let key384 = [0xb; 48];
let key512 = [0xb; 64];
let message = *b"The quick brown fox jumps over the lazy dog";

writeln!(uart, "\r\nRunning HMAC tests...").unwrap();
run_hmac::<Sha256>(uart, hace, &key256, &message);
run_hmac::<Sha384>(uart, hace, &key384, &message);
run_hmac::<Sha512>(uart, hace, &key512, &message);
}

fn run_hmac<A>(uart: &mut UartController, ctrl: &mut HaceController, key: &A::Key, input: &[u8])
where
A: MacAlgorithm + IntoHashAlgo + Default + 'static,
A::MacOutput: Default + AsRef<[u8]> + AsMut<[u8]>,
A::Key: AsRef<[u8]>,
{
let mut ctx = ctrl.init(A::default(), key).unwrap();
ctx.update(input).unwrap();
let output = ctx.finalize().unwrap();

print_input(uart, core::any::type_name::<A>(), input);
write!(uart, "\r\nKey: ").unwrap();
print_hex_array(uart, key.as_ref(), 16);
write!(uart, "\r\nOutput: ").unwrap();
print_hex_array(uart, output.as_ref(), 16);

let expected = if TypeId::of::<A>() == TypeId::of::<Sha256>() {
Some(
&[
0xde, 0x60, 0xb1, 0xd4, 0x83, 0xd2, 0x00, 0x11, 0xf1, 0xb4, 0x2f, 0x33, 0x70, 0x0c,
0xb4, 0x4f, 0xa3, 0x16, 0xc4, 0x43, 0xce, 0x43, 0x03, 0x78, 0xcb, 0x5d, 0x65, 0x42,
0x7f, 0x64, 0x34, 0x8d,
][..],
)
} else if TypeId::of::<A>() == TypeId::of::<Sha384>() {
Some(
&[
0xCC, 0xD7, 0xCA, 0xE4, 0x59, 0xE4, 0x23, 0xB9, 0x94, 0x06, 0x9A, 0xC1, 0xD3, 0xF8,
0x26, 0x41, 0x60, 0x88, 0x85, 0xAF, 0x04, 0x3A, 0x33, 0xAD, 0x51, 0x3E, 0x8E, 0x87,
0x47, 0x19, 0x66, 0x6C, 0x24, 0xD1, 0xC0, 0xDC, 0x54, 0xAE, 0xBB, 0xB9, 0x3B, 0x84,
0x34, 0xA1, 0xA9, 0x70, 0x83, 0x6D,
][..],
)
} else if TypeId::of::<A>() == TypeId::of::<Sha512>() {
Some(
&[
0xf1, 0x10, 0x1d, 0xe2, 0xb4, 0xfa, 0x09, 0xe6, 0xfb, 0x04, 0x9d, 0x2e, 0x12, 0x68,
0xdb, 0xe7, 0x65, 0x09, 0x22, 0x01, 0x75, 0x1a, 0x42, 0x1c, 0xbc, 0x80, 0x61, 0x09,
0x36, 0x14, 0x35, 0x81, 0x22, 0x0f, 0x3a, 0x77, 0x1f, 0xff, 0x10, 0xd8, 0xd8, 0x16,
0x63, 0x19, 0xb6, 0x0d, 0xf0, 0x98, 0xb3, 0x70, 0xdc, 0x5d, 0x1b, 0x01, 0x71, 0x4d,
0x97, 0x87, 0x12, 0x72, 0x24, 0x60, 0x67, 0x4f,
][..],
)
} else {
None
};

if let Some(expected) = expected {
if output.as_ref() == expected {
writeln!(uart, "\r\n{}: Test passed!", core::any::type_name::<A>()).unwrap();
} else {
writeln!(uart, "\r\n{}: Test failed!", core::any::type_name::<A>()).unwrap();
writeln!(uart, "Expected:").unwrap();
print_hex_array(uart, expected, 16);
writeln!(uart, "Got:").unwrap();
print_hex_array(uart, output.as_ref(), 16);
}
} else {
writeln!(
uart,
"\r\n{}: No expected value defined.",
core::any::type_name::<A>()
)
.unwrap();
}
}
1 change: 1 addition & 0 deletions src/tests/functional/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod hash_test;
pub mod hmac_test;
pub mod ecdsa_test;
pub mod rsa_test;
pub mod rsa_test_vec;