Skip to main content

SecureArray

Struct SecureArray 

Source
pub struct SecureArray<T, const LENGTH: usize>
where T: Zeroize,
{ /* private fields */ }
Expand description

A fixed-size array allocated in a secure memory region.

§Security Model

When compiled with the use_os feature (the default), it provides several layers of protection:

  • Zeroization on Drop: The memory is zeroized when the array is dropped.
  • Memory Locking: The underlying memory pages are locked using mlock & madvise for (Unix) or VirtualLock & VirtualProtect for (Windows) to prevent the OS from memory-dump/swap to disk or other processes accessing the memory.

In a no_std environment, it falls back to providing only the zeroization-on-drop guarantee.

§Security Note

We intentionally do not implement Index or IndexMut. array[0] is a compile error.

Always use .unlock() / .unlock_mut() (or the slice variants) to access data.

§Thread Safety

SecureArray is Send (it can be moved to another thread) but not Sync. unlock / unlock_mut change the allocation’s page protection, so two threads unlocking the same instance would race (one can relock while the other still holds a live slice). Share it as Arc<Mutex<SecureArray<...>>>.

§Notes

If you return a new allocated [T; LENGTH] from one of the unlock methods you are responsible for zeroizing the memory.

§Example

use secure_types::{SecureArray, Zeroize};

let exposed_key: &mut [u8; 32] = &mut [1u8; 32];
let secure_key: SecureArray<u8, 32> = SecureArray::from_slice_mut(exposed_key).unwrap();

secure_key.unlock(|unlocked_slice| {
    assert_eq!(unlocked_slice.len(), 32);
    assert_eq!(unlocked_slice[0], 1);
});

// Not recommended but if you allocate a new [u8; LENGTH] make sure to zeroize it
let mut exposed = secure_key.unlock(|unlocked_slice| {
    [unlocked_slice[0], unlocked_slice[1], unlocked_slice[2]]
});

// Do what you need to to do with the new array
// When you are done with it, zeroize it
exposed.zeroize();

Implementations§

Source§

impl<T, const LENGTH: usize> SecureArray<T, LENGTH>
where T: Zeroize,

Source

pub fn empty() -> Result<Self, Error>

Creates an empty (but allocated) SecureArray.

The memory is allocated but not initialized, and it’s the caller’s responsibility to fill it.

Only elements that are actually written are tracked as initialized: drop and erase zeroize just those, so dropping an array that was never filled is sound. The remaining slots still hold the allocator’s poison bytes and must never be read as a T. Initialize the whole array (for example through unlock_mut) before accessing it.

Source

pub fn from_slice_mut(content: &mut [T; LENGTH]) -> Result<Self, Error>
where T: Clone,

Creates a new SecureArray from a &mut [T; LENGTH].

The passed slice is zeroized afterwards

Source

pub fn from_slice(content: &[T; LENGTH]) -> Result<Self, Error>
where T: Clone,

Creates a new SecureArray from a &[T; LENGTH].

The array is not zeroized, you are responsible for zeroizing it

Source

pub fn len(&self) -> usize

Source

pub fn is_empty(&self) -> bool

Source

pub fn unlock<F, R>(&self, f: F) -> R
where F: FnOnce(&[T]) -> R,

Immutable access to the array’s data as a &[T]

The slice covers exactly the elements that have been initialized: LENGTH for any array built through a constructor or unlock_mut, and empty for an empty array that was never filled (see its contract).

Source

pub fn unlock_mut<F, R>(&mut self, f: F) -> R
where F: FnOnce(&mut [T]) -> R,

Mutable access to the array’s data as a &mut [T]

Exposing the whole array as a &mut [T] treats every slot as initialized storage, so a later drop / erase zeroizes all LENGTH elements.

Source

pub fn erase(&mut self)

Securely erases the contents of the array by zeroizing the initialized elements.

Trait Implementations§

Source§

impl<T: Clone + Zeroize, const LENGTH: usize> Clone for SecureArray<T, LENGTH>

Source§

fn clone(&self) -> Self

§Panics

Panics if the clone’s secure allocation cannot be made or locked.

1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Zeroize, const LENGTH: usize> Drop for SecureArray<T, LENGTH>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<T: Clone + Zeroize, const LENGTH: usize> From<SecureArray<T, LENGTH>> for SecureVec<T>

Source§

fn from(array: SecureArray<T, LENGTH>) -> Self

§Panics

Panics if the new secure allocation cannot be made or locked.

Source§

impl<T: Zeroize + Send, const LENGTH: usize> Send for SecureArray<T, LENGTH>

Source§

impl<T: Clone + Zeroize, const LENGTH: usize> TryFrom<SecureVec<T>> for SecureArray<T, LENGTH>

Source§

fn try_from(vec: SecureVec<T>) -> Result<Self, Self::Error>

Tries to convert a SecureVec<T> into a SecureArray<T, LENGTH>.

This operation will only succeed if vec.len() == LENGTH. LENGTH is a compile-time constant on the destination type, it cannot be taken from the vector’s runtime length.

The SecureVec is consumed.

Source§

type Error = Error

The type returned in the event of a conversion error.
Source§

impl<T: Clone + Zeroize, const LENGTH: usize> TryFrom<Vec<T>> for SecureArray<T, LENGTH>

Source§

fn try_from(vec: Vec<T>) -> Result<Self, Self::Error>

Tries to convert a Vec<T> into a SecureArray<T, LENGTH>.

This operation will only succeed if vec.len() == LENGTH. LENGTH is a compile-time constant on the destination type, it cannot be taken from the vector’s runtime length.

The Vec is consumed and zeroized.

Source§

type Error = Error

The type returned in the event of a conversion error.

Auto Trait Implementations§

§

impl<T, const LENGTH: usize> !Sync for SecureArray<T, LENGTH>

§

impl<T, const LENGTH: usize> Freeze for SecureArray<T, LENGTH>

§

impl<T, const LENGTH: usize> RefUnwindSafe for SecureArray<T, LENGTH>

§

impl<T, const LENGTH: usize> Unpin for SecureArray<T, LENGTH>
where NonNull<T>: Unpin, PhantomData<T>: Unpin,

§

impl<T, const LENGTH: usize> UnsafeUnpin for SecureArray<T, LENGTH>

§

impl<T, const LENGTH: usize> UnwindSafe for SecureArray<T, LENGTH>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.