// Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //! Types and functions to help with memory buffer management. use crate::constants::*; use crate::error::{DpeResult, ErrCode}; use heapless::Vec; use zeroize::ZeroizeOnDrop; /// Creates a byte array wrapper type for the sake of precise typing. #[macro_export] macro_rules! byte_array_wrapper { ($type_name:ident, $len:ident, $desc:expr) => { #[doc = "A byte array wrapper to represent a "] #[doc = $desc] #[doc = "."] #[derive(Clone, Debug, Eq, PartialEq, Hash, ZeroizeOnDrop)] pub struct $type_name([u8; $len]); impl $type_name { #[doc = "Returns the length of the array."] pub fn len(&self) -> usize { self.0.len() } #[doc = "Whether the array is empty."] pub fn is_empty(&self) -> bool { self.0.is_empty() } #[doc = "Borrows the array as a slice."] pub fn as_slice(&self) -> &[u8] { self.0.as_slice() } #[doc = "Mutably borrows the array as a slice."] pub fn as_mut_slice(&mut self) -> &mut [u8] { &mut self.0 } #[doc = "Borrows the array."] pub fn as_array(&self) -> &[u8; $len] { &self.0 } #[doc = "Creates a "] #[doc = stringify!($type_name)] #[doc = " from a slice. Fails if the slice length is not "] #[doc = stringify!($len)] #[doc = "."] pub fn from_slice(s: &[u8]) -> DpeResult { Self::try_from(s) } #[doc = "Creates a "] #[doc = stringify!($type_name)] #[doc = " from a slice infallibly. If the length of the slice is less than "] #[doc = stringify!($len)] #[doc = ", the remainder of the array is the default value. If the length "] #[doc = "of the slice is more than "] #[doc = stringify!($len)] #[doc = ", only the first "] #[doc = stringify!($len)] #[doc = " bytes are used. This method is infallible."] pub fn from_slice_infallible(value: &[u8]) -> Self { #![allow(clippy::indexing_slicing)] let mut tmp: Self = Default::default(); if value.len() < $len { tmp.0[..value.len()].copy_from_slice(value); } else { tmp.0.copy_from_slice(&value[..$len]); } tmp } #[doc = "Creates a "] #[doc = stringify!($type_name)] #[doc = " from an array."] pub fn from_array(value: &[u8; $len]) -> Self { Self(*value) } } impl Default for $type_name { fn default() -> Self { Self([0; $len]) } } impl TryFrom<&[u8]> for $type_name { type Error = $crate::error::ErrCode; fn try_from(value: &[u8]) -> Result { value.try_into().map(Self).map_err(|_| { log::error!("Invalid length for fixed length value: {}", $desc); $crate::error::ErrCode::InvalidArgument }) } } impl From<[u8; $len]> for $type_name { fn from(value: [u8; $len]) -> Self { Self(value) } } }; } /// Wraps a [heapless::Vec] of bytes and provides various convenience methods /// that are useful when processing DPE messages. The inner `vec` is also /// accessible directly. #[derive(Clone, Debug, Default, Eq, PartialEq, Hash, ZeroizeOnDrop)] pub struct SizedMessage { /// The wrapped Vec. pub vec: Vec, } impl SizedMessage { /// Creates a new, empty instance. /// /// # Example /// /// ```rust /// type MyMessage = dpe_rs::memory::SizedMessage<200>; /// /// assert_eq!(MyMessage::new().len(), 0); /// ``` pub fn new() -> Self { Default::default() } /// Creates a new instance from a slice. /// /// # Errors /// /// If `value` exceeds the available capacity, returns an OutOfMemory error. /// /// # Example /// /// ```rust /// type MyMessage = dpe_rs::memory::SizedMessage<200>; /// /// assert_eq!(MyMessage::from_slice(&[0; 12]).unwrap().as_slice(), &[0; 12]); /// ``` pub fn from_slice(value: &[u8]) -> DpeResult { Ok(Self { vec: Vec::from_slice(value).map_err(|_| ErrCode::OutOfMemory)?, }) } /// Clones `slice`, replacing any existing content. /// /// # Errors /// /// If `slice` exceeds the available capacity, returns an OutOfMemory error. /// /// # Example /// /// ```rust /// type MyMessage = dpe_rs::memory::SizedMessage<200>; /// /// let mut m = MyMessage::from_slice(&[0; 12]).unwrap(); /// m.clone_from_slice(&[1; 3]).unwrap(); /// assert_eq!(m.as_slice(), &[1; 3]); /// ``` pub fn clone_from_slice(&mut self, slice: &[u8]) -> DpeResult<()> { self.clear(); self.vec.extend_from_slice(slice).map_err(|_| ErrCode::OutOfMemory) } /// Borrows the inner byte array. pub fn as_slice(&self) -> &[u8] { self.vec.as_slice() } /// Mutably borrows the inner byte array after resizing. This is useful when /// using the type as an output buffer. /// /// # Errors /// /// If `size` exceeds the available capacity, returns an OutOfMemory error. /// /// # Example /// /// ```rust /// use rand_core::{RngCore, SeedableRng}; /// /// type MyMessage = dpe_rs::memory::SizedMessage<200>; /// /// let mut buffer = MyMessage::new(); /// ::seed_from_u64(0) /// .fill_bytes(buffer.as_mut_sized(100).unwrap()); /// assert_eq!(buffer.len(), 100); /// ``` pub fn as_mut_sized(&mut self, size: usize) -> DpeResult<&mut [u8]> { self.vec.resize_default(size).map_err(|_| ErrCode::OutOfMemory)?; Ok(self.vec.as_mut()) } /// Returns the length of the inner vec. pub fn len(&self) -> usize { self.vec.len() } /// Whether the inner vec is empty. pub fn is_empty(&self) -> bool { self.vec.is_empty() } /// Clears the inner vec. pub fn clear(&mut self) { self.vec.clear() } /// Removes the first `prefix_size` bytes from the message. This carries the /// cost of moving the remaining bytes to the front of the buffer. /// /// # Errors /// /// If `prefix_size` is larger than the current length, returns an /// InternalError error. /// /// # Example /// /// ```rust /// type MyMessage = dpe_rs::memory::SizedMessage<200>; /// /// let mut m = MyMessage::from_slice("prefixdata".as_bytes()).unwrap(); /// m.remove_prefix(6).unwrap(); /// assert_eq!(m.as_slice(), "data".as_bytes()); /// ``` pub fn remove_prefix(&mut self, prefix_size: usize) -> DpeResult<()> { if prefix_size > self.len() { return Err(ErrCode::InternalError); } if prefix_size == self.len() { self.clear(); } else if prefix_size > 0 { let slice: &mut [u8] = self.vec.as_mut(); slice.copy_within(prefix_size.., 0); self.vec.truncate(self.len() - prefix_size); } Ok(()) } /// Inserts `prefix` at the start of the message. This carries the cost of /// moving the existing bytes to make room for the prefix. /// /// # Errors /// /// If inserting `prefix` overflows the available capacity, returns an /// OutOfMemory error. /// /// # Example /// /// ```rust /// type MyMessage = dpe_rs::memory::SizedMessage<200>; /// /// let mut m = MyMessage::from_slice("data".as_bytes()).unwrap(); /// m.insert_prefix("prefix".as_bytes()).unwrap(); /// assert_eq!(m.as_slice(), "prefixdata".as_bytes()); /// ``` pub fn insert_prefix(&mut self, prefix: &[u8]) -> DpeResult<()> { let old_len = self.len(); self.vec .resize_default(self.len() + prefix.len()) .map_err(|_| ErrCode::OutOfMemory)?; let slice: &mut [u8] = self.vec.as_mut(); slice.copy_within(0..old_len, prefix.len()); slice .get_mut(..prefix.len()) .ok_or(ErrCode::InternalError)? .copy_from_slice(prefix); Ok(()) } } /// Represents a DPE command/response message. This type is large and should not /// be instantiated unnecessarily. pub type Message = SizedMessage;