From c98523b2bc9f60522130266938c17a399086e5a5 Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Sat, 16 May 2020 03:35:49 -0300 Subject: [PATCH 1/3] ecb implementation and example --- Cargo.toml | 1 + examples/ecb-demo/Cargo.toml | 26 +++++++++ examples/ecb-demo/Embed.toml | 46 ++++++++++++++++ examples/ecb-demo/README.md | 19 +++++++ examples/ecb-demo/src/main.rs | 67 ++++++++++++++++++++++ nrf-hal-common/src/ecb.rs | 101 ++++++++++++++++++++++++++++++++++ nrf-hal-common/src/lib.rs | 2 + nrf51-hal/src/lib.rs | 1 + nrf52810-hal/src/lib.rs | 1 + nrf52832-hal/src/lib.rs | 1 + nrf52840-hal/src/lib.rs | 1 + 11 files changed, 266 insertions(+) create mode 100644 examples/ecb-demo/Cargo.toml create mode 100644 examples/ecb-demo/Embed.toml create mode 100644 examples/ecb-demo/README.md create mode 100644 examples/ecb-demo/src/main.rs create mode 100644 nrf-hal-common/src/ecb.rs diff --git a/Cargo.toml b/Cargo.toml index 01fa2c0b..9e6a6d82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ "examples/rtfm-demo", "examples/spi-demo", "examples/twi-ssd1306", + "examples/ecb-demo", ] [profile.dev] diff --git a/examples/ecb-demo/Cargo.toml b/examples/ecb-demo/Cargo.toml new file mode 100644 index 00000000..2f936142 --- /dev/null +++ b/examples/ecb-demo/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "ecb-demo" +version = "0.0.1" +edition = "2018" +authors = [ "Thales Fragoso "] + +[dependencies] +cortex-m = "0.6.2" +cortex-m-rt = "0.6.12" +rtt-target = {version = "0.2.0", features = ["cortex-m"] } + +nrf52810-hal = { path = "../../nrf52810-hal", features = ["rt"], optional = true } +nrf52832-hal = { path = "../../nrf52832-hal", features = ["rt"], optional = true } +nrf52840-hal = { path = "../../nrf52840-hal", features = ["rt"], optional = true } +nrf51-hal = { path = "../../nrf51-hal", features = ["rt"], optional = true} + +[[bin]] +name = "ecb-demo" +doc = false +test = false + +[features] +51 = ["nrf51-hal"] +52810 = ["nrf52810-hal"] +52832 = ["nrf52832-hal"] +52840 = ["nrf52840-hal"] diff --git a/examples/ecb-demo/Embed.toml b/examples/ecb-demo/Embed.toml new file mode 100644 index 00000000..5da61018 --- /dev/null +++ b/examples/ecb-demo/Embed.toml @@ -0,0 +1,46 @@ +[probe] +# The index of the probe in the connected probe list. +# probe_index = 0 +# The protocol to be used for communicating with the target. +protocol = "Swd" +# The speed in kHz of the data link to the target. +# speed = 1337 + +[flashing] +# Whether or not the target should be flashed. +enabled = true +# Whether or not the target should be halted after flashing. +halt_afterwards = false +# Whether or not bytes erased but not rewritten with data from the ELF +# should be restored with their contents before erasing. +restore_unwritten_bytes = false +# The path where an SVG of the assembled flash layout should be written to. +# flash_layout_output_path = "out.svg" + +[general] +# The chip name of the chip to be debugged. +# chip = "nRF52832" +# A list of chip descriptions to be loaded during runtime. +chip_descriptions = [] +# The default log level to be used. +log_level = "Warn" + +[rtt] +# Whether or not an RTTUI should be opened after flashing. +# This is exclusive and cannot be used with GDB at the moment. +enabled = true +# A list of channel associations to be displayed. If left empty, all channels are displayed. +channels = [ + # { up = 0, down = 0, name = "name" } +] +# The duration in ms for which the logger should retry to attach to RTT. +timeout = 3000 +# Whether timestamps in the RTTUI are enabled +show_timestamps = true + +[gdb] +# Whether or not a GDB server should be opened after flashing. +# This is exclusive and cannot be used with RTT at the moment. +enabled = false +# The connection string in host:port format wher the GDB server will open a socket. +# gdb_connection_string diff --git a/examples/ecb-demo/README.md b/examples/ecb-demo/README.md new file mode 100644 index 00000000..173ca901 --- /dev/null +++ b/examples/ecb-demo/README.md @@ -0,0 +1,19 @@ +# AES electronic codebook mode encryption demo + +Chose the microcontroller with one of the following features: +- 51 +- 52810 +- 52832 +- 52840 + +Also, if using `cargo-embed`, change the `chip` and `protocol` fields in [Embed.toml](Embed.toml). + +This demo uses the [rtt-target](https://crates.io/crates/rtt-target) crate for communication. + +If using `cargo-embed`, just run + +```console +$ cargo embed --release --features=52832 +``` + +Replace `52832` with the correct feature for your microcontroller. diff --git a/examples/ecb-demo/src/main.rs b/examples/ecb-demo/src/main.rs new file mode 100644 index 00000000..f0da914d --- /dev/null +++ b/examples/ecb-demo/src/main.rs @@ -0,0 +1,67 @@ +#![no_std] +#![no_main] + +// Import the right HAL/PAC crate, depending on the target chip +#[cfg(feature = "51")] +pub use nrf51_hal as hal; +#[cfg(feature = "52810")] +pub use nrf52810_hal as hal; +#[cfg(feature = "52832")] +pub use nrf52832_hal as hal; +#[cfg(feature = "52840")] +pub use nrf52840_hal as hal; + +use { + core::{ + panic::PanicInfo, + sync::atomic::{compiler_fence, Ordering}, + }, + cortex_m_rt::entry, + hal::{ecb::EcbData, Clocks, Ecb}, + rtt_target::{rprint, rprintln, rtt_init_print}, +}; + +const MSG: &[u8; 16] = b"Message to encry"; +const KEY: &[u8; 16] = b"aaaaaaaaaaaaaaaa"; +const CIPHER_MSG: [u8; 16] = [ + 0xFE, 0xF1, 0x63, 0x82, 0xB4, 0x54, 0x6B, 0xE4, 0xEB, 0x9A, 0x5C, 0x0E, 0xB6, 0x0E, 0x49, 0x2F, +]; + +#[entry] +fn main() -> ! { + let p = hal::pac::Peripherals::take().unwrap(); + + let _clocks = Clocks::new(p.CLOCK).enable_ext_hfosc(); + rtt_init_print!(); + + let data = EcbData::new(*KEY, None); + let mut ecb = Ecb::init(p.ECB, data); + + let clear_text = ecb.clear_text(); + *clear_text = *MSG; + rprintln!( + "Clear text: {}", + core::str::from_utf8(&clear_text[..]).unwrap(), + ); + + loop { + ecb.encrypt().unwrap(); + let chiper_text = ecb.cipher_text(); + for number in chiper_text.iter() { + rprint!("{:x} ", *number); + } + assert_eq!(*chiper_text, CIPHER_MSG); + rprintln!("\n Encryption Done\n"); + + cortex_m::asm::delay(68_000_000); + } +} + +#[inline(never)] +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + rprintln!("{}", info); + loop { + compiler_fence(Ordering::SeqCst); + } +} diff --git a/nrf-hal-common/src/ecb.rs b/nrf-hal-common/src/ecb.rs new file mode 100644 index 00000000..523c3af5 --- /dev/null +++ b/nrf-hal-common/src/ecb.rs @@ -0,0 +1,101 @@ +//! HAL interface to the AES electronic codebook mode encryption +//! +//! The ECB encryption block supports 128 bit AES encryption (encryption only, not decryption). + +use crate::target::ECB; +use core::sync::atomic::{compiler_fence, Ordering}; + +#[derive(Debug, Copy, Clone)] +/// Error type to represent a sharing conflict during encryption +pub struct EncryptionError {} + +#[repr(C)] +/// Type that represents the data structure used by the ECB module +pub struct EcbData { + key: [u8; 16], + clear_text: [u8; 16], + chiper_text: [u8; 16], +} + +impl EcbData { + /// Creates the data structures needed for ECB utilization + /// + /// If `clear_text` is `None` it will be initialized to zero + pub fn new(key: [u8; 16], clear_text: Option<[u8; 16]>) -> Self { + Self { + key, + clear_text: clear_text.unwrap_or_default(), + chiper_text: [0; 16], + } + } +} + +/// HAL structure interface to use the capabilities of the ECB peripheral +pub struct Ecb { + regs: ECB, + data: EcbData, +} + +impl Ecb { + /// Method for initialization + pub fn init(regs: ECB, data: EcbData) -> Self { + // Disable all interrupts + regs.intenclr + .write(|w| w.endecb().clear().errorecb().clear()); + + // NOTE(unsafe) 1 is a valid pattern to write to this register + regs.tasks_stopecb.write(|w| unsafe { w.bits(1) }); + Self { regs, data } + } + + /// Gets a reference to the clear text memory + /// + /// This is the data that will be encrypted by the encrypt method + #[inline] + pub fn clear_text(&mut self) -> &mut [u8; 16] { + &mut self.data.clear_text + } + + /// Get a reference to the cipher text memory + /// + /// This will contain the encrypted data after a successful encryption + #[inline] + pub fn cipher_text(&mut self) -> &mut [u8; 16] { + &mut self.data.chiper_text + } + + /// Encrypts the data in the `clear_text` field, the encrypted data will be located in the + /// cipher text field only if this method returns `Ok` + /// + /// In case of an error, this method will return `Err(EncryptionError)`, in this case, the data + /// in `cipher_text` is not valid + pub fn encrypt(&mut self) -> Result<(), EncryptionError> { + // Ecb data is repr(C) and has no padding + let data_ptr = &mut self.data as *mut _ as u32; + + // NOTE(unsafe) Any 32bits pattern is safe to write to this register + self.regs.ecbdataptr.write(|w| unsafe { w.bits(data_ptr) }); + + // Clear all events + self.regs.events_endecb.reset(); + self.regs.events_errorecb.reset(); + + // "Preceding reads and writes cannot be moved past subsequent writes." + compiler_fence(Ordering::Release); + // NOTE(unsafe) 1 is a valid pattern to write to this register + self.regs.tasks_startecb.write(|w| unsafe { w.bits(1) }); + + while self.regs.events_endecb.read().bits() == 0 + && self.regs.events_errorecb.read().bits() == 0 + {} + + // "Subsequent reads and writes cannot be moved ahead of preceding reads." + compiler_fence(Ordering::Acquire); + + if self.regs.events_errorecb.read().bits() == 1 { + // It's ok to return here, the events will be cleared before the next encryption + return Err(EncryptionError {}); + } + Ok(()) + } +} diff --git a/nrf-hal-common/src/lib.rs b/nrf-hal-common/src/lib.rs index b93b1643..2befd62a 100644 --- a/nrf-hal-common/src/lib.rs +++ b/nrf-hal-common/src/lib.rs @@ -25,6 +25,8 @@ pub mod adc; pub mod clocks; #[cfg(not(feature = "51"))] pub mod delay; +#[cfg(not(feature = "9160"))] +pub mod ecb; pub mod gpio; #[cfg(not(feature = "9160"))] pub mod rng; diff --git a/nrf51-hal/src/lib.rs b/nrf51-hal/src/lib.rs index 2d2b0181..861b8364 100644 --- a/nrf51-hal/src/lib.rs +++ b/nrf51-hal/src/lib.rs @@ -11,6 +11,7 @@ pub mod prelude { pub use crate::adc::Adc; pub use crate::clocks::Clocks; +pub use crate::ecb::Ecb; pub use crate::rtc::Rtc; pub use crate::spi::Spi; pub use crate::temp::Temp; diff --git a/nrf52810-hal/src/lib.rs b/nrf52810-hal/src/lib.rs index 8ea2dea6..dd36a252 100644 --- a/nrf52810-hal/src/lib.rs +++ b/nrf52810-hal/src/lib.rs @@ -13,6 +13,7 @@ pub mod prelude { pub use crate::clocks::Clocks; pub use crate::delay::Delay; +pub use crate::ecb::Ecb; pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::temp::Temp; diff --git a/nrf52832-hal/src/lib.rs b/nrf52832-hal/src/lib.rs index 43f6eb9c..b0aaceae 100644 --- a/nrf52832-hal/src/lib.rs +++ b/nrf52832-hal/src/lib.rs @@ -11,6 +11,7 @@ pub mod prelude { pub use crate::clocks::Clocks; pub use crate::delay::Delay; +pub use crate::ecb::Ecb; pub use crate::rtc::Rtc; pub use crate::saadc::Saadc; pub use crate::spim::Spim; diff --git a/nrf52840-hal/src/lib.rs b/nrf52840-hal/src/lib.rs index f5969422..952b1b41 100644 --- a/nrf52840-hal/src/lib.rs +++ b/nrf52840-hal/src/lib.rs @@ -13,6 +13,7 @@ pub mod prelude { pub use crate::clocks::Clocks; pub use crate::delay::Delay; +pub use crate::ecb::Ecb; pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::temp::Temp; From 9778383537a3389a459c7e46980fe0d298cf62c8 Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Sun, 17 May 2020 15:46:48 -0300 Subject: [PATCH 2/3] Change to jonas API --- examples/ecb-demo/README.md | 6 +-- examples/ecb-demo/src/main.rs | 31 +++++------ nrf-hal-common/src/ecb.rs | 97 +++++++++++++++++------------------ 3 files changed, 63 insertions(+), 71 deletions(-) diff --git a/examples/ecb-demo/README.md b/examples/ecb-demo/README.md index 173ca901..af4c3e76 100644 --- a/examples/ecb-demo/README.md +++ b/examples/ecb-demo/README.md @@ -1,6 +1,6 @@ # AES electronic codebook mode encryption demo -Chose the microcontroller with one of the following features: +Choose the microcontroller with one of the following features: - 51 - 52810 - 52832 @@ -13,7 +13,7 @@ This demo uses the [rtt-target](https://crates.io/crates/rtt-target) crate for c If using `cargo-embed`, just run ```console -$ cargo embed --release --features=52832 +$ cargo embed --release --features=52832 --target=thumbv7em-none-eabihf ``` -Replace `52832` with the correct feature for your microcontroller. +Replace `52832` and `thumbv7em-none-eabihf` with the correct feature and target for your microcontroller. diff --git a/examples/ecb-demo/src/main.rs b/examples/ecb-demo/src/main.rs index f0da914d..24fd1d96 100644 --- a/examples/ecb-demo/src/main.rs +++ b/examples/ecb-demo/src/main.rs @@ -17,12 +17,12 @@ use { sync::atomic::{compiler_fence, Ordering}, }, cortex_m_rt::entry, - hal::{ecb::EcbData, Clocks, Ecb}, + hal::{Clocks, Ecb}, rtt_target::{rprint, rprintln, rtt_init_print}, }; -const MSG: &[u8; 16] = b"Message to encry"; -const KEY: &[u8; 16] = b"aaaaaaaaaaaaaaaa"; +const MSG: [u8; 16] = *b"Message to encry"; +const KEY: [u8; 16] = *b"aaaaaaaaaaaaaaaa"; const CIPHER_MSG: [u8; 16] = [ 0xFE, 0xF1, 0x63, 0x82, 0xB4, 0x54, 0x6B, 0xE4, 0xEB, 0x9A, 0x5C, 0x0E, 0xB6, 0x0E, 0x49, 0x2F, ]; @@ -34,26 +34,21 @@ fn main() -> ! { let _clocks = Clocks::new(p.CLOCK).enable_ext_hfosc(); rtt_init_print!(); - let data = EcbData::new(*KEY, None); - let mut ecb = Ecb::init(p.ECB, data); - - let clear_text = ecb.clear_text(); - *clear_text = *MSG; - rprintln!( - "Clear text: {}", - core::str::from_utf8(&clear_text[..]).unwrap(), - ); + let mut ecb = Ecb::init(p.ECB); loop { - ecb.encrypt().unwrap(); - let chiper_text = ecb.cipher_text(); - for number in chiper_text.iter() { + rprintln!("Starting Encryption\n"); + rprintln!("Clear text: {}", core::str::from_utf8(&MSG[..]).unwrap()); + + let cipher_text = ecb.encrypt_block(MSG, KEY).unwrap(); + rprint!("Cipher Text: "); + for number in cipher_text.iter() { rprint!("{:x} ", *number); } - assert_eq!(*chiper_text, CIPHER_MSG); - rprintln!("\n Encryption Done\n"); + assert_eq!(cipher_text, CIPHER_MSG); + rprintln!("\r\n Encryption Done\n"); - cortex_m::asm::delay(68_000_000); + cortex_m::asm::delay(136_000_000); } } diff --git a/nrf-hal-common/src/ecb.rs b/nrf-hal-common/src/ecb.rs index 523c3af5..4c675a73 100644 --- a/nrf-hal-common/src/ecb.rs +++ b/nrf-hal-common/src/ecb.rs @@ -1,80 +1,77 @@ -//! HAL interface to the AES electronic codebook mode encryption +//! HAL interface to the AES electronic codebook mode encryption. //! //! The ECB encryption block supports 128 bit AES encryption (encryption only, not decryption). use crate::target::ECB; use core::sync::atomic::{compiler_fence, Ordering}; +/// Error type to represent a sharing conflict during encryption. #[derive(Debug, Copy, Clone)] -/// Error type to represent a sharing conflict during encryption pub struct EncryptionError {} -#[repr(C)] -/// Type that represents the data structure used by the ECB module -pub struct EcbData { - key: [u8; 16], - clear_text: [u8; 16], - chiper_text: [u8; 16], -} - -impl EcbData { - /// Creates the data structures needed for ECB utilization - /// - /// If `clear_text` is `None` it will be initialized to zero - pub fn new(key: [u8; 16], clear_text: Option<[u8; 16]>) -> Self { - Self { - key, - clear_text: clear_text.unwrap_or_default(), - chiper_text: [0; 16], - } - } -} - -/// HAL structure interface to use the capabilities of the ECB peripheral +/// A safe, blocking wrapper around the AES-ECB peripheral. +/// +/// It's really just blockwise AES and not an ECB stream cipher. Blocks can be +/// encrypted by calling `crypt_block`. pub struct Ecb { regs: ECB, - data: EcbData, } impl Ecb { - /// Method for initialization - pub fn init(regs: ECB, data: EcbData) -> Self { + /// Takes ownership of the `ECB` peripheral, returning a safe wrapper. + pub fn init(regs: ECB) -> Self { // Disable all interrupts regs.intenclr .write(|w| w.endecb().clear().errorecb().clear()); // NOTE(unsafe) 1 is a valid pattern to write to this register regs.tasks_stopecb.write(|w| unsafe { w.bits(1) }); - Self { regs, data } + Self { regs } } - /// Gets a reference to the clear text memory - /// - /// This is the data that will be encrypted by the encrypt method - #[inline] - pub fn clear_text(&mut self) -> &mut [u8; 16] { - &mut self.data.clear_text - } + /// Destroys `self`, giving the `ECB` peripheral back. + pub fn into_inner(self) -> ECB { + // Clear all events + self.regs.events_endecb.reset(); + self.regs.events_errorecb.reset(); - /// Get a reference to the cipher text memory - /// - /// This will contain the encrypted data after a successful encryption - #[inline] - pub fn cipher_text(&mut self) -> &mut [u8; 16] { - &mut self.data.chiper_text + self.regs } - /// Encrypts the data in the `clear_text` field, the encrypted data will be located in the - /// cipher text field only if this method returns `Ok` + /// Blocking encryption. + /// + /// Encrypts a `block` with `key`. /// - /// In case of an error, this method will return `Err(EncryptionError)`, in this case, the data - /// in `cipher_text` is not valid - pub fn encrypt(&mut self) -> Result<(), EncryptionError> { - // Ecb data is repr(C) and has no padding - let data_ptr = &mut self.data as *mut _ as u32; + /// # Errors + /// + /// An error will be returned when the AES hardware raises an `ERRORECB` + /// event. This can happen when an operation is started that shares the AES + /// hardware resources with the AES ECB peripheral while an encryption + /// operation is running. + pub fn encrypt_block( + &mut self, + block: [u8; 16], + key: [u8; 16], + ) -> Result<[u8; 16], EncryptionError> { + #[repr(C)] + struct EcbData { + key: [u8; 16], + clear_text: [u8; 16], + cipher_text: [u8; 16], + } + + // We allocate the DMA'd buffer on the stack, which means that we must + // not panic or return before the AES operation is finished. + let mut buf = EcbData { + key, + clear_text: block, + cipher_text: [0; 16], + }; // NOTE(unsafe) Any 32bits pattern is safe to write to this register - self.regs.ecbdataptr.write(|w| unsafe { w.bits(data_ptr) }); + self.regs + .ecbdataptr + .write(|w| unsafe { w.bits(&mut buf as *mut _ as u32) }); // Clear all events self.regs.events_endecb.reset(); @@ -96,6 +93,6 @@ impl Ecb { // It's ok to return here, the events will be cleared before the next encryption return Err(EncryptionError {}); } - Ok(()) + Ok(buf.cipher_text) } } From 66e335507a42cf2cf92a9d073541299516ecfdee Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Thu, 28 May 2020 00:19:19 -0300 Subject: [PATCH 3/3] Add ecb to nrf52833 and build example --- examples/ecb-demo/Cargo.toml | 2 ++ examples/ecb-demo/src/main.rs | 2 ++ nrf52833-hal/src/lib.rs | 1 + scripts/build.sh | 2 ++ 4 files changed, 7 insertions(+) diff --git a/examples/ecb-demo/Cargo.toml b/examples/ecb-demo/Cargo.toml index 2f936142..9845417f 100644 --- a/examples/ecb-demo/Cargo.toml +++ b/examples/ecb-demo/Cargo.toml @@ -12,6 +12,7 @@ rtt-target = {version = "0.2.0", features = ["cortex-m"] } nrf52810-hal = { path = "../../nrf52810-hal", features = ["rt"], optional = true } nrf52832-hal = { path = "../../nrf52832-hal", features = ["rt"], optional = true } nrf52840-hal = { path = "../../nrf52840-hal", features = ["rt"], optional = true } +nrf52833-hal = { path = "../../nrf52833-hal", features = ["rt"], optional = true } nrf51-hal = { path = "../../nrf51-hal", features = ["rt"], optional = true} [[bin]] @@ -24,3 +25,4 @@ test = false 52810 = ["nrf52810-hal"] 52832 = ["nrf52832-hal"] 52840 = ["nrf52840-hal"] +52833 = ["nrf52833-hal"] diff --git a/examples/ecb-demo/src/main.rs b/examples/ecb-demo/src/main.rs index 24fd1d96..9a9f7dc3 100644 --- a/examples/ecb-demo/src/main.rs +++ b/examples/ecb-demo/src/main.rs @@ -8,6 +8,8 @@ pub use nrf51_hal as hal; pub use nrf52810_hal as hal; #[cfg(feature = "52832")] pub use nrf52832_hal as hal; +#[cfg(feature = "52833")] +pub use nrf52833_hal as hal; #[cfg(feature = "52840")] pub use nrf52840_hal as hal; diff --git a/nrf52833-hal/src/lib.rs b/nrf52833-hal/src/lib.rs index cbf21491..af84f376 100644 --- a/nrf52833-hal/src/lib.rs +++ b/nrf52833-hal/src/lib.rs @@ -13,6 +13,7 @@ pub mod prelude { pub use crate::clocks::Clocks; pub use crate::delay::Delay; +pub use crate::ecb::Ecb; pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::temp::Temp; diff --git a/scripts/build.sh b/scripts/build.sh index b010fb52..2ec90b26 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -43,5 +43,7 @@ echo Building examples/twi-ssd1306... cargo build --manifest-path examples/twi-ssd1306/Cargo.toml echo Building examples/twi-ssd1306... cargo build --manifest-path examples/twi-ssd1306/Cargo.toml --no-default-features --features="52840" --target thumbv7em-none-eabi +echo Building examples/ecb-demo... +cargo build --manifest-path examples/ecb-demo/Cargo.toml --features=52832 echo Checking source code formatting... cargo +stable fmt -- --check