diff --git a/examples/linux/src/main.rs b/examples/linux/src/main.rs index e387fa53..06564264 100644 --- a/examples/linux/src/main.rs +++ b/examples/linux/src/main.rs @@ -1,17 +1,17 @@ #![feature(type_alias_impl_trait)] // Required for embassy use embassy_executor::Spawner; -use embassy_time::Duration; -use embassy_time::Timer; +use embassy_time::{Duration, Timer}; use heapless::spsc::{Consumer, Producer, Queue}; -use heimlig::client::api::Api; -use heimlig::common::jobs::{Request, Response}; -use heimlig::common::pool::Memory; -use heimlig::common::pool::Pool; -use heimlig::crypto::rng; -use heimlig::crypto::rng::Rng; -use heimlig::hsm::core::Core; -use heimlig::{client, hsm}; +use heimlig::{ + client::{self, api::Api}, + common::{ + jobs::{ExternalMemory, OutParam, Request, Response}, + pool::{Memory, Pool}, + }, + crypto::rng::{self, Rng}, + hsm::{self, core::Core}, +}; use log::{error, info}; use rand::RngCore; @@ -104,13 +104,18 @@ async fn client_task( // Api let mut api = Api::new(&mut core_side); + // Random buffer + let random_buffer = [0u8; 16]; + loop { // Send request Timer::after(Duration::from_millis(1000)).await; - let random_size = 16; - info!(target: "CLIENT", "Sending request: random data (size={})", random_size); - api.get_random(random_size) - .expect("failed to call randomness API"); + + info!(target: "CLIENT", "Sending request: random data (size={})", random_buffer.len()); + api.get_random(OutParam::new(ExternalMemory::from_slice( + random_buffer.as_slice(), + ))) + .expect("failed to call randomness API"); // Receive response loop { @@ -121,7 +126,7 @@ async fn client_task( Response::GetRandom { data } => { info!(target: "CLIENT", "Received response: random data (size={}): {}", - data.len(), + data.as_slice().len(), hex::encode(data.as_slice()) ); break; // Send next request diff --git a/examples/stm32h745i/cm7/src/bin/rng_single_core.rs b/examples/stm32h745i/cm7/src/bin/rng_single_core.rs index 51f3475e..594d5eb8 100644 --- a/examples/stm32h745i/cm7/src/bin/rng_single_core.rs +++ b/examples/stm32h745i/cm7/src/bin/rng_single_core.rs @@ -12,7 +12,7 @@ use embassy_time::{Duration, Timer}; use heapless::spsc::{Consumer, Producer, Queue}; use heimlig::client; use heimlig::client::api::Api; -use heimlig::common::jobs::{Request, Response}; +use heimlig::common::jobs::{ExternalMemory, OutParam, Request, Response}; use heimlig::common::pool::Memory; use heimlig::common::pool::Pool; use heimlig::crypto::rng; @@ -123,14 +123,21 @@ async fn client_task( // Api let mut api = Api::new(&mut core_side); + // Random buffer + let random_buffer = [0u8; 16]; + loop { // Send requests Timer::after(Duration::from_millis(1000)).await; led.set_high(); - let random_size = 16; - info!("Sending request: random data (size={})", random_size); - api.get_random(random_size) - .expect("failed to call randomness API"); + info!( + "Sending request: random data (size={})", + random_buffer.len() + ); + api.get_random(OutParam::new(ExternalMemory::from_slice( + random_buffer.as_slice(), + ))) + .expect("failed to call randomness API"); // Receive response loop { @@ -139,7 +146,7 @@ async fn client_task( Response::GetRandom { data } => { info!( "Received response: random data (size={}): {:02x}", - data.len(), + data.as_slice().len(), data.as_slice() ); break; diff --git a/heimlig/src/client/api.rs b/heimlig/src/client/api.rs index 082d2b83..46fadf47 100644 --- a/heimlig/src/client/api.rs +++ b/heimlig/src/client/api.rs @@ -1,4 +1,4 @@ -use crate::common::jobs::{Request, Response}; +use crate::common::jobs::{OutParam, Request, Response}; #[derive(Clone, Eq, PartialEq, Debug)] pub enum Error { @@ -25,9 +25,9 @@ impl<'a, C: Channel> Api<'a, C> { Api { channel } } - /// Request `size` many random bytes. - pub fn get_random(&mut self, size: usize) -> Result<(), Error> { - self.channel.send(Request::GetRandom { size }) + /// Request to fill `data` with random bytes. + pub fn get_random(&mut self, data: OutParam) -> Result<(), Error> { + self.channel.send(Request::GetRandom { data }) } /// Attempt to poll a response and return it. @@ -39,7 +39,7 @@ impl<'a, C: Channel> Api<'a, C> { #[cfg(test)] mod test { use crate::client::api::{Api, Channel, Error}; - use crate::common::jobs::{Request, Response}; + use crate::common::jobs::{ExternalMemory, OutParam, Request, Response}; use crate::common::pool::{Memory, Pool}; use heapless::spsc::{Consumer, Producer, Queue}; @@ -79,22 +79,26 @@ mod test { // Send request let random_len = 16; - api.get_random(random_len) + let data = pool.alloc(random_len).expect("failed to allocate"); + api.get_random(OutParam::new(ExternalMemory::from_slice(data.as_slice()))) .expect("failed to call randomness API"); let request = req_rx.dequeue().expect("failed to receive request"); - match request { - Request::GetRandom { size } => assert_eq!(size, random_len), + let random_buffer = match request { + Request::GetRandom { data } => data, _ => panic!("Unexpected request type"), - } + }; + + assert_eq!(random_buffer.as_slice().len(), random_len); // Receive response - let data = pool.alloc(random_len).expect("failed to allocate"); resp_tx - .enqueue(Response::GetRandom { data }) + .enqueue(Response::GetRandom { + data: random_buffer, + }) .expect("failed to send response"); let response = api.recv_response().expect("failed to receive response"); match response { - Response::GetRandom { data } => assert_eq!(data.len(), random_len), + Response::GetRandom { data } => assert_eq!(data.as_slice().len(), random_len), _ => panic!("Unexpected response type"), } } diff --git a/heimlig/src/common/jobs.rs b/heimlig/src/common/jobs.rs index c6c49926..a6d51495 100644 --- a/heimlig/src/common/jobs.rs +++ b/heimlig/src/common/jobs.rs @@ -1,4 +1,5 @@ -use crate::common::pool::PoolChunk; +use core::ptr::NonNull; + use crate::hsm::keystore; use crate::hsm::keystore::Id; @@ -14,41 +15,138 @@ pub enum Error { KeyStore(keystore::Error), } +/// Shared memory representation. +#[derive(Eq, PartialEq, Debug)] +pub struct ExternalMemory { + /// Pointer to memory. + ptr: *const u8, + /// Memory size. + size: usize, +} + +impl ExternalMemory { + pub fn new(ptr: *const u8, size: usize) -> Self { + Self { ptr, size } + } + + pub fn from_slice(data: &[u8]) -> Self { + Self::new(data.as_ptr(), data.len()) + } + + pub fn as_slice(&self) -> &[u8] { + unsafe { core::slice::from_raw_parts(self.ptr, self.size) } + } + + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { core::slice::from_raw_parts_mut(self.ptr as *mut _, self.size) } + } +} + +impl Default for ExternalMemory { + fn default() -> Self { + Self { + ptr: NonNull::::dangling().as_ptr(), + size: 0, + } + } +} + +/// Shared memory input parameter. +#[derive(Eq, PartialEq, Debug, Default)] +pub struct InParam { + /// Shared memory. + memory: ExternalMemory, +} + +impl InParam { + pub fn new(memory: ExternalMemory) -> Self { + Self { memory } + } + + pub fn as_slice(&self) -> &[u8] { + self.memory.as_slice() + } +} + +/// Shared memory output parameter. +#[derive(Eq, PartialEq, Debug, Default)] +pub struct OutParam { + /// Shared memory. + memory: ExternalMemory, +} + +impl OutParam { + pub fn new(memory: ExternalMemory) -> Self { + Self { memory } + } + + pub fn as_slice(&self) -> &[u8] { + self.memory.as_slice() + } + + pub fn as_mut_slice(&mut self) -> &mut [u8] { + self.memory.as_mut_slice() + } +} + +/// Shared memory in/out parameter. +#[derive(Eq, PartialEq, Debug, Default)] +pub struct InOutParam { + /// Shared memory. + memory: ExternalMemory, +} + +impl InOutParam { + pub fn new(memory: ExternalMemory) -> Self { + Self { memory } + } + + pub fn as_slice(&self) -> &[u8] { + self.memory.as_slice() + } + + pub fn as_mut_slice(&mut self) -> &mut [u8] { + self.memory.as_mut_slice() + } +} + /// A request for the HSM to perform a cryptographic task. #[derive(Eq, PartialEq, Debug)] pub enum Request { ImportKey { id: Id, - data: PoolChunk, + data: InParam, }, GetRandom { - size: usize, + data: OutParam, }, EncryptChaChaPoly { key_id: Id, - nonce: PoolChunk, - aad: Option, - plaintext: PoolChunk, + nonce: InParam, + aad: Option, + plaintext: InOutParam, + tag: OutParam, }, EncryptChaChaPolyExternalKey { - key: PoolChunk, - nonce: PoolChunk, - aad: Option, - plaintext: PoolChunk, + key: InParam, + nonce: InParam, + aad: Option, + plaintext: InOutParam, + tag: OutParam, }, DecryptChaChaPoly { key_id: Id, - nonce: PoolChunk, - aad: Option, - ciphertext: PoolChunk, - tag: PoolChunk, + nonce: InParam, + aad: Option, + ciphertext: InOutParam, + tag: InParam, }, DecryptChaChaPolyExternalKey { - key: PoolChunk, - nonce: PoolChunk, - aad: Option, - ciphertext: PoolChunk, - tag: PoolChunk, + key: InParam, + nonce: InParam, + aad: Option, + ciphertext: InOutParam, + tag: InParam, }, } @@ -58,13 +156,13 @@ pub enum Response { ImportKey, Error(Error), GetRandom { - data: PoolChunk, + data: OutParam, }, EncryptChaChaPoly { - ciphertext: PoolChunk, - tag: PoolChunk, + ciphertext: InOutParam, + tag: OutParam, }, DecryptChaChaPoly { - plaintext: PoolChunk, + plaintext: InOutParam, }, } diff --git a/heimlig/src/hsm/core.rs b/heimlig/src/hsm/core.rs index 2349e586..23d1f540 100644 --- a/heimlig/src/hsm/core.rs +++ b/heimlig/src/hsm/core.rs @@ -116,6 +116,7 @@ impl<'a, E: EntropySource, C: Channel, const MAX_CLIENTS: usize> Core<'a, E, C, mod tests { use super::*; use crate::client::api::Channel as ApiChannel; + use crate::common::jobs::{ExternalMemory, OutParam}; use crate::common::pool::Memory; use crate::config; use crate::config::keystore::{KEY1, KEY2, KEY3}; @@ -212,8 +213,11 @@ mod tests { // Send request from client 1 let size = 65; // Exceed size of a small chunk + let data1 = pool.alloc(size).unwrap(); client1_side - .send(Request::GetRandom { size }) + .send(Request::GetRandom { + data: OutParam::new(ExternalMemory::from_slice(data1.as_slice())), + }) .expect("failed to send request"); core.process_next().expect("failed to process next request"); if client2_side.recv().is_some() { @@ -222,7 +226,7 @@ mod tests { match client1_side.recv() { Some(response) => match response { Response::GetRandom { data } => { - assert_eq!(data.len(), size) + assert_eq!(data.as_slice().len(), size) } _ => { panic!("Unexpected response type"); @@ -234,8 +238,11 @@ mod tests { } // Send request from client 2 + let data2 = pool.alloc(size).unwrap(); client2_side - .send(Request::GetRandom { size }) + .send(Request::GetRandom { + data: OutParam::new(ExternalMemory::from_slice(data2.as_slice())), + }) .expect("failed to send request"); core.process_next().expect("failed to process next request"); if client1_side.recv().is_some() { @@ -244,7 +251,7 @@ mod tests { match client2_side.recv() { Some(response) => match response { Response::GetRandom { data } => { - assert_eq!(data.len(), size) + assert_eq!(data.as_slice().len(), size) } _ => { panic!("Unexpected response type"); diff --git a/heimlig/src/hsm/scheduler/mod.rs b/heimlig/src/hsm/scheduler/mod.rs index 38e94358..6e6d2d04 100644 --- a/heimlig/src/hsm/scheduler/mod.rs +++ b/heimlig/src/hsm/scheduler/mod.rs @@ -58,19 +58,21 @@ impl<'a, E: EntropySource> Scheduler<'a, E> { }, None => Response::Error(jobs::Error::KeyStore(keystore::Error::KeyNotFound)), }, - Request::GetRandom { size } => self.rng_worker.get_random(size), + Request::GetRandom { data } => self.rng_worker.get_random(data), Request::EncryptChaChaPoly { key_id, nonce, aad, plaintext, + tag, } => { let mut key: ScrubOnDrop = ScrubOnDrop::new(); match &self.key_store { Some(key_store) => match key_store.get(key_id, &mut key.data) { Ok(size) => { let key = &key.data[..size]; - self.chachapoly_worker.encrypt(key, nonce, aad, plaintext) + self.chachapoly_worker + .encrypt(key, nonce, aad, plaintext, tag) } Err(e) => Response::Error(jobs::Error::KeyStore(e)), }, @@ -82,9 +84,10 @@ impl<'a, E: EntropySource> Scheduler<'a, E> { nonce, aad, plaintext, + tag, } => self .chachapoly_worker - .encrypt_external_key(key, nonce, aad, plaintext), + .encrypt_external_key(key, nonce, aad, plaintext, tag), Request::DecryptChaChaPoly { key_id, nonce, diff --git a/heimlig/src/hsm/scheduler/tests.rs b/heimlig/src/hsm/scheduler/tests.rs index eb038a9b..e77805f7 100644 --- a/heimlig/src/hsm/scheduler/tests.rs +++ b/heimlig/src/hsm/scheduler/tests.rs @@ -1,4 +1,6 @@ -use crate::common::jobs::{Error, Request, Response}; +use crate::common::jobs::{ + Error, ExternalMemory, InOutParam, InParam, OutParam, Request, Response, +}; use crate::common::limits::MAX_RANDOM_SIZE; use crate::common::pool::{Memory, Pool, PoolChunk}; use crate::config; @@ -32,8 +34,11 @@ fn get_random() { { config::keystore::NUM_KEYS }, >::try_new(&key_infos) .expect("failed to create key store"); + let data = pool.alloc(32).unwrap(); let mut scheduler = init_scheduler(&pool, &mut key_store); - let request = Request::GetRandom { size: 32 }; + let request = Request::GetRandom { + data: OutParam::new(ExternalMemory::from_slice(data.as_slice())), + }; let job = Job { channel_id: 0, request, @@ -46,7 +51,7 @@ fn get_random() { panic!("Unexpected response type"); } }; - assert_eq!(response_data.len(), 32); + assert_eq!(response_data.as_slice().len(), 32); } #[test] @@ -60,8 +65,9 @@ fn get_random_request_too_large() { >::try_new(&key_infos) .expect("failed to create key store"); let mut scheduler = init_scheduler(&pool, &mut key_store); + let data = [0u8; MAX_RANDOM_SIZE + 1]; let request = Request::GetRandom { - size: MAX_RANDOM_SIZE + 1, + data: OutParam::new(ExternalMemory::from_slice(data.as_slice())), }; let job = Job { channel_id: 0, @@ -74,7 +80,7 @@ fn get_random_request_too_large() { )) } -fn alloc_chachapoly_vars(pool: &Pool) -> (PoolChunk, PoolChunk, PoolChunk, PoolChunk) { +fn alloc_chachapoly_vars(pool: &Pool) -> (PoolChunk, PoolChunk, PoolChunk, PoolChunk, PoolChunk) { const KEY: &[u8; KEY_SIZE] = b"Fortuna Major or Oddsbodikins???"; const NONCE: &[u8; NONCE_SIZE] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; const PLAINTEXT: &[u8] = b"I solemnly swear I am up to no good!"; @@ -86,7 +92,10 @@ fn alloc_chachapoly_vars(pool: &Pool) -> (PoolChunk, PoolChunk, PoolChunk, PoolC aad.as_slice_mut().copy_from_slice(AAD); let mut plaintext = pool.alloc(PLAINTEXT.len()).unwrap(); plaintext.as_slice_mut().copy_from_slice(PLAINTEXT); - (key, nonce, aad, plaintext) + let tag = pool + .alloc(crate::crypto::chacha20poly1305::TAG_SIZE) + .unwrap(); + (key, nonce, aad, plaintext, tag) } #[test] @@ -102,10 +111,10 @@ fn encrypt_chachapoly() { let mut scheduler = init_scheduler(&pool, &mut key_store); // Import key - let (key, nonce, aad, plaintext) = alloc_chachapoly_vars(&pool); + let (key, nonce, aad, plaintext, tag) = alloc_chachapoly_vars(&pool); let request = Request::ImportKey { id: KEY3.id, - data: key, + data: InParam::new(ExternalMemory::from_slice(key.as_slice())), }; let job = Job { channel_id: 0, @@ -121,9 +130,10 @@ fn encrypt_chachapoly() { // Encrypt data let request = Request::EncryptChaChaPoly { key_id: KEY3.id, - nonce, - aad: Some(aad), - plaintext, + nonce: InParam::new(ExternalMemory::from_slice(nonce.as_slice())), + aad: Some(InParam::new(ExternalMemory::from_slice(aad.as_slice()))), + plaintext: InOutParam::new(ExternalMemory::from_slice(plaintext.as_slice())), + tag: OutParam::new(ExternalMemory::from_slice(tag.as_slice())), }; let job = Job { channel_id: 0, @@ -137,13 +147,13 @@ fn encrypt_chachapoly() { }; // Decrypt data - let (_key, nonce, aad, org_plaintext) = alloc_chachapoly_vars(&pool); + let (_key, nonce, aad, org_plaintext, _) = alloc_chachapoly_vars(&pool); let request = Request::DecryptChaChaPoly { key_id: KEY3.id, - nonce, - aad: Some(aad), + nonce: InParam::new(ExternalMemory::from_slice(nonce.as_slice())), + aad: Some(InParam::new(ExternalMemory::from_slice(aad.as_slice()))), ciphertext, - tag, + tag: InParam::new(ExternalMemory::from_slice(tag.as_slice())), }; let job = Job { channel_id: 0, @@ -171,12 +181,13 @@ fn encrypt_chachapoly_external_key() { let mut scheduler = init_scheduler(&pool, &mut key_store); // Encrypt data - let (key, nonce, aad, plaintext) = alloc_chachapoly_vars(&pool); + let (key, nonce, aad, plaintext, tag) = alloc_chachapoly_vars(&pool); let request = Request::EncryptChaChaPolyExternalKey { - key, - nonce, - aad: Some(aad), - plaintext, + key: InParam::new(ExternalMemory::from_slice(key.as_slice())), + nonce: InParam::new(ExternalMemory::from_slice(nonce.as_slice())), + aad: Some(InParam::new(ExternalMemory::from_slice(aad.as_slice()))), + plaintext: InOutParam::new(ExternalMemory::from_slice(plaintext.as_slice())), + tag: OutParam::new(ExternalMemory::from_slice(tag.as_slice())), }; let job = Job { channel_id: 0, @@ -190,13 +201,13 @@ fn encrypt_chachapoly_external_key() { }; // Decrypt data - let (key, nonce, aad, org_plaintext) = alloc_chachapoly_vars(&pool); + let (key, nonce, aad, org_plaintext, _) = alloc_chachapoly_vars(&pool); let request = Request::DecryptChaChaPolyExternalKey { - key, - nonce, - aad: Some(aad), + key: InParam::new(ExternalMemory::from_slice(key.as_slice())), + nonce: InParam::new(ExternalMemory::from_slice(nonce.as_slice())), + aad: Some(InParam::new(ExternalMemory::from_slice(aad.as_slice()))), ciphertext, - tag, + tag: InParam::new(ExternalMemory::from_slice(tag.as_slice())), }; let job = Job { channel_id: 0, @@ -210,3 +221,38 @@ fn encrypt_chachapoly_external_key() { }; assert_eq!(plaintext.as_slice(), org_plaintext.as_slice()) } + +#[test] +fn encrypt_chachapoly_invalid_tag_size() { + static mut MEMORY: Memory = [0; Pool::required_memory()]; + let pool = Pool::try_from(unsafe { &mut MEMORY }).unwrap(); + let key_infos = [KEY1, KEY2, KEY3]; + let mut key_store = MemoryKeyStore::< + { config::keystore::TOTAL_SIZE }, + { config::keystore::NUM_KEYS }, + >::try_new(&key_infos) + .expect("failed to create key store"); + let mut scheduler = init_scheduler(&pool, &mut key_store); + + // Encrypt data + let (key, nonce, aad, plaintext, _) = alloc_chachapoly_vars(&pool); + let tag = pool + .alloc(crate::crypto::chacha20poly1305::TAG_SIZE + 1) + .expect("failed to allocate invalid tag"); + let request = Request::EncryptChaChaPolyExternalKey { + key: InParam::new(ExternalMemory::from_slice(key.as_slice())), + nonce: InParam::new(ExternalMemory::from_slice(nonce.as_slice())), + aad: Some(InParam::new(ExternalMemory::from_slice(aad.as_slice()))), + plaintext: InOutParam::new(ExternalMemory::from_slice(plaintext.as_slice())), + tag: OutParam::new(ExternalMemory::from_slice(tag.as_slice())), + }; + let job = Job { + channel_id: 0, + request, + }; + + assert_eq!( + Response::Error(Error::Crypto(crate::crypto::Error::InvalidTagSize)), + scheduler.schedule(job).response + ); +} diff --git a/heimlig/src/hsm/workers/chachapoly_worker.rs b/heimlig/src/hsm/workers/chachapoly_worker.rs index 19be9737..bb248be5 100644 --- a/heimlig/src/hsm/workers/chachapoly_worker.rs +++ b/heimlig/src/hsm/workers/chachapoly_worker.rs @@ -1,5 +1,5 @@ -use crate::common::jobs::{Error, Response}; -use crate::common::pool::{Pool, PoolChunk}; +use crate::common::jobs::{Error, InOutParam, InParam, OutParam, Response}; +use crate::common::pool::Pool; pub struct ChachaPolyWorker<'a> { pub pool: &'a Pool, @@ -8,54 +8,49 @@ pub struct ChachaPolyWorker<'a> { impl<'a> ChachaPolyWorker<'a> { pub fn encrypt_external_key( &mut self, - key: PoolChunk, - nonce: PoolChunk, - aad: Option, - ciphertext: PoolChunk, + key: InParam, + nonce: InParam, + aad: Option, + ciphertext: InOutParam, + tag: OutParam, ) -> Response { - self.encrypt(key.as_slice(), nonce, aad, ciphertext) + self.encrypt(key.as_slice(), nonce, aad, ciphertext, tag) } pub fn encrypt( &mut self, key: &[u8], - nonce: PoolChunk, - aad: Option, - mut ciphertext: PoolChunk, + nonce: InParam, + aad: Option, + mut ciphertext: InOutParam, + mut tag: OutParam, ) -> Response { - match self.pool.alloc(crate::crypto::chacha20poly1305::TAG_SIZE) { - Err(_) => Response::Error(Error::Alloc), - Ok(mut tag) => { - let aad = match &aad { - Some(aad) => aad.as_slice(), - None => &[] as &[u8], - }; - match crate::crypto::chacha20poly1305::encrypt_in_place_detached( - key, - nonce.as_slice(), - aad, - ciphertext.as_slice_mut(), - ) { - Ok(computed_tag) => { - if computed_tag.len() != tag.as_slice().len() { - return Response::Error(Error::Alloc); - } - tag.as_slice_mut().copy_from_slice(computed_tag.as_slice()); - Response::EncryptChaChaPoly { ciphertext, tag } - } - Err(e) => Response::Error(Error::Crypto(e)), + let aad = aad.unwrap_or_default(); + match crate::crypto::chacha20poly1305::encrypt_in_place_detached( + key, + nonce.as_slice(), + aad.as_slice(), + ciphertext.as_mut_slice(), + ) { + Ok(computed_tag) => { + if computed_tag.len() != tag.as_slice().len() { + return Response::Error(Error::Crypto(crate::crypto::Error::InvalidTagSize)); } + + tag.as_mut_slice().copy_from_slice(computed_tag.as_slice()); + Response::EncryptChaChaPoly { ciphertext, tag } } + Err(e) => Response::Error(Error::Crypto(e)), } } pub fn decrypt_external_key( &mut self, - key: PoolChunk, - nonce: PoolChunk, - aad: Option, - plaintext: PoolChunk, - tag: PoolChunk, + key: InParam, + nonce: InParam, + aad: Option, + plaintext: InOutParam, + tag: InParam, ) -> Response { self.decrypt(key.as_slice(), nonce, aad, plaintext, tag) } @@ -63,20 +58,17 @@ impl<'a> ChachaPolyWorker<'a> { pub fn decrypt( &mut self, key: &[u8], - nonce: PoolChunk, - aad: Option, - mut plaintext: PoolChunk, - tag: PoolChunk, + nonce: InParam, + aad: Option, + mut plaintext: InOutParam, + tag: InParam, ) -> Response { - let aad = match &aad { - Some(aad) => aad.as_slice(), - None => &[] as &[u8], - }; + let aad = aad.unwrap_or_default(); match crate::crypto::chacha20poly1305::decrypt_in_place_detached( key, nonce.as_slice(), - aad, - plaintext.as_slice_mut(), + aad.as_slice(), + plaintext.as_mut_slice(), tag.as_slice(), ) { Ok(()) => Response::DecryptChaChaPoly { plaintext }, diff --git a/heimlig/src/hsm/workers/rng_worker.rs b/heimlig/src/hsm/workers/rng_worker.rs index f00470bd..55ad336f 100644 --- a/heimlig/src/hsm/workers/rng_worker.rs +++ b/heimlig/src/hsm/workers/rng_worker.rs @@ -1,5 +1,5 @@ use crate::common::jobs::Response::GetRandom; -use crate::common::jobs::{Error, Response}; +use crate::common::jobs::{Error, OutParam, Response}; use crate::common::limits::MAX_RANDOM_SIZE; use crate::common::pool::Pool; use crate::crypto::rng::{EntropySource, Rng}; @@ -11,16 +11,12 @@ pub struct RngWorker<'a, E: EntropySource> { } impl<'a, E: EntropySource> RngWorker<'a, E> { - pub fn get_random(&mut self, size: usize) -> Response { - if size >= MAX_RANDOM_SIZE { + pub fn get_random(&mut self, mut data: OutParam) -> Response { + let data_slice = data.as_mut_slice(); + if data_slice.len() >= MAX_RANDOM_SIZE { return Response::Error(Error::RequestTooLarge); } - match self.pool.alloc(size) { - Err(_) => Response::Error(Error::Alloc), - Ok(mut chunk) => { - self.rng.fill_bytes(chunk.as_slice_mut()); - GetRandom { data: chunk } - } - } + self.rng.fill_bytes(data_slice); + GetRandom { data } } } diff --git a/heimlig/tests/api_core_integration.rs b/heimlig/tests/api_core_integration.rs index 9e451ae4..c9ad26a3 100644 --- a/heimlig/tests/api_core_integration.rs +++ b/heimlig/tests/api_core_integration.rs @@ -1,7 +1,7 @@ mod test { use heapless::spsc::{Consumer, Producer, Queue}; use heimlig::client::api::Api; - use heimlig::common::jobs::{Request, Response}; + use heimlig::common::jobs::{ExternalMemory, OutParam, Request, Response}; use heimlig::common::pool::{Memory, Pool}; use heimlig::config::keystore::{KEY1, KEY2, KEY3}; use heimlig::crypto::rng::{EntropySource, Rng}; @@ -96,14 +96,15 @@ mod test { // Send request let random_size = 16; - api.get_random(random_size) + let data = pool.alloc(random_size).expect("failed to allocate data"); + api.get_random(OutParam::new(ExternalMemory::from_slice(data.as_slice()))) .expect("failed to call randomness API"); core.process_next().expect("failed to process next request"); // Receive response let response = api.recv_response().expect("failed to receive response"); match response { - Response::GetRandom { data } => assert_eq!(data.len(), random_size), + Response::GetRandom { data } => assert_eq!(data.as_slice().len(), random_size), _ => panic!("Unexpected response type"), } }