Refactor SHA to use trait. Implement Digest traits for SHA (#1908)
* feat(SHA): Refactor SHA to use trait. Implement Digest traits for SHA * Fix CI. Fix wrong sha mode for esp32 * Save hash register for interleaving operation An example (wip) `sha_fuzz.rs` was added to test different functionalities of the SHA driver and to ensure proper functionning under all cases. * Use random data when testing SHA * fix(SHA): Buffer words until a full block before writing to memory This fixes interleaving operations by buffering words into the SHA context until a full block can be processed. * Fix(SHA): Use correct length padding for SHA384 and SHA512. - This fixes a long running issue with SHA384 and SHA512, where some digest of specific sizes wouldn't compute correctly, by changing the padding length of the size field. * Re-export digest for convenience * Remove completed TODO * Remove SHA peripheral requirement. - Document safety of the SHA driver. --------- Co-authored-by: Scott Mabin <scott@mabez.dev>
This commit is contained in:
parent
ec130877b7
commit
70491b9e37
@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Added touch pad support for esp32 (#1873, #1956)
|
- Added touch pad support for esp32 (#1873, #1956)
|
||||||
- Allow configuration of period updating method for MCPWM timers (#1898)
|
- Allow configuration of period updating method for MCPWM timers (#1898)
|
||||||
- Add self-testing mode for TWAI peripheral. (#1929)
|
- Add self-testing mode for TWAI peripheral. (#1929)
|
||||||
|
- Added a `PeripheralClockControl::reset` to the driver constructors where missing (#1893)
|
||||||
|
- Added `digest::Digest` implementation to SHA (#1908)
|
||||||
- Added `debugger::debugger_connected`. (#1961)
|
- Added `debugger::debugger_connected`. (#1961)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
@ -24,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Allow DMA to/from psram for esp32s3 (#1827)
|
- Allow DMA to/from psram for esp32s3 (#1827)
|
||||||
- DMA buffers now don't require a static lifetime. Make sure to never `mem::forget` an in-progress DMA transfer (consider using `#[deny(clippy::mem_forget)]`) (#1837)
|
- DMA buffers now don't require a static lifetime. Make sure to never `mem::forget` an in-progress DMA transfer (consider using `#[deny(clippy::mem_forget)]`) (#1837)
|
||||||
- Peripherals (where possible) are now explicitly reset and enabled in their constructors (#1893)
|
- Peripherals (where possible) are now explicitly reset and enabled in their constructors (#1893)
|
||||||
|
- SHA driver now use specific structs for the hashing algorithm instead of a parameter. (#1908)
|
||||||
- Reset peripherals in driver constructors where missing (#1893, #1961)
|
- Reset peripherals in driver constructors where missing (#1893, #1961)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@ -22,6 +22,7 @@ cfg-if = "1.0.0"
|
|||||||
critical-section = "1.1.2"
|
critical-section = "1.1.2"
|
||||||
defmt = { version = "0.3.8", optional = true }
|
defmt = { version = "0.3.8", optional = true }
|
||||||
delegate = "0.12.0"
|
delegate = "0.12.0"
|
||||||
|
digest = { version = "0.10.7", default-features = false, optional = true }
|
||||||
document-features = "0.2.10"
|
document-features = "0.2.10"
|
||||||
embassy-futures = { version = "0.1.1", optional = true }
|
embassy-futures = { version = "0.1.1", optional = true }
|
||||||
embassy-sync = { version = "0.6.0", optional = true }
|
embassy-sync = { version = "0.6.0", optional = true }
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl EndianessConverter for NativeEndianess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Use BE for ESP32, NE otherwise
|
/// Use BE for ESP32, NE otherwise
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct SocDependentEndianess;
|
pub(crate) struct SocDependentEndianess;
|
||||||
|
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
@ -61,7 +62,7 @@ impl EndianessConverter for SocDependentEndianess {
|
|||||||
// It assumes incoming `dst` are aligned to desired layout (in future
|
// It assumes incoming `dst` are aligned to desired layout (in future
|
||||||
// ptr.is_aligned can be used). It also assumes that writes are done in FIFO
|
// ptr.is_aligned can be used). It also assumes that writes are done in FIFO
|
||||||
// order.
|
// order.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct AlignmentHelper<E: EndianessConverter> {
|
pub(crate) struct AlignmentHelper<E: EndianessConverter> {
|
||||||
buf: [u8; U32_ALIGN_SIZE],
|
buf: [u8; U32_ALIGN_SIZE],
|
||||||
buf_fill: usize,
|
buf_fill: usize,
|
||||||
|
|||||||
@ -32,12 +32,12 @@
|
|||||||
//! ```rust, no_run
|
//! ```rust, no_run
|
||||||
#![doc = crate::before_snippet!()]
|
#![doc = crate::before_snippet!()]
|
||||||
//! # use esp_hal::sha::Sha;
|
//! # use esp_hal::sha::Sha;
|
||||||
//! # use esp_hal::sha::ShaMode;
|
//! # use esp_hal::sha::Sha256;
|
||||||
//! # use core::option::Option::None;
|
//! # use core::option::Option::None;
|
||||||
//! # use nb::block;
|
//! # use nb::block;
|
||||||
//! let source_data = "HELLO, ESPRESSIF!".as_bytes();
|
//! let source_data = "HELLO, ESPRESSIF!".as_bytes();
|
||||||
//! let mut remaining = source_data;
|
//! let mut remaining = source_data;
|
||||||
//! let mut hasher = Sha::new(peripherals.SHA, ShaMode::SHA256);
|
//! let mut hasher = Sha256::new();
|
||||||
//! // Short hashes can be created by decreasing the output buffer to the
|
//! // Short hashes can be created by decreasing the output buffer to the
|
||||||
//! // desired length
|
//! // desired length
|
||||||
//! let mut output = [0u8; 32];
|
//! let mut output = [0u8; 32];
|
||||||
@ -61,107 +61,34 @@
|
|||||||
|
|
||||||
use core::{convert::Infallible, marker::PhantomData};
|
use core::{convert::Infallible, marker::PhantomData};
|
||||||
|
|
||||||
|
/// Re-export digest for convenience
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
pub use digest::Digest;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
|
||||||
peripherals::SHA,
|
|
||||||
reg_access::{AlignmentHelper, SocDependentEndianess},
|
reg_access::{AlignmentHelper, SocDependentEndianess},
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
};
|
};
|
||||||
|
|
||||||
// All the hash algorithms introduced in FIPS PUB 180-4 Spec.
|
/// Context for a SHA Accelerator driver instance
|
||||||
// – SHA-1
|
#[derive(Debug, Clone)]
|
||||||
// – SHA-224
|
pub struct Context<DM: crate::Mode> {
|
||||||
// – SHA-256
|
|
||||||
// – SHA-384
|
|
||||||
// – SHA-512
|
|
||||||
// – SHA-512/224
|
|
||||||
// – SHA-512/256
|
|
||||||
// – SHA-512/t (not implemented yet)
|
|
||||||
// Two working modes
|
|
||||||
// – Typical SHA
|
|
||||||
// – DMA-SHA (not implemented yet)
|
|
||||||
|
|
||||||
/// The SHA Accelerator driver instance
|
|
||||||
pub struct Sha<'d, DM: crate::Mode> {
|
|
||||||
sha: PeripheralRef<'d, SHA>,
|
|
||||||
mode: ShaMode,
|
|
||||||
alignment_helper: AlignmentHelper<SocDependentEndianess>,
|
alignment_helper: AlignmentHelper<SocDependentEndianess>,
|
||||||
cursor: usize,
|
cursor: usize,
|
||||||
first_run: bool,
|
first_run: bool,
|
||||||
finished: bool,
|
finished: bool,
|
||||||
|
/// Buffered bytes (SHA_M_n_REG) to be processed.
|
||||||
|
buffer: [u32; 32],
|
||||||
|
/// Saved digest (SHA_H_n_REG) for interleaving operation
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
saved_digest: Option<[u8; 64]>,
|
||||||
phantom: PhantomData<DM>,
|
phantom: PhantomData<DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hash Algorithm Mode
|
impl crate::private::Sealed for Context<crate::Blocking> {}
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum ShaMode {
|
|
||||||
SHA1,
|
|
||||||
#[cfg(not(esp32))]
|
|
||||||
SHA224,
|
|
||||||
SHA256,
|
|
||||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
|
||||||
SHA384,
|
|
||||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
|
||||||
SHA512,
|
|
||||||
#[cfg(any(esp32s2, esp32s3))]
|
|
||||||
SHA512_224,
|
|
||||||
#[cfg(any(esp32s2, esp32s3))]
|
|
||||||
SHA512_256,
|
|
||||||
// SHA512_(u16) // Max 511
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Maybe make Sha Generic (Sha<Mode>) in order to allow for better
|
|
||||||
// compiler optimizations? (Requires complex const generics which isn't stable
|
|
||||||
// yet)
|
|
||||||
|
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
fn mode_as_bits(mode: ShaMode) -> u8 {
|
impl crate::InterruptConfigurable for Context<crate::Blocking> {
|
||||||
match mode {
|
|
||||||
ShaMode::SHA1 => 0,
|
|
||||||
ShaMode::SHA224 => 1,
|
|
||||||
ShaMode::SHA256 => 2,
|
|
||||||
#[cfg(any(esp32s2, esp32s3))]
|
|
||||||
ShaMode::SHA384 => 3,
|
|
||||||
#[cfg(any(esp32s2, esp32s3))]
|
|
||||||
ShaMode::SHA512 => 4,
|
|
||||||
#[cfg(any(esp32s2, esp32s3))]
|
|
||||||
ShaMode::SHA512_224 => 5,
|
|
||||||
#[cfg(any(esp32s2, esp32s3))]
|
|
||||||
ShaMode::SHA512_256 => 6,
|
|
||||||
// _ => 0 // TODO: SHA512/t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> Sha<'d, crate::Blocking> {
|
|
||||||
/// Create a new instance in [crate::Blocking] mode.
|
|
||||||
#[cfg_attr(not(esp32), doc = "Optionally an interrupt handler can be bound.")]
|
|
||||||
pub fn new(sha: impl Peripheral<P = SHA> + 'd, mode: ShaMode) -> Self {
|
|
||||||
crate::into_ref!(sha);
|
|
||||||
|
|
||||||
PeripheralClockControl::reset(crate::system::Peripheral::Sha);
|
|
||||||
PeripheralClockControl::enable(crate::system::Peripheral::Sha);
|
|
||||||
|
|
||||||
// Setup SHA Mode
|
|
||||||
#[cfg(not(esp32))]
|
|
||||||
sha.mode()
|
|
||||||
.write(|w| unsafe { w.mode().bits(mode_as_bits(mode)) });
|
|
||||||
|
|
||||||
Self {
|
|
||||||
sha,
|
|
||||||
mode,
|
|
||||||
cursor: 0,
|
|
||||||
first_run: true,
|
|
||||||
finished: false,
|
|
||||||
alignment_helper: AlignmentHelper::default(),
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> crate::private::Sealed for Sha<'d, crate::Blocking> {}
|
|
||||||
|
|
||||||
#[cfg(not(esp32))]
|
|
||||||
impl<'d> crate::InterruptConfigurable for Sha<'d, crate::Blocking> {
|
|
||||||
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::SHA, handler.handler());
|
crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::SHA, handler.handler());
|
||||||
@ -171,7 +98,15 @@ impl<'d> crate::InterruptConfigurable for Sha<'d, crate::Blocking> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Allow/Implement SHA512_(u16)
|
impl<DM: crate::Mode> Context<DM> {
|
||||||
|
pub fn first_run(&self) -> bool {
|
||||||
|
self.first_run
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finished(&self) -> bool {
|
||||||
|
self.finished
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A few notes on this implementation with regards to 'memcpy',
|
// A few notes on this implementation with regards to 'memcpy',
|
||||||
// - It seems that ptr::write_bytes already acts as volatile, while ptr::copy_*
|
// - It seems that ptr::write_bytes already acts as volatile, while ptr::copy_*
|
||||||
@ -189,87 +124,73 @@ impl<'d> crate::InterruptConfigurable for Sha<'d, crate::Blocking> {
|
|||||||
|
|
||||||
// This implementation might fail after u32::MAX/8 bytes, to increase please see
|
// This implementation might fail after u32::MAX/8 bytes, to increase please see
|
||||||
// ::finish() length/self.cursor usage
|
// ::finish() length/self.cursor usage
|
||||||
impl<'d, DM: crate::Mode> Sha<'d, DM> {
|
pub trait Sha<DM: crate::Mode>: core::ops::DerefMut<Target = Context<DM>> {
|
||||||
pub fn first_run(&self) -> bool {
|
/// Constant containing the name of the algorithm as a string.
|
||||||
self.first_run
|
const ALGORITHM: &'static str;
|
||||||
|
|
||||||
|
/// Setup SHA Mode
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
fn mode_as_bits() -> u8;
|
||||||
|
|
||||||
|
fn chunk_length(&self) -> usize;
|
||||||
|
|
||||||
|
fn digest_length(&self) -> usize;
|
||||||
|
|
||||||
|
/// ESP32 requires that a control register to be written to calculate the
|
||||||
|
/// final SHA hash.
|
||||||
|
#[cfg(esp32)]
|
||||||
|
fn load_reg(&self);
|
||||||
|
|
||||||
|
/// ESP32 uses a different register per hash mode.
|
||||||
|
#[cfg(esp32)]
|
||||||
|
fn is_busy(&self) -> bool;
|
||||||
|
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
fn is_busy(&self) -> bool {
|
||||||
|
// Safety: This is safe because we only read `SHA_BUSY_REG`
|
||||||
|
let sha = unsafe { crate::peripherals::SHA::steal() };
|
||||||
|
sha.busy().read().bits() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finished(&self) -> bool {
|
#[cfg(esp32)]
|
||||||
self.finished
|
fn process_buffer(&mut self);
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
fn process_buffer(&mut self) {
|
fn process_buffer(&mut self) {
|
||||||
|
// Safety: This is safe because digest state is restored and saved between
|
||||||
|
// operations.
|
||||||
|
let sha = unsafe { crate::peripherals::SHA::steal() };
|
||||||
|
// Setup SHA Mode before processing current buffer.
|
||||||
|
sha.mode()
|
||||||
|
.write(|w| unsafe { w.mode().bits(Self::mode_as_bits()) });
|
||||||
if self.first_run {
|
if self.first_run {
|
||||||
// Set SHA_START_REG
|
// Set SHA_START_REG
|
||||||
self.sha.start().write(|w| unsafe { w.bits(1) });
|
sha.start().write(|w| unsafe { w.bits(1) });
|
||||||
self.first_run = false;
|
self.first_run = false;
|
||||||
} else {
|
} else {
|
||||||
|
// Restore previously saved hash if interleaving operation
|
||||||
|
if let Some(ref saved_digest) = self.saved_digest.take() {
|
||||||
|
self.alignment_helper.volatile_write_regset(
|
||||||
|
sha.h_mem(0).as_ptr(),
|
||||||
|
saved_digest,
|
||||||
|
64,
|
||||||
|
);
|
||||||
|
}
|
||||||
// SET SHA_CONTINUE_REG
|
// SET SHA_CONTINUE_REG
|
||||||
self.sha.continue_().write(|w| unsafe { w.bits(1) });
|
sha.continue_().write(|w| unsafe { w.bits(1) });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(esp32)]
|
// Wait until buffer has completely processed
|
||||||
fn process_buffer(&mut self) {
|
while self.is_busy() {}
|
||||||
if self.first_run {
|
|
||||||
match self.mode {
|
|
||||||
ShaMode::SHA1 => self.sha.sha1_start().write(|w| unsafe { w.bits(1) }),
|
|
||||||
ShaMode::SHA256 => self.sha.sha256_start().write(|w| unsafe { w.bits(1) }),
|
|
||||||
ShaMode::SHA384 => self.sha.sha384_start().write(|w| unsafe { w.bits(1) }),
|
|
||||||
ShaMode::SHA512 => self.sha.sha512_start().write(|w| unsafe { w.bits(1) }),
|
|
||||||
}
|
|
||||||
self.first_run = false;
|
|
||||||
} else {
|
|
||||||
match self.mode {
|
|
||||||
ShaMode::SHA1 => self.sha.sha1_continue().write(|w| unsafe { w.bits(1) }),
|
|
||||||
ShaMode::SHA256 => self.sha.sha256_continue().write(|w| unsafe { w.bits(1) }),
|
|
||||||
ShaMode::SHA384 => self.sha.sha384_continue().write(|w| unsafe { w.bits(1) }),
|
|
||||||
ShaMode::SHA512 => self.sha.sha512_continue().write(|w| unsafe { w.bits(1) }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn chunk_length(&self) -> usize {
|
// Save the content of the current hash for interleaving operation.
|
||||||
match self.mode {
|
let mut saved_digest = [0u8; 64];
|
||||||
ShaMode::SHA1 | ShaMode::SHA256 => 64,
|
self.alignment_helper.volatile_read_regset(
|
||||||
#[cfg(not(esp32))]
|
sha.h_mem(0).as_ptr(),
|
||||||
ShaMode::SHA224 => 64,
|
&mut saved_digest,
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
64 / self.alignment_helper.align_size(),
|
||||||
_ => 128,
|
);
|
||||||
}
|
self.saved_digest.replace(saved_digest);
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(esp32)]
|
|
||||||
fn is_busy(&self) -> bool {
|
|
||||||
match self.mode {
|
|
||||||
ShaMode::SHA1 => self.sha.sha1_busy().read().sha1_busy().bit_is_set(),
|
|
||||||
ShaMode::SHA256 => self.sha.sha256_busy().read().sha256_busy().bit_is_set(),
|
|
||||||
ShaMode::SHA384 => self.sha.sha384_busy().read().sha384_busy().bit_is_set(),
|
|
||||||
ShaMode::SHA512 => self.sha.sha512_busy().read().sha512_busy().bit_is_set(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(esp32))]
|
|
||||||
fn is_busy(&self) -> bool {
|
|
||||||
self.sha.busy().read().bits() != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn digest_length(&self) -> usize {
|
|
||||||
match self.mode {
|
|
||||||
ShaMode::SHA1 => 20,
|
|
||||||
#[cfg(not(esp32))]
|
|
||||||
ShaMode::SHA224 => 28,
|
|
||||||
ShaMode::SHA256 => 32,
|
|
||||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
|
||||||
ShaMode::SHA384 => 48,
|
|
||||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
|
||||||
ShaMode::SHA512 => 64,
|
|
||||||
#[cfg(any(esp32s2, esp32s3))]
|
|
||||||
ShaMode::SHA512_224 => 28,
|
|
||||||
#[cfg(any(esp32s2, esp32s3))]
|
|
||||||
ShaMode::SHA512_256 => 32,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_data(&mut self) -> nb::Result<(), Infallible> {
|
fn flush_data(&mut self) -> nb::Result<(), Infallible> {
|
||||||
@ -277,14 +198,31 @@ impl<'d, DM: crate::Mode> Sha<'d, DM> {
|
|||||||
return Err(nb::Error::WouldBlock);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
let chunk_len = self.chunk_length();
|
// Safety: This is safe because the buffer is processed after being flushed to
|
||||||
|
// memory.
|
||||||
|
let sha = unsafe { crate::peripherals::SHA::steal() };
|
||||||
|
|
||||||
let flushed = self.alignment_helper.flush_to(
|
let chunk_len = self.chunk_length();
|
||||||
|
let ctx = self.deref_mut();
|
||||||
|
|
||||||
|
// Flush aligned buffer in memory before flushing alignment_helper
|
||||||
|
unsafe {
|
||||||
|
core::ptr::copy_nonoverlapping(
|
||||||
|
ctx.buffer.as_ptr(),
|
||||||
|
#[cfg(esp32)]
|
||||||
|
sha.text(0).as_ptr(),
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
sha.m_mem(0).as_ptr(),
|
||||||
|
(ctx.cursor % chunk_len) / ctx.alignment_helper.align_size(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let flushed = ctx.alignment_helper.flush_to(
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
self.sha.text(0).as_ptr(),
|
sha.text(0).as_ptr(),
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
self.sha.m_mem(0).as_ptr(),
|
sha.m_mem(0).as_ptr(),
|
||||||
(self.cursor % chunk_len) / self.alignment_helper.align_size(),
|
(ctx.cursor % chunk_len) / ctx.alignment_helper.align_size(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.cursor = self.cursor.wrapping_add(flushed);
|
self.cursor = self.cursor.wrapping_add(flushed);
|
||||||
@ -303,26 +241,39 @@ impl<'d, DM: crate::Mode> Sha<'d, DM> {
|
|||||||
|
|
||||||
let chunk_len = self.chunk_length();
|
let chunk_len = self.chunk_length();
|
||||||
|
|
||||||
let (remaining, bound_reached) = self.alignment_helper.aligned_volatile_copy(
|
let ctx = self.deref_mut();
|
||||||
#[cfg(esp32)]
|
// Buffer the incoming bytes into u32 aligned words.
|
||||||
self.sha.text(0).as_ptr(),
|
let (remaining, bound_reached) = ctx.alignment_helper.aligned_volatile_copy(
|
||||||
#[cfg(not(esp32))]
|
ctx.buffer.as_mut_ptr(),
|
||||||
self.sha.m_mem(0).as_ptr(),
|
|
||||||
incoming,
|
incoming,
|
||||||
chunk_len / self.alignment_helper.align_size(),
|
chunk_len / ctx.alignment_helper.align_size(),
|
||||||
mod_cursor / self.alignment_helper.align_size(),
|
mod_cursor / ctx.alignment_helper.align_size(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.cursor = self.cursor.wrapping_add(incoming.len() - remaining.len());
|
self.cursor = self.cursor.wrapping_add(incoming.len() - remaining.len());
|
||||||
|
|
||||||
|
// If bound reached we write the buffer to memory and process it.
|
||||||
if bound_reached {
|
if bound_reached {
|
||||||
|
// Safety: This is safe because the bound has been reached and the buffer will
|
||||||
|
// be fully processed then saved.
|
||||||
|
unsafe {
|
||||||
|
let sha = crate::peripherals::SHA::steal();
|
||||||
|
core::ptr::copy_nonoverlapping(
|
||||||
|
self.buffer.as_ptr(),
|
||||||
|
#[cfg(esp32)]
|
||||||
|
sha.text(0).as_ptr(),
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
sha.m_mem(0).as_ptr(),
|
||||||
|
32,
|
||||||
|
);
|
||||||
|
}
|
||||||
self.process_buffer();
|
self.process_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(remaining)
|
Ok(remaining)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update<'a>(&mut self, buffer: &'a [u8]) -> nb::Result<&'a [u8], Infallible> {
|
fn update<'a>(&mut self, buffer: &'a [u8]) -> nb::Result<&'a [u8], Infallible> {
|
||||||
if self.is_busy() {
|
if self.is_busy() {
|
||||||
return Err(nb::Error::WouldBlock);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
@ -340,13 +291,15 @@ impl<'d, DM: crate::Mode> Sha<'d, DM> {
|
|||||||
//
|
//
|
||||||
// Typically output is expected to be the size of digest_length(), but smaller
|
// Typically output is expected to be the size of digest_length(), but smaller
|
||||||
// inputs can be given to get a "short hash"
|
// inputs can be given to get a "short hash"
|
||||||
pub fn finish(&mut self, output: &mut [u8]) -> nb::Result<(), Infallible> {
|
fn finish(&mut self, output: &mut [u8]) -> nb::Result<(), Infallible> {
|
||||||
// The main purpose of this function is to dynamically generate padding for the
|
// The main purpose of this function is to dynamically generate padding for the
|
||||||
// input. Padding: Append "1" bit, Pad zeros until 512/1024 filled
|
// input. Padding: Append "1" bit, Pad zeros until 512/1024 filled
|
||||||
// then set the message length in the LSB (overwriting the padding)
|
// then set the message length in the LSB (overwriting the padding)
|
||||||
// If not enough free space for length+1, add length at end of a new zero'd
|
// If not enough free space for length+1, add length at end of a new zero'd
|
||||||
// block
|
// block
|
||||||
|
|
||||||
|
let sha = unsafe { crate::peripherals::SHA::steal() };
|
||||||
|
|
||||||
if self.is_busy() {
|
if self.is_busy() {
|
||||||
return Err(nb::Error::WouldBlock);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
@ -355,23 +308,24 @@ impl<'d, DM: crate::Mode> Sha<'d, DM> {
|
|||||||
|
|
||||||
// Store message length for padding
|
// Store message length for padding
|
||||||
let length = (self.cursor as u64 * 8).to_be_bytes();
|
let length = (self.cursor as u64 * 8).to_be_bytes();
|
||||||
nb::block!(self.update(&[0x80]))?; // Append "1" bit
|
nb::block!(Sha::update(self, &[0x80]))?; // Append "1" bit
|
||||||
nb::block!(self.flush_data())?; // Flush partial data, ensures aligned cursor
|
nb::block!(self.flush_data())?; // Flush partial data, ensures aligned cursor
|
||||||
debug_assert!(self.cursor % 4 == 0);
|
debug_assert!(self.cursor % 4 == 0);
|
||||||
|
|
||||||
let mod_cursor = self.cursor % chunk_len;
|
let mod_cursor = self.cursor % chunk_len;
|
||||||
if (chunk_len - mod_cursor) < core::mem::size_of::<u64>() {
|
if (chunk_len - mod_cursor) < chunk_len / 8 {
|
||||||
// Zero out remaining data if buffer is almost full (>=448/896), and process
|
// Zero out remaining data if buffer is almost full (>=448/896), and process
|
||||||
// buffer
|
// buffer
|
||||||
let pad_len = chunk_len - mod_cursor;
|
let pad_len = chunk_len - mod_cursor;
|
||||||
self.alignment_helper.volatile_write_bytes(
|
let ctx = self.deref_mut();
|
||||||
|
ctx.alignment_helper.volatile_write_bytes(
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
self.sha.text(0).as_ptr(),
|
sha.text(0).as_ptr(),
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
self.sha.m_mem(0).as_ptr(),
|
sha.m_mem(0).as_ptr(),
|
||||||
0_u8,
|
0_u8,
|
||||||
pad_len / self.alignment_helper.align_size(),
|
pad_len / ctx.alignment_helper.align_size(),
|
||||||
mod_cursor / self.alignment_helper.align_size(),
|
mod_cursor / ctx.alignment_helper.align_size(),
|
||||||
);
|
);
|
||||||
self.process_buffer();
|
self.process_buffer();
|
||||||
self.cursor = self.cursor.wrapping_add(pad_len);
|
self.cursor = self.cursor.wrapping_add(pad_len);
|
||||||
@ -385,24 +339,25 @@ impl<'d, DM: crate::Mode> Sha<'d, DM> {
|
|||||||
let mod_cursor = self.cursor % chunk_len; // Should be zero if branched above
|
let mod_cursor = self.cursor % chunk_len; // Should be zero if branched above
|
||||||
let pad_len = chunk_len - mod_cursor - core::mem::size_of::<u64>();
|
let pad_len = chunk_len - mod_cursor - core::mem::size_of::<u64>();
|
||||||
|
|
||||||
self.alignment_helper.volatile_write_bytes(
|
let ctx = self.deref_mut();
|
||||||
|
ctx.alignment_helper.volatile_write_bytes(
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
self.sha.text(0).as_ptr(),
|
sha.text(0).as_ptr(),
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
self.sha.m_mem(0).as_ptr(),
|
sha.m_mem(0).as_ptr(),
|
||||||
0_u8,
|
0_u8,
|
||||||
pad_len / self.alignment_helper.align_size(),
|
pad_len / ctx.alignment_helper.align_size(),
|
||||||
mod_cursor / self.alignment_helper.align_size(),
|
mod_cursor / ctx.alignment_helper.align_size(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.alignment_helper.aligned_volatile_copy(
|
ctx.alignment_helper.aligned_volatile_copy(
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
self.sha.text(0).as_ptr(),
|
sha.text(0).as_ptr(),
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
self.sha.m_mem(0).as_ptr(),
|
sha.m_mem(0).as_ptr(),
|
||||||
&length,
|
&length,
|
||||||
chunk_len / self.alignment_helper.align_size(),
|
chunk_len / ctx.alignment_helper.align_size(),
|
||||||
(chunk_len - core::mem::size_of::<u64>()) / self.alignment_helper.align_size(),
|
(chunk_len - core::mem::size_of::<u64>()) / ctx.alignment_helper.align_size(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.process_buffer();
|
self.process_buffer();
|
||||||
@ -412,22 +367,16 @@ impl<'d, DM: crate::Mode> Sha<'d, DM> {
|
|||||||
// ESP32 requires additional load to retrieve output
|
// ESP32 requires additional load to retrieve output
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
{
|
{
|
||||||
match self.mode {
|
self.load_reg();
|
||||||
ShaMode::SHA1 => unsafe { self.sha.sha1_load().write(|w| w.bits(1)) },
|
|
||||||
ShaMode::SHA256 => unsafe { self.sha.sha256_load().write(|w| w.bits(1)) },
|
|
||||||
ShaMode::SHA384 => unsafe { self.sha.sha384_load().write(|w| w.bits(1)) },
|
|
||||||
ShaMode::SHA512 => unsafe { self.sha.sha512_load().write(|w| w.bits(1)) },
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spin wait for result, 8-20 clock cycles according to manual
|
// Spin wait for result, 8-20 clock cycles according to manual
|
||||||
while self.is_busy() {}
|
while self.is_busy() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.alignment_helper.volatile_read_regset(
|
self.alignment_helper.volatile_read_regset(
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
self.sha.text(0).as_ptr(),
|
sha.text(0).as_ptr(),
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
self.sha.h_mem(0).as_ptr(),
|
sha.h_mem(0).as_ptr(),
|
||||||
output,
|
output,
|
||||||
core::cmp::min(output.len(), 32) / self.alignment_helper.align_size(),
|
core::cmp::min(output.len(), 32) / self.alignment_helper.align_size(),
|
||||||
);
|
);
|
||||||
@ -439,3 +388,161 @@ impl<'d, DM: crate::Mode> Sha<'d, DM> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This macro implements the Sha<'a, DM> trait for a specified Sha algorithm
|
||||||
|
/// and a set of parameters
|
||||||
|
macro_rules! impl_sha {
|
||||||
|
($name: ident, $mode_bits: tt, $digest_length: tt, $chunk_length: tt) => {
|
||||||
|
pub struct $name<DM: crate::Mode>(Context<DM>);
|
||||||
|
|
||||||
|
impl $name<crate::Blocking> {
|
||||||
|
/// Create a new instance in [crate::Blocking] mode.
|
||||||
|
#[cfg_attr(not(esp32), doc = "Optionally an interrupt handler can be bound.")]
|
||||||
|
pub fn new() -> $name<crate::Blocking> {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Automatically implement Deref + DerefMut to get access to inner context
|
||||||
|
impl<DM: crate::Mode> core::ops::Deref for $name<DM> {
|
||||||
|
type Target = Context<DM>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DM: crate::Mode> core::ops::DerefMut for $name<DM> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement Default to create hasher out of thin air
|
||||||
|
impl core::default::Default for $name<crate::Blocking> {
|
||||||
|
fn default() -> Self {
|
||||||
|
PeripheralClockControl::reset(crate::system::Peripheral::Sha);
|
||||||
|
PeripheralClockControl::enable(crate::system::Peripheral::Sha);
|
||||||
|
|
||||||
|
Self(Context {
|
||||||
|
cursor: 0,
|
||||||
|
first_run: true,
|
||||||
|
finished: false,
|
||||||
|
alignment_helper: AlignmentHelper::default(),
|
||||||
|
buffer: [0u32; 32],
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
saved_digest: None,
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::sha::Sha<crate::Blocking> for $name<crate::Blocking> {
|
||||||
|
const ALGORITHM: &'static str = stringify!($name);
|
||||||
|
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
fn mode_as_bits() -> u8 {
|
||||||
|
$mode_bits
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chunk_length(&self) -> usize {
|
||||||
|
$chunk_length
|
||||||
|
}
|
||||||
|
|
||||||
|
fn digest_length(&self) -> usize {
|
||||||
|
$digest_length
|
||||||
|
}
|
||||||
|
|
||||||
|
// ESP32 uses different registers for its operation
|
||||||
|
#[cfg(esp32)]
|
||||||
|
fn load_reg(&self) {
|
||||||
|
// Safety: This is safe because digest state is restored and saved between
|
||||||
|
// operations.
|
||||||
|
let sha = unsafe { crate::peripherals::SHA::steal() };
|
||||||
|
paste::paste! {
|
||||||
|
unsafe { sha.[< $name:lower _load >]().write(|w| w.bits(1)) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(esp32)]
|
||||||
|
fn is_busy(&self) -> bool {
|
||||||
|
let sha = unsafe { crate::peripherals::SHA::steal() };
|
||||||
|
paste::paste! {
|
||||||
|
sha.[< $name:lower _busy >]().read().[< $name:lower _busy >]().bit_is_set()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(esp32)]
|
||||||
|
fn process_buffer(&mut self) {
|
||||||
|
let sha = unsafe { crate::peripherals::SHA::steal() };
|
||||||
|
paste::paste! {
|
||||||
|
if self.first_run {
|
||||||
|
sha.[< $name:lower _start >]().write(|w| unsafe { w.bits(1) });
|
||||||
|
self.first_run = false;
|
||||||
|
} else {
|
||||||
|
sha.[< $name:lower _continue >]().write(|w| unsafe { w.bits(1) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// implement digest traits if digest feature is present.
|
||||||
|
/// Note: digest has a blanket trait implementation for [digest::Digest] for any
|
||||||
|
/// element that implements FixedOutput + Default + Update + HashMarker
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
impl<DM: crate::Mode> digest::HashMarker for $name<DM> {}
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
impl<DM: crate::Mode> digest::OutputSizeUser for $name<DM> {
|
||||||
|
// We use paste to append `U` to the digest size to match a const defined in
|
||||||
|
// digest
|
||||||
|
paste::paste! {
|
||||||
|
type OutputSize = digest::consts::[< U $digest_length >];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
impl digest::Update for $name<crate::Blocking> {
|
||||||
|
fn update(&mut self, data: &[u8]) {
|
||||||
|
let mut remaining = data.as_ref();
|
||||||
|
while remaining.len() > 0 {
|
||||||
|
remaining = nb::block!(Sha::update(self, remaining)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "digest")]
|
||||||
|
impl digest::FixedOutput for $name<crate::Blocking> {
|
||||||
|
fn finalize_into(mut self, out: &mut digest::Output<Self>) {
|
||||||
|
nb::block!(self.finish(out)).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// All the hash algorithms introduced in FIPS PUB 180-4 Spec.
|
||||||
|
// – SHA-1
|
||||||
|
// – SHA-224
|
||||||
|
// – SHA-256
|
||||||
|
// – SHA-384
|
||||||
|
// – SHA-512
|
||||||
|
// – SHA-512/224
|
||||||
|
// – SHA-512/256
|
||||||
|
// – SHA-512/t (not implemented yet)
|
||||||
|
// Two working modes
|
||||||
|
// – Typical SHA
|
||||||
|
// – DMA-SHA (not implemented yet)
|
||||||
|
//
|
||||||
|
// TODO: Allow/Implement SHA512_(u16)
|
||||||
|
impl_sha!(Sha1, 0, 20, 64);
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
impl_sha!(Sha224, 1, 28, 64);
|
||||||
|
impl_sha!(Sha256, 2, 32, 64);
|
||||||
|
#[cfg(any(esp32, esp32s2, esp32s3))]
|
||||||
|
impl_sha!(Sha384, 3, 48, 128);
|
||||||
|
#[cfg(any(esp32, esp32s2, esp32s3))]
|
||||||
|
impl_sha!(Sha512, 4, 64, 128);
|
||||||
|
#[cfg(any(esp32s2, esp32s3))]
|
||||||
|
impl_sha!(Sha512_224, 5, 28, 128);
|
||||||
|
#[cfg(any(esp32s2, esp32s3))]
|
||||||
|
impl_sha!(Sha512_256, 6, 32, 128);
|
||||||
|
|||||||
@ -151,13 +151,14 @@ embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", features = [
|
|||||||
embedded-hal-async = { version = "1.0.0", optional = true }
|
embedded-hal-async = { version = "1.0.0", optional = true }
|
||||||
embedded-hal-nb = { version = "1.0.0", optional = true }
|
embedded-hal-nb = { version = "1.0.0", optional = true }
|
||||||
esp-backtrace = { path = "../esp-backtrace", default-features = false, features = ["exception-handler", "panic-handler", "defmt", "semihosting"] }
|
esp-backtrace = { path = "../esp-backtrace", default-features = false, features = ["exception-handler", "panic-handler", "defmt", "semihosting"] }
|
||||||
esp-hal = { path = "../esp-hal", features = ["defmt", "embedded-hal", "embedded-hal-02"], optional = true }
|
esp-hal = { path = "../esp-hal", features = ["defmt", "digest", "embedded-hal", "embedded-hal-02"], optional = true }
|
||||||
esp-hal-embassy = { path = "../esp-hal-embassy", optional = true }
|
esp-hal-embassy = { path = "../esp-hal-embassy", optional = true }
|
||||||
portable-atomic = "1.6.0"
|
portable-atomic = "1.6.0"
|
||||||
static_cell = { version = "2.1.0", features = ["nightly"] }
|
static_cell = { version = "2.1.0", features = ["nightly"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
crypto-bigint = { version = "0.5.5", default-features = false }
|
crypto-bigint = { version = "0.5.5", default-features = false }
|
||||||
|
digest = { version = "0.10.7", default-features = false }
|
||||||
elliptic-curve = { version = "0.13.8", default-features = false, features = ["sec1"] }
|
elliptic-curve = { version = "0.13.8", default-features = false, features = ["sec1"] }
|
||||||
embassy-executor = { version = "0.6.0", default-features = false }
|
embassy-executor = { version = "0.6.0", default-features = false }
|
||||||
# Add the `embedded-test/defmt` feature for more verbose testing
|
# Add the `embedded-test/defmt` feature for more verbose testing
|
||||||
@ -166,6 +167,8 @@ hex-literal = "0.4.1"
|
|||||||
nb = "1.1.0"
|
nb = "1.1.0"
|
||||||
p192 = { version = "0.13.0", default-features = false, features = ["arithmetic"] }
|
p192 = { version = "0.13.0", default-features = false, features = ["arithmetic"] }
|
||||||
p256 = { version = "0.13.2", default-features = false, features = ["arithmetic"] }
|
p256 = { version = "0.13.2", default-features = false, features = ["arithmetic"] }
|
||||||
|
sha1 = { version = "0.10.6", default-features = false }
|
||||||
|
sha2 = { version = "0.10.8", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["async", "embassy"]
|
default = ["async", "embassy"]
|
||||||
|
|||||||
@ -5,13 +5,39 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
use digest::Digest;
|
||||||
use esp_hal::{
|
use esp_hal::{
|
||||||
|
clock::ClockControl,
|
||||||
peripherals::Peripherals,
|
peripherals::Peripherals,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
sha::{Sha, ShaMode},
|
rng::Rng,
|
||||||
|
sha::{Sha, Sha1, Sha256},
|
||||||
|
system::SystemControl,
|
||||||
};
|
};
|
||||||
use hil_test as _;
|
use hil_test as _;
|
||||||
use nb::block;
|
use nb::block;
|
||||||
|
use sha1;
|
||||||
|
use sha2;
|
||||||
|
|
||||||
|
/// Dummy data used to feed the hasher.
|
||||||
|
static CHAR_ARRAY: [u8; 200] = [b'a'; 200];
|
||||||
|
|
||||||
|
/// Dummy random data used to feed the Sha1 hasher
|
||||||
|
static mut SHA1_RANDOM_ARRAY: [u8; 256] = [0u8; 256];
|
||||||
|
|
||||||
|
/// Dummy random data used to feed the Sha224 hasher
|
||||||
|
static mut SHA224_RANDOM_ARRAY: [u8; 256] = [0u8; 256];
|
||||||
|
|
||||||
|
/// Dummy random data used to feed the Sha256 hasher
|
||||||
|
static mut SHA256_RANDOM_ARRAY: [u8; 256] = [0u8; 256];
|
||||||
|
|
||||||
|
/// Dummy random data used to feed the Sha384 hasher
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
static mut SHA384_RANDOM_ARRAY: [u8; 256] = [0u8; 256];
|
||||||
|
|
||||||
|
/// Dummy random data used to feed the Sha512 hasher
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
static mut SHA512_RANDOM_ARRAY: [u8; 256] = [0u8; 256];
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[embedded_test::tests]
|
#[embedded_test::tests]
|
||||||
@ -25,8 +51,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sha_1() {
|
fn test_sha_1() {
|
||||||
let peripherals = Peripherals::take();
|
let mut sha = Sha1::new();
|
||||||
let mut sha = Sha::new(peripherals.SHA, ShaMode::SHA1);
|
|
||||||
|
|
||||||
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
let mut remaining = source_data;
|
let mut remaining = source_data;
|
||||||
@ -38,7 +63,43 @@ mod tests {
|
|||||||
let mut output = [0u8; 32];
|
let mut output = [0u8; 32];
|
||||||
|
|
||||||
while remaining.len() > 0 {
|
while remaining.len() > 0 {
|
||||||
remaining = block!(sha.update(remaining)).unwrap();
|
remaining = block!(Sha::update(&mut sha, remaining)).unwrap();
|
||||||
|
}
|
||||||
|
block!(sha.finish(output.as_mut_slice())).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(expected_output, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sha_1_digest() {
|
||||||
|
let mut sha: Sha1<esp_hal::Blocking> = digest::Digest::new();
|
||||||
|
|
||||||
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
|
let expected_output = [
|
||||||
|
0x57, 0xf5, 0x3e, 0xd5, 0x59, 0x85, 0x24, 0x49, 0x3e, 0xc5, 0x76, 0x77, 0xa, 0xaf,
|
||||||
|
0x3b, 0xb1, 0x0, 0x63, 0xe3, 0xce,
|
||||||
|
];
|
||||||
|
digest::Digest::update(&mut sha, source_data);
|
||||||
|
let output: [u8; 20] = digest::Digest::finalize(sha).into();
|
||||||
|
|
||||||
|
assert_eq!(expected_output, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
fn test_sha_224() {
|
||||||
|
let mut sha = esp_hal::sha::Sha224::new();
|
||||||
|
|
||||||
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
|
let mut remaining = source_data;
|
||||||
|
let expected_output = [
|
||||||
|
0x3b, 0x29, 0x33, 0xca, 0xfa, 0x6, 0xc0, 0x29, 0x68, 0x10, 0xa1, 0x3e, 0x54, 0x5f,
|
||||||
|
0x25, 0x40, 0xa4, 0x35, 0x17, 0x3, 0x6d, 0xa2, 0xb, 0xeb, 0x8c, 0xbe, 0x79, 0x3b,
|
||||||
|
];
|
||||||
|
let mut output = [0u8; 28];
|
||||||
|
|
||||||
|
while remaining.len() > 0 {
|
||||||
|
remaining = block!(Sha::update(&mut sha, remaining)).unwrap();
|
||||||
}
|
}
|
||||||
block!(sha.finish(output.as_mut_slice())).unwrap();
|
block!(sha.finish(output.as_mut_slice())).unwrap();
|
||||||
|
|
||||||
@ -47,31 +108,24 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "esp32"))]
|
#[cfg(not(feature = "esp32"))]
|
||||||
fn test_sha_224() {
|
fn test_sha_224_digest() {
|
||||||
let peripherals = Peripherals::take();
|
let mut sha: esp_hal::sha::Sha224<esp_hal::Blocking> = digest::Digest::new();
|
||||||
let mut sha = Sha::new(peripherals.SHA, ShaMode::SHA224);
|
|
||||||
|
|
||||||
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
let mut remaining = source_data;
|
|
||||||
let expected_output = [
|
let expected_output = [
|
||||||
0x3b, 0x29, 0x33, 0xca, 0xfa, 0x6, 0xc0, 0x29, 0x68, 0x10, 0xa1, 0x3e, 0x54, 0x5f,
|
0x3b, 0x29, 0x33, 0xca, 0xfa, 0x6, 0xc0, 0x29, 0x68, 0x10, 0xa1, 0x3e, 0x54, 0x5f,
|
||||||
0x25, 0x40, 0xa4, 0x35, 0x17, 0x3, 0x6d, 0xa2, 0xb, 0xeb, 0x8c, 0xbe, 0x79, 0x3b, 0xb6,
|
0x25, 0x40, 0xa4, 0x35, 0x17, 0x3, 0x6d, 0xa2, 0xb, 0xeb, 0x8c, 0xbe, 0x79, 0x3b,
|
||||||
0xa8, 0x8c, 0xff,
|
|
||||||
];
|
];
|
||||||
let mut output = [0u8; 32];
|
|
||||||
|
|
||||||
while remaining.len() > 0 {
|
digest::Digest::update(&mut sha, source_data);
|
||||||
remaining = block!(sha.update(remaining)).unwrap();
|
let output: [u8; 28] = digest::Digest::finalize(sha).into();
|
||||||
}
|
|
||||||
block!(sha.finish(output.as_mut_slice())).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(expected_output, output);
|
assert_eq!(expected_output, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sha_256() {
|
fn test_sha_256() {
|
||||||
let peripherals = Peripherals::take();
|
let mut sha = Sha256::new();
|
||||||
let mut sha = Sha::new(peripherals.SHA, ShaMode::SHA256);
|
|
||||||
|
|
||||||
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
let mut remaining = source_data;
|
let mut remaining = source_data;
|
||||||
@ -83,18 +137,34 @@ mod tests {
|
|||||||
let mut output = [0u8; 32];
|
let mut output = [0u8; 32];
|
||||||
|
|
||||||
while remaining.len() > 0 {
|
while remaining.len() > 0 {
|
||||||
remaining = block!(sha.update(remaining)).unwrap();
|
remaining = block!(Sha::update(&mut sha, remaining)).unwrap();
|
||||||
}
|
}
|
||||||
block!(sha.finish(output.as_mut_slice())).unwrap();
|
block!(sha.finish(output.as_mut_slice())).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_output, output);
|
assert_eq!(expected_output, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sha_256_digest() {
|
||||||
|
let mut sha: Sha256<esp_hal::Blocking> = digest::Digest::new();
|
||||||
|
|
||||||
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
|
let expected_output = [
|
||||||
|
0x1e, 0xbb, 0xda, 0xb3, 0x35, 0xe0, 0x54, 0x01, 0x5f, 0x0f, 0xc1, 0x7f, 0x62, 0x77,
|
||||||
|
0x06, 0x09, 0x72, 0x3d, 0x92, 0xc6, 0x40, 0xb6, 0x5b, 0xa9, 0x97, 0x4d, 0x66, 0x6c,
|
||||||
|
0x36, 0x4a, 0x3a, 0x63,
|
||||||
|
];
|
||||||
|
|
||||||
|
digest::Digest::update(&mut sha, source_data);
|
||||||
|
let output: [u8; 32] = digest::Digest::finalize(sha).into();
|
||||||
|
|
||||||
|
assert_eq!(expected_output, output);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
fn test_sha_384() {
|
fn test_sha_384() {
|
||||||
let peripherals = Peripherals::take();
|
let mut sha = esp_hal::sha::Sha384::new();
|
||||||
let mut sha = Sha::new(peripherals.SHA, ShaMode::SHA384);
|
|
||||||
|
|
||||||
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
let mut remaining = source_data;
|
let mut remaining = source_data;
|
||||||
@ -106,18 +176,36 @@ mod tests {
|
|||||||
let mut output = [0u8; 32];
|
let mut output = [0u8; 32];
|
||||||
|
|
||||||
while remaining.len() > 0 {
|
while remaining.len() > 0 {
|
||||||
remaining = block!(sha.update(remaining)).unwrap();
|
remaining = block!(Sha::update(&mut sha, remaining)).unwrap();
|
||||||
}
|
}
|
||||||
block!(sha.finish(output.as_mut_slice())).unwrap();
|
block!(sha.finish(output.as_mut_slice())).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_output, output);
|
assert_eq!(expected_output, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
fn test_sha_384_digest() {
|
||||||
|
let mut sha: esp_hal::sha::Sha384<esp_hal::Blocking> = digest::Digest::new();
|
||||||
|
|
||||||
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
|
let expected_output = [
|
||||||
|
0x8a, 0x1d, 0xe0, 0x7f, 0xa9, 0xc, 0x4c, 0xbb, 0xac, 0xe4, 0x62, 0xbd, 0xd9, 0x2f,
|
||||||
|
0x90, 0x88, 0x61, 0x69, 0x40, 0xc0, 0x55, 0x6b, 0x80, 0x6, 0xaa, 0xfc, 0xd4, 0xff,
|
||||||
|
0xc1, 0x8, 0xe9, 0xb2, 0xcd, 0xd8, 0xa9, 0x77, 0x36, 0x98, 0x2e, 0x36, 0x3f, 0x69,
|
||||||
|
0xa0, 0x7a, 0x20, 0xfa, 0x1c, 0xeb,
|
||||||
|
];
|
||||||
|
|
||||||
|
digest::Digest::update(&mut sha, source_data);
|
||||||
|
let output: [u8; 48] = digest::Digest::finalize(sha).into();
|
||||||
|
|
||||||
|
assert_eq!(expected_output, output);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
fn test_sha_512() {
|
fn test_sha_512() {
|
||||||
let peripherals = Peripherals::take();
|
let mut sha = esp_hal::sha::Sha512::new();
|
||||||
let mut sha = Sha::new(peripherals.SHA, ShaMode::SHA512);
|
|
||||||
|
|
||||||
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
let mut remaining = source_data;
|
let mut remaining = source_data;
|
||||||
@ -129,18 +217,37 @@ mod tests {
|
|||||||
let mut output = [0u8; 32];
|
let mut output = [0u8; 32];
|
||||||
|
|
||||||
while remaining.len() > 0 {
|
while remaining.len() > 0 {
|
||||||
remaining = block!(sha.update(remaining)).unwrap();
|
remaining = block!(Sha::update(&mut sha, remaining)).unwrap();
|
||||||
}
|
}
|
||||||
block!(sha.finish(output.as_mut_slice())).unwrap();
|
block!(sha.finish(output.as_mut_slice())).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_output, output);
|
assert_eq!(expected_output, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
fn test_sha_512_digest() {
|
||||||
|
let mut sha: esp_hal::sha::Sha512<esp_hal::Blocking> = digest::Digest::new();
|
||||||
|
|
||||||
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
|
let expected_output = [
|
||||||
|
0xee, 0x8d, 0x0e, 0x15, 0xde, 0xdc, 0xd8, 0xc8, 0x86, 0xa2, 0xef, 0xb1, 0xac, 0x6a,
|
||||||
|
0x49, 0xcf, 0xd8, 0x3f, 0x67, 0x65, 0x64, 0xb3, 0x00, 0xce, 0x48, 0x51, 0x5e, 0xce,
|
||||||
|
0x5f, 0x4b, 0xee, 0x10, 0xe1, 0x1d, 0x89, 0xc2, 0x1c, 0x21, 0x81, 0x53, 0xc3, 0xb2,
|
||||||
|
0x31, 0xab, 0x77, 0xca, 0xed, 0xc9, 0x6c, 0x24, 0xd7, 0xe5, 0x9a, 0x94, 0x86, 0x80,
|
||||||
|
0xe1, 0x51, 0x00, 0x1a, 0xe1, 0x8c, 0xec, 0x80,
|
||||||
|
];
|
||||||
|
|
||||||
|
digest::Digest::update(&mut sha, source_data);
|
||||||
|
let output: [u8; 64] = digest::Digest::finalize(sha).into();
|
||||||
|
|
||||||
|
assert_eq!(expected_output, output);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
||||||
fn test_sha_512_224() {
|
fn test_sha_512_224() {
|
||||||
let peripherals = Peripherals::take();
|
let mut sha = esp_hal::sha::Sha512_224::new();
|
||||||
let mut sha = Sha::new(peripherals.SHA, ShaMode::SHA512_224);
|
|
||||||
|
|
||||||
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
let mut remaining = source_data;
|
let mut remaining = source_data;
|
||||||
@ -152,18 +259,34 @@ mod tests {
|
|||||||
let mut output = [0u8; 32];
|
let mut output = [0u8; 32];
|
||||||
|
|
||||||
while remaining.len() > 0 {
|
while remaining.len() > 0 {
|
||||||
remaining = block!(sha.update(remaining)).unwrap();
|
remaining = block!(Sha::update(&mut sha, remaining)).unwrap();
|
||||||
}
|
}
|
||||||
block!(sha.finish(output.as_mut_slice())).unwrap();
|
block!(sha.finish(output.as_mut_slice())).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_output, output);
|
assert_eq!(expected_output, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
fn test_sha_512_224_digest() {
|
||||||
|
let mut sha: esp_hal::sha::Sha512_224<esp_hal::Blocking> = digest::Digest::new();
|
||||||
|
|
||||||
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
|
let expected_output = [
|
||||||
|
0x19, 0xf2, 0xb3, 0x88, 0x22, 0x86, 0x94, 0x38, 0xee, 0x24, 0xc1, 0xc3, 0xb0, 0xb1,
|
||||||
|
0x21, 0x6a, 0xf4, 0x81, 0x14, 0x8f, 0x4, 0x34, 0xfd, 0xd7, 0x54, 0x3, 0x2b, 0x88,
|
||||||
|
];
|
||||||
|
|
||||||
|
digest::Digest::update(&mut sha, source_data);
|
||||||
|
let output: [u8; 28] = digest::Digest::finalize(sha).into();
|
||||||
|
|
||||||
|
assert_eq!(expected_output, output);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
||||||
fn test_sha_512_256() {
|
fn test_sha_512_256() {
|
||||||
let peripherals = Peripherals::take();
|
let mut sha = esp_hal::sha::Sha512_256::new();
|
||||||
let mut sha = Sha::new(peripherals.SHA, ShaMode::SHA512_256);
|
|
||||||
|
|
||||||
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
let mut remaining = source_data;
|
let mut remaining = source_data;
|
||||||
@ -175,10 +298,373 @@ mod tests {
|
|||||||
let mut output = [0u8; 32];
|
let mut output = [0u8; 32];
|
||||||
|
|
||||||
while remaining.len() > 0 {
|
while remaining.len() > 0 {
|
||||||
remaining = block!(sha.update(remaining)).unwrap();
|
remaining = block!(Sha::update(&mut sha, remaining)).unwrap();
|
||||||
}
|
}
|
||||||
block!(sha.finish(output.as_mut_slice())).unwrap();
|
block!(sha.finish(output.as_mut_slice())).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_output, output);
|
assert_eq!(expected_output, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
fn test_sha_512_256_digest() {
|
||||||
|
let mut sha: esp_hal::sha::Sha512_256<esp_hal::Blocking> = digest::Digest::new();
|
||||||
|
|
||||||
|
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
|
||||||
|
let expected_output = [
|
||||||
|
0xb7, 0x49, 0x4e, 0xe1, 0xdb, 0xcd, 0xe5, 0x47, 0x5a, 0x61, 0x25, 0xac, 0x27, 0xc2,
|
||||||
|
0x1b, 0x53, 0xcd, 0x6b, 0x16, 0x33, 0xb4, 0x94, 0xac, 0xa4, 0x2a, 0xe6, 0x99, 0x2f,
|
||||||
|
0xe7, 0xd, 0x83, 0x19,
|
||||||
|
];
|
||||||
|
|
||||||
|
digest::Digest::update(&mut sha, source_data);
|
||||||
|
let output: [u8; 32] = digest::Digest::finalize(sha).into();
|
||||||
|
|
||||||
|
assert_eq!(expected_output, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A test that runs a hashing on a digest of every size between 1 and 256
|
||||||
|
/// inclusively.
|
||||||
|
#[test]
|
||||||
|
fn test_digest_of_size_1_to_200() {
|
||||||
|
for i in 1..=200 {
|
||||||
|
test_for_size::<esp_hal::sha::Sha1<esp_hal::Blocking>, 20>(i);
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
test_for_size::<esp_hal::sha::Sha224<esp_hal::Blocking>, 28>(i);
|
||||||
|
test_for_size::<esp_hal::sha::Sha256<esp_hal::Blocking>, 32>(i);
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
test_for_size::<esp_hal::sha::Sha384<esp_hal::Blocking>, 48>(i);
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
test_for_size::<esp_hal::sha::Sha512<esp_hal::Blocking>, 64>(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A rolling test that loops between hasher for every step to test
|
||||||
|
/// interleaving. This specifically test the Sha trait implementation
|
||||||
|
#[test]
|
||||||
|
fn test_sha_rolling() {
|
||||||
|
let peripherals = Peripherals::take();
|
||||||
|
let system = SystemControl::new(peripherals.SYSTEM);
|
||||||
|
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||||
|
|
||||||
|
let mut rng = Rng::new(peripherals.RNG);
|
||||||
|
|
||||||
|
// Fill source data with random data
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
|
for slice in unsafe {
|
||||||
|
[
|
||||||
|
addr_of_mut!(SHA1_RANDOM_ARRAY),
|
||||||
|
addr_of_mut!(SHA224_RANDOM_ARRAY),
|
||||||
|
addr_of_mut!(SHA256_RANDOM_ARRAY),
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
addr_of_mut!(SHA384_RANDOM_ARRAY),
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
addr_of_mut!(SHA512_RANDOM_ARRAY),
|
||||||
|
]
|
||||||
|
} {
|
||||||
|
rng.read(unsafe { &mut *slice });
|
||||||
|
}
|
||||||
|
|
||||||
|
for size in [1, 64, 128, 256] {
|
||||||
|
// Use different random data for each hasher.
|
||||||
|
let sha1_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA1_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
let sha224_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA224_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
let sha256_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA256_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let sha384_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA384_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let sha512_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA512_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
|
||||||
|
let mut sha1_remaining = sha1_source_data;
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
let mut sha224_remaining = sha224_source_data;
|
||||||
|
let mut sha256_remaining = sha256_source_data;
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let mut sha384_remaining = sha384_source_data;
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let mut sha512_remaining = sha512_source_data;
|
||||||
|
|
||||||
|
let mut sha1 = esp_hal::sha::Sha1::default();
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
let mut sha224 = esp_hal::sha::Sha224::default();
|
||||||
|
let mut sha256 = esp_hal::sha::Sha256::default();
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let mut sha384 = esp_hal::sha::Sha384::default();
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let mut sha512 = esp_hal::sha::Sha512::default();
|
||||||
|
|
||||||
|
// All sources are the same length
|
||||||
|
while sha1_remaining.len() > 0 {
|
||||||
|
sha1_remaining = block!(Sha::update(&mut sha1, sha1_remaining)).unwrap();
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
{
|
||||||
|
sha224_remaining = block!(Sha::update(&mut sha224, sha224_remaining)).unwrap();
|
||||||
|
}
|
||||||
|
sha256_remaining = block!(Sha::update(&mut sha256, sha256_remaining)).unwrap();
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
{
|
||||||
|
sha384_remaining = block!(Sha::update(&mut sha384, sha384_remaining)).unwrap();
|
||||||
|
sha512_remaining = block!(Sha::update(&mut sha512, sha512_remaining)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sha1_output = [0u8; 20];
|
||||||
|
block!(sha1.finish(sha1_output.as_mut_slice())).unwrap();
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
let mut sha224_output = [0u8; 28];
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
block!(sha224.finish(sha224_output.as_mut_slice())).unwrap();
|
||||||
|
let mut sha256_output = [0u8; 32];
|
||||||
|
block!(sha256.finish(sha256_output.as_mut_slice())).unwrap();
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let mut sha384_output = [0u8; 48];
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
block!(sha384.finish(sha384_output.as_mut_slice())).unwrap();
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let mut sha512_output = [0u8; 64];
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
block!(sha512.finish(sha512_output.as_mut_slice())).unwrap();
|
||||||
|
|
||||||
|
// Calculate software result to compare against
|
||||||
|
// Sha1
|
||||||
|
let mut sha1_sw = sha1::Sha1::new();
|
||||||
|
sha1_sw.update(sha1_source_data);
|
||||||
|
let soft_result = sha1_sw.finalize();
|
||||||
|
for (a, b) in sha1_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sha224
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
{
|
||||||
|
let mut sha224_sw = sha2::Sha224::new();
|
||||||
|
sha224_sw.update(sha224_source_data);
|
||||||
|
let soft_result = sha224_sw.finalize();
|
||||||
|
for (a, b) in sha224_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sha256
|
||||||
|
let mut sha256_sw = sha2::Sha256::new();
|
||||||
|
sha256_sw.update(sha256_source_data);
|
||||||
|
let soft_result = sha256_sw.finalize();
|
||||||
|
for (a, b) in sha256_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sha384
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
{
|
||||||
|
let mut sha384_sw = sha2::Sha384::new();
|
||||||
|
sha384_sw.update(sha384_source_data);
|
||||||
|
let soft_result = sha384_sw.finalize();
|
||||||
|
for (a, b) in sha384_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sha512
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
{
|
||||||
|
let mut sha512_sw = sha2::Sha512::new();
|
||||||
|
sha512_sw.update(sha512_source_data);
|
||||||
|
let soft_result = sha512_sw.finalize();
|
||||||
|
for (a, b) in sha512_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A rolling test that loops between hasher for every step to test
|
||||||
|
/// interleaving. This specifically test the Digest trait implementation
|
||||||
|
#[test]
|
||||||
|
fn test_for_digest_rolling() {
|
||||||
|
let peripherals = Peripherals::take();
|
||||||
|
let system = SystemControl::new(peripherals.SYSTEM);
|
||||||
|
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||||
|
|
||||||
|
let mut rng = Rng::new(peripherals.RNG);
|
||||||
|
|
||||||
|
// Fill source data with random data
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
|
for slice in unsafe {
|
||||||
|
[
|
||||||
|
addr_of_mut!(SHA1_RANDOM_ARRAY),
|
||||||
|
addr_of_mut!(SHA224_RANDOM_ARRAY),
|
||||||
|
addr_of_mut!(SHA256_RANDOM_ARRAY),
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
addr_of_mut!(SHA384_RANDOM_ARRAY),
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
addr_of_mut!(SHA512_RANDOM_ARRAY),
|
||||||
|
]
|
||||||
|
} {
|
||||||
|
rng.read(unsafe { &mut *slice });
|
||||||
|
}
|
||||||
|
|
||||||
|
for size in [1, 64, 128, 256] {
|
||||||
|
// Use different random data for each hasher.
|
||||||
|
let sha1_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA1_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
let sha224_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA224_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
let sha256_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA256_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let sha384_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA384_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let sha512_source_data =
|
||||||
|
unsafe { core::slice::from_raw_parts(SHA512_RANDOM_ARRAY.as_ptr(), size) };
|
||||||
|
|
||||||
|
let mut sha1 = esp_hal::sha::Sha1::default();
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
let mut sha224 = esp_hal::sha::Sha224::default();
|
||||||
|
let mut sha256 = esp_hal::sha::Sha256::default();
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let mut sha384 = esp_hal::sha::Sha384::default();
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let mut sha512 = esp_hal::sha::Sha512::default();
|
||||||
|
|
||||||
|
// The Digest::update will consume the entirety of remaining. We don't need to
|
||||||
|
// loop until remaining is fully consumed.
|
||||||
|
Digest::update(&mut sha1, sha1_source_data);
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
Digest::update(&mut sha224, sha224_source_data);
|
||||||
|
Digest::update(&mut sha256, sha256_source_data);
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
Digest::update(&mut sha384, sha384_source_data);
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
Digest::update(&mut sha512, sha512_source_data);
|
||||||
|
|
||||||
|
let sha1_output: [u8; 20] = Digest::finalize(sha1).into();
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
let sha224_output: [u8; 28] = Digest::finalize(sha224).into();
|
||||||
|
let sha256_output: [u8; 32] = Digest::finalize(sha256).into();
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let sha384_output: [u8; 48] = Digest::finalize(sha384).into();
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
let sha512_output: [u8; 64] = Digest::finalize(sha512).into();
|
||||||
|
|
||||||
|
// Calculate software result to compare against
|
||||||
|
// Sha1
|
||||||
|
let mut sha1_sw = sha1::Sha1::new();
|
||||||
|
sha1_sw.update(sha1_source_data);
|
||||||
|
let soft_result = sha1_sw.finalize();
|
||||||
|
for (a, b) in sha1_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sha224
|
||||||
|
#[cfg(not(feature = "esp32"))]
|
||||||
|
{
|
||||||
|
let mut sha224_sw = sha2::Sha224::new();
|
||||||
|
sha224_sw.update(sha224_source_data);
|
||||||
|
let soft_result = sha224_sw.finalize();
|
||||||
|
for (a, b) in sha224_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sha256
|
||||||
|
let mut sha256_sw = sha2::Sha256::new();
|
||||||
|
sha256_sw.update(sha256_source_data);
|
||||||
|
let soft_result = sha256_sw.finalize();
|
||||||
|
for (a, b) in sha256_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sha384
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
{
|
||||||
|
let mut sha384_sw = sha2::Sha384::new();
|
||||||
|
sha384_sw.update(sha384_source_data);
|
||||||
|
let soft_result = sha384_sw.finalize();
|
||||||
|
for (a, b) in sha384_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sha512
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
|
{
|
||||||
|
let mut sha512_sw = sha2::Sha512::new();
|
||||||
|
sha512_sw.update(sha512_source_data);
|
||||||
|
let soft_result = sha512_sw.finalize();
|
||||||
|
for (a, b) in sha512_output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple test using [esp_hal::sha::Sha] trait to test hashing for an
|
||||||
|
/// algorithm against a specific size. This will compare the result with a
|
||||||
|
/// software implementation and return false if there's a mismatch
|
||||||
|
fn test_for_size<D: Digest + Default + Sha<esp_hal::Blocking>, const N: usize>(size: usize) {
|
||||||
|
let source_data = unsafe { core::slice::from_raw_parts(CHAR_ARRAY.as_ptr(), size) };
|
||||||
|
let mut remaining = source_data;
|
||||||
|
let mut hasher = D::default();
|
||||||
|
|
||||||
|
let mut output = [0u8; N];
|
||||||
|
|
||||||
|
while remaining.len() > 0 {
|
||||||
|
remaining = block!(Sha::update(&mut hasher, &remaining)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
block!(hasher.finish(output.as_mut_slice())).unwrap();
|
||||||
|
|
||||||
|
// Compare against Software result.
|
||||||
|
match N {
|
||||||
|
20 => {
|
||||||
|
let mut hasher = sha1::Sha1::new();
|
||||||
|
hasher.update(source_data);
|
||||||
|
let soft_result = hasher.finalize();
|
||||||
|
for (a, b) in output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
28 => {
|
||||||
|
let mut hasher = sha2::Sha224::new();
|
||||||
|
hasher.update(source_data);
|
||||||
|
let soft_result = hasher.finalize();
|
||||||
|
for (a, b) in output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
32 => {
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(source_data);
|
||||||
|
let soft_result = hasher.finalize();
|
||||||
|
for (a, b) in output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
48 => {
|
||||||
|
let mut hasher = sha2::Sha384::new();
|
||||||
|
hasher.update(source_data);
|
||||||
|
let soft_result = hasher.finalize();
|
||||||
|
for (a, b) in output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
64 => {
|
||||||
|
let mut hasher = sha2::Sha512::new();
|
||||||
|
hasher.update(source_data);
|
||||||
|
let soft_result = hasher.finalize();
|
||||||
|
for (a, b) in output.iter().zip(soft_result) {
|
||||||
|
assert_eq!(*a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user