Scott Mabin db409ffe7b
Unify the system peripheral (#832)
* Unify the system peripheral

Whilst the PCR, SYSTEM and DPORT peripherals are different, we currently
use them all in the same way. This PR unifies the peripheral name in the
hal to `SYSTEM`. The idea is that they all do the same sort of thing, so
we can collect them under the same name, and later down the line we can
being to expose differences under an extended API.

The benifits to this are imo quite big, the examples now are all identical,
which makes things easier for esp-wifi, and paves a path towards the
multichip hal.

Why not do this in the PAC? Imo the pac should be as close to the
hardware as possible, and the HAL is where we should abstractions such
as this.

* changelog
2023-09-29 08:14:50 -07:00

122 lines
4.5 KiB
Rust

//! Demonstrates the use of the HMAC peripheral and compares the speed of
//! hardware-accelerated and pure software hashing.
//!
//! # Writing key
//! Before using the HMAC accelerator in upstream mode, you first need to
//! prepare a secret 256-bit HMAC key and burn the key to an empty eFuse block.
//!
//! ## ⚠️ Before writing ⚠️
//! - From the factory, the eFuse keyblocks are programmed to be 32-byte 0x00.
//! - This example is programmed to use this value so you can skip this step if
//! you don't want to burn an eFuse key.
//! - If you skip the skip burning a custom key, you still need to [burn the
//! purpose](#burn-key-purpose).
//! - [Read more about eFuses](https://docs.espressif.com/projects/esptool/en/latest/esp32h2/espefuse/index.html)
//!
//! ## Burn key purpose
//! You first need to burn the efuse key purpose for the specified key below
//! (Default Key0). Purposes:
//!
//! | Purpose | Mode | Value | Description |
//! |--------------------------------|------------|-------|-----------------------------------------------|
//! | JTAG Re-enable | Downstream | 6 | EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG |
//! | DS Key Derivation | Downstream | 7 | EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE |
//! | HMAC Calculation | Upstream | 8 | EFUSE_KEY_PURPOSE_HMAC_UP |
//! | Both JTAG Re-enable and DS KDF | Downstream | 5 | EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL |
//!
//! To burn the efuse key purpose `HMAC_UP` to `Key0`:
//! ```sh
//! espefuse.py burn_efuse KEY_PURPOSE_0 8
//! ```
//!
//! ## Use a custom key
//! You can generate a custom key file from a string using the following command
//! ```sh
//! echo -n "<Your custom key>" | openssl dgst -sha256 -binary > key.bin
//! ```
//!
//! You can then write your key using the following command
//! - `BLOCK_KEY0` The keyblock to program the key to. By default this example
//! uses key0.
//! - `HMAC_UP` The purpose for the key. Use HMAC_UP for upstream.
//! - `--no-read-protect` Allow to read the key from software, after writing it.
//! ```sh
//! espefuse.py burn_key BLOCK_KEY0 key.bin HMAC_UP --no-read-protect
//! ```
//! To see the key in bytes, you can do the following:
//! ```sh
//! echo -n "<Your custom key>" | openssl dgst -sha256 -binary | xxd -p
//! ```
//! or from the binary file
//! ```sh
//! xxd -p key.bin
//! ```
#![no_std]
#![no_main]
use esp32h2_hal::{
clock::ClockControl,
hmac::{Hmac, HmacPurpose, KeyId},
peripherals::Peripherals,
prelude::*,
systimer::SystemTimer,
Rng,
};
use esp_backtrace as _;
use esp_println::println;
use hmac::{Hmac as HmacSw, Mac};
use nb::block;
use sha2::Sha256;
type HmacSha256 = HmacSw<Sha256>;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rng = Rng::new(peripherals.RNG);
// Set sw key
let key = [0_u8; 32].as_ref();
let mut hw_hmac = Hmac::new(peripherals.HMAC);
let mut src = [0_u8; 1024];
rng.read(src.as_mut_slice()).unwrap();
// println!("HMAC input {:02X?}", src);
let mut output = [0u8; 32];
println!("Beginning stress tests...");
println!("Testing length from 0 to {:?} bytes for HMAC...", src.len());
for i in 0..src.len() + 1 {
let (nsrc, _) = src.split_at(i);
let mut remaining = nsrc;
hw_hmac.init();
block!(hw_hmac.configure(HmacPurpose::ToUser, KeyId::Key0)).expect("Key purpose mismatch");
let pre_hw_hmac = SystemTimer::now();
while remaining.len() > 0 {
remaining = block!(hw_hmac.update(remaining)).unwrap();
}
block!(hw_hmac.finalize(output.as_mut_slice())).unwrap();
let post_hw_hmac = SystemTimer::now();
let hw_time = post_hw_hmac - pre_hw_hmac;
let mut sw_hmac = HmacSha256::new_from_slice(key).expect("HMAC can take key of any size");
let pre_sw_hash = SystemTimer::now();
sw_hmac.update(nsrc);
let soft_result = sw_hmac.finalize().into_bytes();
let post_sw_hash = SystemTimer::now();
let soft_time = post_sw_hash - pre_sw_hash;
for (a, b) in output.iter().zip(soft_result) {
assert_eq!(*a, b);
}
println!("Testing for length: {:>4} | HW: {:>6} cycles, SW: {:>7} cycles (HW HMAC is {:>2}x faster)", i, hw_time, soft_time, soft_time / hw_time);
}
println!("Finished stress tests!");
loop {}
}