ast10x0 : drain stale bootloader hash op
diff --git a/hal/blocking/src/cipher.rs b/hal/blocking/src/cipher.rs index 55d8875..d1aeced 100644 --- a/hal/blocking/src/cipher.rs +++ b/hal/blocking/src/cipher.rs
@@ -40,6 +40,12 @@ /// Key or IV is invalid or missing. KeyError, + + /// The hardware accelerator is busy and cannot process the cipher operation. + Busy, + + /// The operation did not complete within the expected time. + Timeout, } /// Trait for converting implementation-specific errors into a generic [`ErrorKind`]. @@ -183,7 +189,6 @@ /// /// - `key`: A reference to the key used for the cipher. /// - `nonce`: A reference to the nonce or IV used for the cipher. - /// - `mode`: The cipher mode to use. /// /// # Returns /// @@ -192,7 +197,6 @@ &'a mut self, key: &Self::Key, nonce: &Self::Nonce, - mode: M, ) -> Result<Self::CipherContext<'a>, Self::Error>; } @@ -232,7 +236,7 @@ } /// Optional trait for cipher contexts that support rekeying. -pub trait CipherRekey<K>: ErrorType { +pub trait CipherRekey: SymmetricCipher { /// Rekeys the cipher context with a new key. /// /// # Parameters @@ -242,7 +246,7 @@ /// # Returns /// /// A result indicating success or failure. - fn rekey(&mut self, new_key: &K) -> Result<(), Self::Error>; + fn rekey(&mut self, new_key: &Self::Key) -> Result<(), Self::Error>; } /// Error type for block-aligned container operations. @@ -410,7 +414,7 @@ /// - Security managers that don't perform encryption/decryption /// - Key stores and vaults with secure cleanup /// - Flexible composition with other cipher traits -pub trait SecureCipherOp: ErrorType { +pub trait SecureCipherOp { /// Securely clear internal state and zeroize sensitive data. /// /// This method performs a secure cleanup of all internal state, including: @@ -441,9 +445,9 @@ /// ```ignore /// let mut cipher = SecureAesCipher::new(); /// // ... perform cipher operations ... - /// cipher.clear_state()?; // Secure cleanup before dropping + /// cipher.clear_state(); // Secure cleanup before dropping /// ``` - fn clear_state(&mut self) -> Result<(), Self::Error>; + fn clear_state(&mut self); } /// Trait for querying cipher status and hardware state. @@ -586,11 +590,6 @@ /// /// # Common Types /// - /// - `&[u8]` for read-only associated data - /// - `[u8; N]` for fixed-size owned associated data - /// - `()` or empty slice if no associated data is needed - type AssociatedData: FromBytes + IntoBytes; - /// The authentication tag type for AEAD operations. /// /// The authentication tag is a cryptographic checksum that provides @@ -634,7 +633,7 @@ fn encrypt_aead( &mut self, plaintext: Self::PlainText, - associated_data: Self::AssociatedData, + associated_data: &[u8], ) -> Result<(Self::CipherText, Self::Tag), Self::Error>; /// Decrypts the given ciphertext with associated data and authentication tag. @@ -651,7 +650,7 @@ fn decrypt_aead( &mut self, ciphertext: Self::CipherText, - associated_data: Self::AssociatedData, + associated_data: &[u8], tag: Self::Tag, ) -> Result<Self::PlainText, Self::Error>; }
diff --git a/hal/blocking/src/digest.rs b/hal/blocking/src/digest.rs index 178bd18..7a62152 100644 --- a/hal/blocking/src/digest.rs +++ b/hal/blocking/src/digest.rs
@@ -54,7 +54,6 @@ //! # impl ErrorType for MyDigestImpl { type Error = core::convert::Infallible; } //! # impl DigestInit<Sha2_256> for MyDigestImpl { //! # type OpContext<'a> = MyContext<'a> where Self: 'a; -//! # type Output = Digest<8>; //! # fn init<'a>(&'a mut self, _: Sha2_256) -> Result<Self::OpContext<'a>, Self::Error> { todo!() } //! # } //! # struct MyContext<'a>(&'a mut MyDigestImpl); @@ -81,7 +80,6 @@ //! # impl ErrorType for MyDigestController { type Error = core::convert::Infallible; } //! # impl DigestInit<Sha2_256> for MyDigestController { //! # type Context = MyOwnedContext; -//! # type Output = Digest<8>; //! # fn init(self, _: Sha2_256) -> Result<Self::Context, Self::Error> { todo!() } //! # } //! # struct MyOwnedContext; @@ -417,9 +415,6 @@ /// The specified hash algorithm is not supported by the hardware or software implementation. UnsupportedAlgorithm, - /// Failed to allocate memory for the hash computation. - MemoryAllocationFailure, - /// Failed to initialize the hash computation context. InitializationError, @@ -435,9 +430,6 @@ /// General hardware failure during hash computation. HardwareFailure, - /// The specified output size is not valid for the hash function. - InvalidOutputSize, - /// Insufficient permissions to access the hardware or perform the hash computation. PermissionDenied, @@ -450,13 +442,11 @@ match self { Self::InvalidInputLength => write!(f, "invalid input data length"), Self::UnsupportedAlgorithm => write!(f, "unsupported hash algorithm"), - Self::MemoryAllocationFailure => write!(f, "memory allocation failed"), Self::InitializationError => write!(f, "failed to initialize hash computation"), Self::UpdateError => write!(f, "error updating hash computation"), Self::FinalizationError => write!(f, "error finalizing hash computation"), Self::Busy => write!(f, "hardware accelerator is busy"), Self::HardwareFailure => write!(f, "hardware failure during hash computation"), - Self::InvalidOutputSize => write!(f, "invalid output size for hash function"), Self::PermissionDenied => write!(f, "insufficient permissions to access hardware"), Self::NotInitialized => write!(f, "hash computation context not initialized"), } @@ -549,7 +539,6 @@ /// # impl ErrorType for MyDigestImpl { type Error = core::convert::Infallible; } /// # impl DigestInit<Sha2_256> for MyDigestImpl { /// # type OpContext<'a> = MyContext<'a> where Self: 'a; -/// # type Output = Digest<8>; /// # fn init<'a>(&'a mut self, _: Sha2_256) -> Result<Self::OpContext<'a>, Self::Error> { todo!() } /// # } /// # struct MyContext<'a>(&'a mut MyDigestImpl); @@ -571,26 +560,20 @@ /// This associated type represents the stateful context returned by [`init`](Self::init) /// that can be used to perform the actual digest operations via [`DigestOp`]. /// The lifetime parameter ensures the context cannot outlive the device that created it. - type OpContext<'a>: DigestOp<Output = Self::Output> + type OpContext<'a>: DigestOp<Output = T::Digest> where Self: 'a; - /// The output type produced by this digest implementation. - /// - /// This type must implement [`IntoBytes`] to allow conversion to byte arrays - /// for interoperability with other systems and zero-copy operations. - type Output: IntoBytes; - /// Init instance of the crypto function with the given context. /// /// # Parameters /// - /// - `init_params`: The context or configuration parameters for the crypto function. + /// - `algorithm`: The zero-sized algorithm marker type specifying which hash function to use. /// /// # Returns /// /// A new instance of the hash function. - fn init(&mut self, init_params: T) -> Result<Self::OpContext<'_>, Self::Error>; + fn init(&mut self, algorithm: T) -> Result<Self::OpContext<'_>, Self::Error>; } /// Trait for resetting digest computation contexts. @@ -748,7 +731,6 @@ /// # } /// # impl DigestInit<Sha2_256> for MyController { /// # type Context = MyContext; - /// # type Output = Digest<8>; /// # fn init(self, _: Sha2_256) -> Result<Self::Context, Self::Error> { todo!() } /// # } /// let controller = MyController; @@ -761,13 +743,7 @@ /// /// This context has no lifetime constraints and can be stored in structs, /// moved between functions, and persisted across IPC boundaries. - type Context: DigestOp<Output = Self::Output, Controller = Self>; - - /// The output type produced by this digest implementation. - /// - /// This type must implement [`IntoBytes`] to allow conversion to byte arrays - /// for interoperability with other systems and zero-copy operations. - type Output: IntoBytes; + type Context: DigestOp<Output = T::Digest, Controller = Self>; /// Initialize a new digest computation context. /// @@ -776,12 +752,12 @@ /// /// # Parameters /// - /// - `init_params`: Algorithm-specific initialization parameters + /// - `algorithm`: The zero-sized algorithm marker type specifying which hash function to use. /// /// # Returns /// /// An owned context that can be used for digest operations. - fn init(self, init_params: T) -> Result<Self::Context, Self::Error>; + fn init(self, algorithm: T) -> Result<Self::Context, Self::Error>; } /// Trait for performing digest operations with owned contexts.
diff --git a/platform/impls/baremetal/mock/src/hash.rs b/platform/impls/baremetal/mock/src/hash.rs index 640f1ea..b0b9914 100644 --- a/platform/impls/baremetal/mock/src/hash.rs +++ b/platform/impls/baremetal/mock/src/hash.rs
@@ -83,13 +83,12 @@ ($algo:ident) => { impl DigestInit<$algo> for MockDigestDevice { type OpContext<'a> = MockHasher<'a, $algo>; - type Output = <$algo as DigestAlgorithm>::Digest; - fn init(&mut self, init_params: $algo) -> Result<Self::OpContext<'_>, Self::Error> { + fn init(&mut self, algorithm: $algo) -> Result<Self::OpContext<'_>, Self::Error> { // In a real implementation, we'd configure the hardware here Ok(Self::OpContext { hw: self, - _alg: init_params, + _alg: algorithm, data_processed: 0, }) } @@ -183,14 +182,13 @@ ($algo:ident) => { impl DigestInit<$algo> for MockDigestController { type Context = MockOwnedContext<$algo>; - type Output = <$algo as DigestAlgorithm>::Digest; - fn init(self, init_params: $algo) -> Result<Self::Context, Self::Error> { + fn init(self, algorithm: $algo) -> Result<Self::Context, Self::Error> { // Controller moves into the context // In hardware implementation, this might claim hardware resources Ok(MockOwnedContext { controller: self, - algorithm: init_params, + algorithm, data_processed: 0, }) }
diff --git a/platform/impls/rustcrypto/src/cipher.rs b/platform/impls/rustcrypto/src/cipher.rs index cc0fc70..15664cc 100644 --- a/platform/impls/rustcrypto/src/cipher.rs +++ b/platform/impls/rustcrypto/src/cipher.rs
@@ -233,7 +233,6 @@ &'a mut self, key: &Self::Key, nonce: &Self::Nonce, - _mode: Aes256CtrMode, ) -> Result<Self::CipherContext<'a>, Self::Error> { // Validate key and nonce lengths (compile-time guaranteed by types) // Create new context with the provided key and IV @@ -409,7 +408,7 @@ #[test] fn test_cipher_init_trait() { let mut cipher = Aes256CtrCipher; - let result = cipher.init(&TEST_KEY, &TEST_IV, Aes256CtrMode); + let result = cipher.init(&TEST_KEY, &TEST_IV); assert!( result.is_ok(), "Failed to create context via CipherInit trait"
diff --git a/platform/impls/rustcrypto/src/controller.rs b/platform/impls/rustcrypto/src/controller.rs index e04265e..12540cd 100644 --- a/platform/impls/rustcrypto/src/controller.rs +++ b/platform/impls/rustcrypto/src/controller.rs
@@ -69,7 +69,7 @@ fn kind(&self) -> DigestErrorKind { match self { CryptoError::InvalidKeyLength => DigestErrorKind::InvalidInputLength, - CryptoError::InvalidOutputLength => DigestErrorKind::InvalidOutputSize, + CryptoError::InvalidOutputLength => DigestErrorKind::FinalizationError, CryptoError::OperationFailed => DigestErrorKind::HardwareFailure, } } @@ -218,7 +218,6 @@ // Digest initialization - creates SHA-256 context impl DigestInit<Sha2_256> for RustCryptoController { type Context = DigestContext256; - type Output = Digest<8>; // SHA-256 output as 8 words of 32 bits fn init(self, _algorithm: Sha2_256) -> Result<Self::Context, Self::Error> { Ok(DigestContext256(Sha256::new())) @@ -228,7 +227,6 @@ // Digest initialization - creates SHA-384 context impl DigestInit<Sha2_384> for RustCryptoController { type Context = DigestContext384; - type Output = Digest<12>; // SHA-384 output as 12 words of 32 bits fn init(self, _algorithm: Sha2_384) -> Result<Self::Context, Self::Error> { Ok(DigestContext384(Sha384::new())) @@ -238,7 +236,6 @@ // Digest initialization - creates SHA-512 context impl DigestInit<Sha2_512> for RustCryptoController { type Context = DigestContext512; - type Output = Digest<16>; // SHA-512 output as 16 words of 32 bits fn init(self, _algorithm: Sha2_512) -> Result<Self::Context, Self::Error> { Ok(DigestContext512(Sha512::new()))
diff --git a/target/ast10x0/peripherals/hace/aes.rs b/target/ast10x0/peripherals/hace/aes.rs index 5c2d92e..19b5221 100644 --- a/target/ast10x0/peripherals/hace/aes.rs +++ b/target/ast10x0/peripherals/hace/aes.rs
@@ -61,9 +61,7 @@ /// /// # Safety /// No concurrent or reentrant HACE access for the returned lifetime. - pub unsafe fn from_device<Y: FnMut(u32)>( - device: &'a mut super::device::HaceDevice<Y>, - ) -> Self { + pub unsafe fn from_device<Y: FnMut(u32)>(device: &'a mut super::device::HaceDevice<Y>) -> Self { // Borrow split; retained `yield_fn` keeps the device exclusively borrowed. let regs = device.regs; let poll_budget = device.poll_budget; @@ -96,10 +94,7 @@ output: &mut [u8], ) -> Result<(), HaceError> { // Enforce block-aligned sizing before programming the engine. - if input.is_empty() - || input.len() % AES_BLOCK != 0 - || output.len() < input.len() - { + if input.is_empty() || input.len() % AES_BLOCK != 0 || output.len() < input.len() { return Err(HaceError::InvalidInput); } let kbits = Self::keylen_bits(key)?; @@ -120,10 +115,7 @@ self.ctx.dst.addr = out_ptr; self.ctx.dst.len = len | HACE_SG_LAST; - let cmd = AES_CMD_BASE - | kbits - | mode_bits - | if encrypt { HACE_CMD_ENCRYPT } else { 0 }; + let cmd = AES_CMD_BASE | kbits | mode_bits | if encrypt { HACE_CMD_ENCRYPT } else { 0 }; self.ctx.cmd = cmd; // Program descriptor addresses, ctx base, and data length. @@ -198,11 +190,11 @@ } } - // ===== Optional openprot cipher-trait skin (ADR-A1) ===================== - // - // Thin fixed-`N` wrapper over `AesCipher`. Kept separate because - // `SymmetricCipher` uses fixed associated buffer types and cannot express - // large streaming DMA paths. +// ===== Optional openprot cipher-trait skin (ADR-A1) ===================== +// +// Thin fixed-`N` wrapper over `AesCipher`. Kept separate because +// `SymmetricCipher` uses fixed associated buffer types and cannot express +// large streaming DMA paths. /// AES-ECB mode marker (port-defined; the hal declares no concrete modes). #[derive(Debug, Clone, Copy)] @@ -219,6 +211,8 @@ /// Owned AES key for the trait skin (raw-key path only). /// /// Size selects variant: 16 => AES-128, 32 => AES-256. +/// +/// The key bytes are zeroized when this value is dropped. #[derive(Clone)] pub enum AesKey { Aes128([u8; 16]), @@ -233,6 +227,19 @@ AesKey::Aes256(k) => k, } } + + fn zeroize(&mut self) { + match self { + AesKey::Aes128(k) => k.fill(0), + AesKey::Aes256(k) => k.fill(0), + } + } +} + +impl Drop for AesKey { + fn drop(&mut self) { + self.zeroize(); + } } /// Fixed-`N` openprot cipher-trait skin bound to one [`HaceDevice`]. @@ -295,7 +302,6 @@ &'a mut self, key: &Self::Key, nonce: &Self::Nonce, - _mode: $mode, ) -> Result<Self::CipherContext<'a>, Self::Error> { // SAFETY: `AesSkin::new` guarantees non-reentrancy; reborrow is exclusive. let core = unsafe { AesCipher::from_device(&mut *self.dev) }; @@ -314,6 +320,7 @@ impl<'a, const N: usize> CipherOp<Ecb> for AesOp<'a, N, Ecb> { fn encrypt(&mut self, plaintext: [u8; N]) -> Result<[u8; N], HaceError> { + const { assert!(N % AES_BLOCK == 0, "AesSkin<N>: N must be a multiple of 16") }; let mut ct = [0u8; N]; self.core .ecb_encrypt(self.key.as_slice(), &plaintext, &mut ct)?; @@ -321,6 +328,7 @@ } fn decrypt(&mut self, ciphertext: [u8; N]) -> Result<[u8; N], HaceError> { + const { assert!(N % AES_BLOCK == 0, "AesSkin<N>: N must be a multiple of 16") }; let mut pt = [0u8; N]; self.core .ecb_decrypt(self.key.as_slice(), &ciphertext, &mut pt)?; @@ -330,16 +338,27 @@ impl<'a, const N: usize> CipherOp<Cbc> for AesOp<'a, N, Cbc> { fn encrypt(&mut self, plaintext: [u8; N]) -> Result<[u8; N], HaceError> { + const { assert!(N % AES_BLOCK == 0, "AesSkin<N>: N must be a multiple of 16") }; let mut ct = [0u8; N]; self.core .cbc_encrypt(self.key.as_slice(), &self.iv, &plaintext, &mut ct)?; + // Advance IV to last ciphertext block so sequential encrypt() calls + // form a correct CBC chain instead of reusing the original IV. + if let Some(last) = ct.get(N - AES_BLOCK..) { + self.iv.copy_from_slice(last); + } Ok(ct) } fn decrypt(&mut self, ciphertext: [u8; N]) -> Result<[u8; N], HaceError> { + const { assert!(N % AES_BLOCK == 0, "AesSkin<N>: N must be a multiple of 16") }; let mut pt = [0u8; N]; self.core .cbc_decrypt(self.key.as_slice(), &self.iv, &ciphertext, &mut pt)?; + // Advance IV to last ciphertext block (CBC decrypt chaining). + if let Some(last) = ciphertext.get(N - AES_BLOCK..) { + self.iv.copy_from_slice(last); + } Ok(pt) } }
diff --git a/target/ast10x0/peripherals/hace/device.rs b/target/ast10x0/peripherals/hace/device.rs index 72b8eba..8c6df49 100644 --- a/target/ast10x0/peripherals/hace/device.rs +++ b/target/ast10x0/peripherals/hace/device.rs
@@ -4,8 +4,9 @@ //! HACE device binding with cooperative yield. use super::constants::DEFAULT_POLL_BUDGET; -use super::context::{CryptoContext, HashContext, acquire_crypto_ctx, acquire_shared_ctx}; +use super::context::{acquire_crypto_ctx, acquire_shared_ctx, CryptoContext, HashContext}; use super::registers::HaceRegisters; +use crate::scu::{ClockRegisterHalf, ScuRegisters}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum HashAlgo { @@ -95,9 +96,31 @@ /// Caller must coordinate singleton access globally. /// This type is non-reentrant: only one `HaceDevice` may be active at a time. pub unsafe fn new_global_with_yield(yield_fn: Y) -> Self { + // SCU080 bit 13 = StopYCLKForHACE. Write bit 13 to SCU084 to clear the + // clock-stop bit and enable the HACE YCLK before touching any HACE registers. + // SAFETY: SCU is a singleton; this is called under the same single-instance + // contract as HaceRegisters::new_global — the caller guarantees exclusivity. + let scu = unsafe { ScuRegisters::new_global_unlocked() }; + scu.ungate_clock_mask(ClockRegisterHalf::Lower, 1 << 13); + + // SAFETY: Caller coordinates singleton access. + let regs = unsafe { HaceRegisters::new_global() }; + + // Drain any in-progress hash operation left by the bootloader. + // On real hardware the engine may be busy when firmware starts; the + // HACE W1C clear of `hash_intflag` is ignored while `HashEngStsFlag` + // (bit 0) is set, causing the first poll to return a stale flag and the + // digest buffer to read back as the IV (never written by the engine). + // We stop the engine, then spin until it goes idle, then clear the + // stale flag before handing the device to callers. + regs.stop_hash_operation(); + while regs.hash_engine_is_busy() { + core::hint::spin_loop(); + } + regs.clear_hash_intflag(); + Self { - // SAFETY: Caller coordinates singleton access. - regs: unsafe { HaceRegisters::new_global() }, + regs, // SAFETY: the `unsafe fn new*` single-instance contract makes this // the sole live device, hence the sole holder of these pointers. ctx: unsafe { acquire_shared_ctx() },
diff --git a/target/ast10x0/peripherals/hace/digest.rs b/target/ast10x0/peripherals/hace/digest.rs index 303aaf8..0ea53b4 100644 --- a/target/ast10x0/peripherals/hace/digest.rs +++ b/target/ast10x0/peripherals/hace/digest.rs
@@ -3,18 +3,22 @@ //! Generic HACE Digest HAL adapter for OpenPRoT +use super::constants::{ + HACE_SG_LAST, POLL_YIELD_NS, SHA256_HASH_CMD, SHA384_HASH_CMD, SHA512_HASH_CMD, +}; use super::context::{ - HACE_BLOCK_SIZE, HACE_BLOCK_SIZE_128, HashContext, SHA256_DIGEST_SIZE, SHA256_IV, + HashContext, HACE_BLOCK_SIZE, HACE_BLOCK_SIZE_128, SHA256_DIGEST_SIZE, SHA256_IV, SHA384_DIGEST_SIZE, SHA384_IV, SHA512_DIGEST_SIZE, SHA512_IV, }; use super::error::HaceError; use super::helpers::{fill_padding, load_iv, ptr_to_u32}; -use super::constants::{HACE_SG_LAST, POLL_YIELD_NS, SHA256_HASH_CMD, SHA384_HASH_CMD, SHA512_HASH_CMD}; use super::registers::HaceRegisters; -use openprot_hal_blocking::digest::{Digest, DigestAlgorithm, ErrorType, Sha2_256, Sha2_384, Sha2_512}; -use openprot_hal_blocking::digest::scoped::{DigestCtrlReset, DigestInit, DigestOp}; -use zerocopy::IntoBytes; use core::marker::PhantomData; +use openprot_hal_blocking::digest::scoped::{DigestCtrlReset, DigestInit, DigestOp}; +use openprot_hal_blocking::digest::{ + Digest, DigestAlgorithm, ErrorType, Sha2_256, Sha2_384, Sha2_512, +}; +use zerocopy::IntoBytes; /// Per-algorithm constants required by the HACE driver. /// @@ -116,9 +120,7 @@ /// # Safety /// Caller must ensure no concurrent or reentrant HACE access for the /// lifetime of the returned [`HaceDigest`]. - pub unsafe fn from_device<Y: FnMut(u32)>( - device: &'a mut super::device::HaceDevice<Y>, - ) -> Self { + pub unsafe fn from_device<Y: FnMut(u32)>(device: &'a mut super::device::HaceDevice<Y>) -> Self { // Borrow split. `regs`/`poll_budget`/`ctx` are `Copy`d out; the // retained `&'a mut device.yield_fn` reborrow pins `&'a mut HaceDevice` // for the whole life of the returned op — that is the arbiter: a @@ -140,7 +142,6 @@ } } - impl<'a, T: DigestAlgorithm> ErrorType for HaceDigest<'a, T> { type Error = HaceError; } @@ -149,8 +150,10 @@ where T::Digest: IntoBytes, { - type OpContext<'b> = HaceDigest<'b, T> where Self: 'b; - type Output = T::Digest; + type OpContext<'b> + = HaceDigest<'b, T> + where + Self: 'b; fn init(&mut self, _algo: T) -> Result<Self::OpContext<'_>, Self::Error> { // Mirror aspeed-rust init sequence exactly: @@ -229,7 +232,8 @@ let method = self.ctx.method; self.regs.clear_hash_intflag(); - self.regs.program_hash_operation(sg_addr, digest_addr, total_len, method); + self.regs + .program_hash_operation(sg_addr, digest_addr, total_len, method); let mut done = false; for _ in 0..self.poll_budget { @@ -272,7 +276,8 @@ let method = this.ctx.method; this.regs.clear_hash_intflag(); - this.regs.program_hash_operation(sg_addr, digest_addr, bufcnt, method); + this.regs + .program_hash_operation(sg_addr, digest_addr, bufcnt, method); for _ in 0..this.poll_budget { if this.regs.hash_intflag_is_set() { @@ -303,4 +308,3 @@ Ok(()) } } -
diff --git a/target/ast10x0/peripherals/hace/error.rs b/target/ast10x0/peripherals/hace/error.rs index 8a43297..19bcb5f 100644 --- a/target/ast10x0/peripherals/hace/error.rs +++ b/target/ast10x0/peripherals/hace/error.rs
@@ -44,8 +44,8 @@ impl CipherError for HaceError { fn kind(&self) -> CipherErrorKind { match self { - HaceError::Busy => CipherErrorKind::HardwareFailure, - HaceError::Timeout => CipherErrorKind::HardwareFailure, + HaceError::Busy => CipherErrorKind::Busy, + HaceError::Timeout => CipherErrorKind::Timeout, HaceError::InvalidInput => CipherErrorKind::InvalidInput, HaceError::Internal => CipherErrorKind::HardwareFailure, }
diff --git a/target/ast10x0/peripherals/hace/helpers.rs b/target/ast10x0/peripherals/hace/helpers.rs index f198b87..3e38631 100644 --- a/target/ast10x0/peripherals/hace/helpers.rs +++ b/target/ast10x0/peripherals/hace/helpers.rs
@@ -22,7 +22,11 @@ let index = (bufcnt + remaining) & (block_size - 1); let padlen = if block_size == 64 { - if index < 56 { 56 - index } else { 64 + 56 - index } + if index < 56 { + 56 - index + } else { + 64 + 56 - index + } } else if index < 112 { 112 - index } else {
diff --git a/target/ast10x0/peripherals/hace/hmac.rs b/target/ast10x0/peripherals/hace/hmac.rs index 095b9c4..3a7f736 100644 --- a/target/ast10x0/peripherals/hace/hmac.rs +++ b/target/ast10x0/peripherals/hace/hmac.rs
@@ -77,7 +77,10 @@ } let mut bytes = [0u8; HMAC_KEY_CAP]; bytes[..key.len()].copy_from_slice(key); - Ok(Self { bytes, len: key.len() }) + Ok(Self { + bytes, + len: key.len(), + }) } #[inline] @@ -104,9 +107,7 @@ /// # Safety /// Caller must ensure no concurrent or reentrant HACE access for the /// lifetime of HMAC operations created from this controller. - pub unsafe fn from_device<Y: FnMut(u32)>( - device: &mut super::device::HaceDevice<Y>, - ) -> Self { + pub unsafe fn from_device<Y: FnMut(u32)>(device: &mut super::device::HaceDevice<Y>) -> Self { Self::new(device.poll_budget) } }
diff --git a/target/ast10x0/peripherals/hace/mod.rs b/target/ast10x0/peripherals/hace/mod.rs index 8f28307..a892337 100644 --- a/target/ast10x0/peripherals/hace/mod.rs +++ b/target/ast10x0/peripherals/hace/mod.rs
@@ -6,16 +6,16 @@ mod aes; mod constants; mod context; +mod device; mod digest; mod error; -mod device; mod helpers; mod hmac; mod registers; -pub use aes::{AES_BLOCK, AesCipher, AesKey, AesOp, AesSkin, Cbc, Ecb}; +pub use aes::{AesCipher, AesKey, AesOp, AesSkin, Cbc, Ecb, AES_BLOCK}; +pub use device::{HaceDevice, HashAlgo}; pub use digest::HaceDigest; pub use error::HaceError; -pub use device::{HaceDevice, HashAlgo}; pub use hmac::{HaceHmac, HaceHmacCtx, HmacKey, HMAC_KEY_CAP}; pub use registers::HaceRegisters;
diff --git a/target/ast10x0/peripherals/hace/registers.rs b/target/ast10x0/peripherals/hace/registers.rs index 23000a3..049673e 100644 --- a/target/ast10x0/peripherals/hace/registers.rs +++ b/target/ast10x0/peripherals/hace/registers.rs
@@ -53,6 +53,13 @@ self.regs().hace1c().read().hash_intflag().bit_is_set() } + /// Returns `true` while the hash engine is actively processing (HACE1C bit 0). + /// Used to drain any in-progress bootloader operation before starting our own. + #[inline] + pub(crate) fn hash_engine_is_busy(&self) -> bool { + self.regs().hace1c().read().hash_eng_sts_flag().bit_is_set() + } + #[inline] pub(crate) fn program_hash_operation( &self, @@ -63,8 +70,12 @@ ) { // SAFETY: Callers provide HACE-usable physical addresses and a valid command. self.regs().hace20().write(|w| unsafe { w.bits(src_addr) }); - self.regs().hace24().write(|w| unsafe { w.bits(digest_addr) }); - self.regs().hace28().write(|w| unsafe { w.bits(digest_addr) }); + self.regs() + .hace24() + .write(|w| unsafe { w.bits(digest_addr) }); + self.regs() + .hace28() + .write(|w| unsafe { w.bits(digest_addr) }); self.regs().hace2c().write(|w| unsafe { w.bits(data_len) }); self.regs().hace30().write(|w| unsafe { w.bits(cmd) }); }
diff --git a/target/ast10x0/tests/peripherals/hace/hace_aes/target.rs b/target/ast10x0/tests/peripherals/hace/hace_aes/target.rs index 6be2d68..60fc8d8 100644 --- a/target/ast10x0/tests/peripherals/hace/hace_aes/target.rs +++ b/target/ast10x0/tests/peripherals/hace/hace_aes/target.rs
@@ -15,7 +15,7 @@ use codegen as _; use console_backend::console_backend_write_all; use entry as _; -use target_common::{TargetInterface, declare_target}; +use target_common::{declare_target, TargetInterface}; pub struct Target {} @@ -93,19 +93,78 @@ let board = Ast10x0Board::new(Ast10x0BoardDescriptor { pinctrl_groups: &[], + i2c_buses: &[], }); // SAFETY: test runs once at boot with exclusive access to the board. - unsafe { board.init() }; + unsafe { + let _ = board.init(); + }; // NIST SP 800-38A KATs. - kat!("ecb-128 encrypt", ecb_encrypt, &AES128_KEY, &CBC_IV, &PT64, &ECB128_CT); - kat!("ecb-128 decrypt", ecb_decrypt, &AES128_KEY, &CBC_IV, &ECB128_CT, &PT64); - kat!("ecb-256 encrypt", ecb_encrypt, &AES256_KEY, &CBC_IV, &PT64, &ECB256_CT); - kat!("ecb-256 decrypt", ecb_decrypt, &AES256_KEY, &CBC_IV, &ECB256_CT, &PT64); - kat!("cbc-128 encrypt", cbc_encrypt, &AES128_KEY, &CBC_IV, &PT64, &CBC128_CT); - kat!("cbc-128 decrypt", cbc_decrypt, &AES128_KEY, &CBC_IV, &CBC128_CT, &PT64); - kat!("cbc-256 encrypt", cbc_encrypt, &AES256_KEY, &CBC_IV, &PT64, &CBC256_CT); - kat!("cbc-256 decrypt", cbc_decrypt, &AES256_KEY, &CBC_IV, &CBC256_CT, &PT64); + kat!( + "ecb-128 encrypt", + ecb_encrypt, + &AES128_KEY, + &CBC_IV, + &PT64, + &ECB128_CT + ); + kat!( + "ecb-128 decrypt", + ecb_decrypt, + &AES128_KEY, + &CBC_IV, + &ECB128_CT, + &PT64 + ); + kat!( + "ecb-256 encrypt", + ecb_encrypt, + &AES256_KEY, + &CBC_IV, + &PT64, + &ECB256_CT + ); + kat!( + "ecb-256 decrypt", + ecb_decrypt, + &AES256_KEY, + &CBC_IV, + &ECB256_CT, + &PT64 + ); + kat!( + "cbc-128 encrypt", + cbc_encrypt, + &AES128_KEY, + &CBC_IV, + &PT64, + &CBC128_CT + ); + kat!( + "cbc-128 decrypt", + cbc_decrypt, + &AES128_KEY, + &CBC_IV, + &CBC128_CT, + &PT64 + ); + kat!( + "cbc-256 encrypt", + cbc_encrypt, + &AES256_KEY, + &CBC_IV, + &PT64, + &CBC256_CT + ); + kat!( + "cbc-256 decrypt", + cbc_decrypt, + &AES256_KEY, + &CBC_IV, + &CBC256_CT, + &PT64 + ); // Non-block-size input must return InvalidInput. {
diff --git a/target/ast10x0/tests/peripherals/hace/hace_sha256/target.rs b/target/ast10x0/tests/peripherals/hace/hace_sha256/target.rs index 2752209..b20e921 100644 --- a/target/ast10x0/tests/peripherals/hace/hace_sha256/target.rs +++ b/target/ast10x0/tests/peripherals/hace/hace_sha256/target.rs
@@ -13,7 +13,7 @@ use openprot_hal_blocking::digest::{Sha2_256, Sha2_384, Sha2_512}; use openprot_hal_blocking::mac::scoped::{MacInit, MacOp}; use openprot_hal_blocking::mac::{HmacSha2_256, HmacSha2_384, HmacSha2_512}; -use target_common::{TargetInterface, declare_target}; +use target_common::{declare_target, TargetInterface}; pub struct Target {} @@ -138,9 +138,12 @@ let board = Ast10x0Board::new(Ast10x0BoardDescriptor { pinctrl_groups: &[], + i2c_buses: &[], }); // SAFETY: test runs once at boot with exclusive access to the board. - unsafe { board.init() }; + unsafe { + let _ = board.init(); + }; // --- SHA-256 --- oneshot_case!("sha256 empty", Sha2_256, Sha2_256, b"", EMPTY_256); @@ -158,9 +161,30 @@ // --- Production streaming path: 9000 B fed as 4096 + 4096 + 808 --- // 4096 is a multiple of both 64 and 128, so every full chunk lands on an // exact block boundary: this is the dominant PFR workload (goal.md §3.5). - stream_case!("sha256 stream-9000", Sha2_256, Sha2_256, 9000usize, 4096usize, STREAM9000_256); - stream_case!("sha384 stream-9000", Sha2_384, Sha2_384, 9000usize, 4096usize, STREAM9000_384); - stream_case!("sha512 stream-9000", Sha2_512, Sha2_512, 9000usize, 4096usize, STREAM9000_512); + stream_case!( + "sha256 stream-9000", + Sha2_256, + Sha2_256, + 9000usize, + 4096usize, + STREAM9000_256 + ); + stream_case!( + "sha384 stream-9000", + Sha2_384, + Sha2_384, + 9000usize, + 4096usize, + STREAM9000_384 + ); + stream_case!( + "sha512 stream-9000", + Sha2_512, + Sha2_512, + 9000usize, + 4096usize, + STREAM9000_512 + ); // --- D2 delta case (goal.md D2) --- // SHA-256, block 64. update(100): buffers a 36-byte remainder. update(28): @@ -242,30 +266,126 @@ // --- HMAC (software RFC-2104 over the HACE hasher), RFC-4231 vectors --- // Cases 1-4,6,7. Case 6/7 use a 131-byte key (> block size) exercising the // RFC-2104-correct `key_len > block_size` reduction path. - hmac_case!("hmac-sha256 rfc4231-1", HmacSha2_256, &HMAC_K1, b"Hi There", HMAC_C1_256); - hmac_case!("hmac-sha256 rfc4231-2", HmacSha2_256, b"Jefe", b"what do ya want for nothing?", HMAC_C2_256); - hmac_case!("hmac-sha256 rfc4231-3", HmacSha2_256, &HMAC_K3, &HMAC_D3, HMAC_C3_256); - hmac_case!("hmac-sha256 rfc4231-4", HmacSha2_256, &HMAC_K4, &HMAC_D4, HMAC_C4_256); - hmac_case!("hmac-sha256 rfc4231-6", HmacSha2_256, &HMAC_K6, b"Test Using Larger Than Block-Size Key - Hash Key First", HMAC_C6_256); + hmac_case!( + "hmac-sha256 rfc4231-1", + HmacSha2_256, + &HMAC_K1, + b"Hi There", + HMAC_C1_256 + ); + hmac_case!( + "hmac-sha256 rfc4231-2", + HmacSha2_256, + b"Jefe", + b"what do ya want for nothing?", + HMAC_C2_256 + ); + hmac_case!( + "hmac-sha256 rfc4231-3", + HmacSha2_256, + &HMAC_K3, + &HMAC_D3, + HMAC_C3_256 + ); + hmac_case!( + "hmac-sha256 rfc4231-4", + HmacSha2_256, + &HMAC_K4, + &HMAC_D4, + HMAC_C4_256 + ); + hmac_case!( + "hmac-sha256 rfc4231-6", + HmacSha2_256, + &HMAC_K6, + b"Test Using Larger Than Block-Size Key - Hash Key First", + HMAC_C6_256 + ); hmac_case!("hmac-sha256 rfc4231-7", HmacSha2_256, &HMAC_K7, b"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", HMAC_C7_256); - hmac_case!("hmac-sha384 rfc4231-1", HmacSha2_384, &HMAC_K1, b"Hi There", HMAC_C1_384); - hmac_case!("hmac-sha384 rfc4231-2", HmacSha2_384, b"Jefe", b"what do ya want for nothing?", HMAC_C2_384); - hmac_case!("hmac-sha384 rfc4231-3", HmacSha2_384, &HMAC_K3, &HMAC_D3, HMAC_C3_384); - hmac_case!("hmac-sha384 rfc4231-4", HmacSha2_384, &HMAC_K4, &HMAC_D4, HMAC_C4_384); - hmac_case!("hmac-sha384 rfc4231-6", HmacSha2_384, &HMAC_K6, b"Test Using Larger Than Block-Size Key - Hash Key First", HMAC_C6_384); + hmac_case!( + "hmac-sha384 rfc4231-1", + HmacSha2_384, + &HMAC_K1, + b"Hi There", + HMAC_C1_384 + ); + hmac_case!( + "hmac-sha384 rfc4231-2", + HmacSha2_384, + b"Jefe", + b"what do ya want for nothing?", + HMAC_C2_384 + ); + hmac_case!( + "hmac-sha384 rfc4231-3", + HmacSha2_384, + &HMAC_K3, + &HMAC_D3, + HMAC_C3_384 + ); + hmac_case!( + "hmac-sha384 rfc4231-4", + HmacSha2_384, + &HMAC_K4, + &HMAC_D4, + HMAC_C4_384 + ); + hmac_case!( + "hmac-sha384 rfc4231-6", + HmacSha2_384, + &HMAC_K6, + b"Test Using Larger Than Block-Size Key - Hash Key First", + HMAC_C6_384 + ); hmac_case!("hmac-sha384 rfc4231-7", HmacSha2_384, &HMAC_K7, b"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", HMAC_C7_384); // Isolation: K6_512 == SHA512(K6). Feeding it as a 64-byte (<=block) key // takes hmac.rs's NON-reduce branch but yields the identical K0, so it must // equal HMAC(K6,msg). If this PASSES, the in-init kd reduction is the bug. - hmac_case!("hmac-sha512 prereduced6", HmacSha2_512, &K6_512, b"Test Using Larger Than Block-Size Key - Hash Key First", HMAC_C6_512); + hmac_case!( + "hmac-sha512 prereduced6", + HmacSha2_512, + &K6_512, + b"Test Using Larger Than Block-Size Key - Hash Key First", + HMAC_C6_512 + ); - hmac_case!("hmac-sha512 rfc4231-1", HmacSha2_512, &HMAC_K1, b"Hi There", HMAC_C1_512); - hmac_case!("hmac-sha512 rfc4231-2", HmacSha2_512, b"Jefe", b"what do ya want for nothing?", HMAC_C2_512); - hmac_case!("hmac-sha512 rfc4231-3", HmacSha2_512, &HMAC_K3, &HMAC_D3, HMAC_C3_512); - hmac_case!("hmac-sha512 rfc4231-4", HmacSha2_512, &HMAC_K4, &HMAC_D4, HMAC_C4_512); - hmac_case!("hmac-sha512 rfc4231-6", HmacSha2_512, &HMAC_K6, b"Test Using Larger Than Block-Size Key - Hash Key First", HMAC_C6_512); + hmac_case!( + "hmac-sha512 rfc4231-1", + HmacSha2_512, + &HMAC_K1, + b"Hi There", + HMAC_C1_512 + ); + hmac_case!( + "hmac-sha512 rfc4231-2", + HmacSha2_512, + b"Jefe", + b"what do ya want for nothing?", + HMAC_C2_512 + ); + hmac_case!( + "hmac-sha512 rfc4231-3", + HmacSha2_512, + &HMAC_K3, + &HMAC_D3, + HMAC_C3_512 + ); + hmac_case!( + "hmac-sha512 rfc4231-4", + HmacSha2_512, + &HMAC_K4, + &HMAC_D4, + HMAC_C4_512 + ); + hmac_case!( + "hmac-sha512 rfc4231-6", + HmacSha2_512, + &HMAC_K6, + b"Test Using Larger Than Block-Size Key - Hash Key First", + HMAC_C6_512 + ); hmac_case!("hmac-sha512 rfc4231-7", HmacSha2_512, &HMAC_K7, b"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", HMAC_C7_512); // Streaming HMAC: split RFC-4231 case 7 data across multiple `update`s;