pub struct SecureVec<T>where
T: Zeroize,{ /* private fields */ }Expand description
A securely allocated, growable vector, just like std::vec::Vec.
§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 vector is dropped.
- Memory Locking: The underlying memory pages are locked using
mlock&madvisefor (Unix) orVirtualLock&VirtualProtectfor (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 on Direct Access
We intentionally do not implement Index / IndexMut.
Using secure_vec[0] is a compile error.
This is by design: direct indexing would allow bypassing the explicit
unlock mechanism. Always use unlock_slice() / unlock_slice_mut() (or
the unlock* family of methods) to access the contents.
§Thread Safety
SecureVec is Send (it can be moved to another thread) but not Sync.
unlock* changes 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<SecureVec<T>>>.
§Notes
If you return a new allocated Vec from one of the unlock methods you are responsible for zeroizing the memory.
§Example
Using SecureBytes (a type alias for SecureVec<u8>) to handle a secret key.
use secure_types::{SecureBytes, Zeroize};
// Create a new, empty secure vector.
let mut secret_key = SecureBytes::new().unwrap();
// Push some sensitive data into it.
secret_key.push(0xAB);
secret_key.push(0xCD);
secret_key.push(0xEF);
// The memory is locked here.
// Use a scope to safely access the contents as a slice.
secret_key.unlock_slice(|unlocked_slice| {
assert_eq!(unlocked_slice, &[0xAB, 0xCD, 0xEF]);
});
// Not recommended but if you allocate a new Vec make sure to zeroize it
let mut exposed = secret_key.unlock_slice(|unlocked_slice| {
Vec::from(unlocked_slice)
});
// Do what you need to to do with the new vector
// When you are done with it, zeroize it
exposed.zeroize();
// The memory is automatically locked again when the scope ends.
// When `secret_key` is dropped, its memory is securely zeroized.Implementations§
Source§impl<T: Zeroize> SecureVec<T>
impl<T: Zeroize> SecureVec<T>
Sourcepub fn new_with_capacity(capacity: usize) -> Result<Self, Error>
pub fn new_with_capacity(capacity: usize) -> Result<Self, Error>
Create a new SecureVec with the given capacity
Sourcepub fn from_vec(vec: Vec<T>) -> Result<Self, Error>
pub fn from_vec(vec: Vec<T>) -> Result<Self, Error>
Create a new SecureVec from a Vec
The Vec is zeroized afterwards
Sourcepub fn from_slice_mut(slice: &mut [T]) -> Result<Self, Error>where
T: Clone + DefaultIsZeroes,
pub fn from_slice_mut(slice: &mut [T]) -> Result<Self, Error>where
T: Clone + DefaultIsZeroes,
Create a new SecureVec from a mutable slice.
The slice is zeroized afterwards
Sourcepub fn from_slice(slice: &[T]) -> Result<Self, Error>where
T: Clone,
pub fn from_slice(slice: &[T]) -> Result<Self, Error>where
T: Clone,
Create a new SecureVec from a slice.
The slice is not zeroized, you are responsible for zeroizing it
pub fn len(&self) -> usize
Sourcepub fn capacity(&self) -> usize
pub fn capacity(&self) -> usize
The number of elements the locked allocation can hold before it grows.
The allocation is re-mprotected on every growth, so this is also the number of
elements that can be pushed before another unlock/lock cycle.
pub fn is_empty(&self) -> bool
Sourcepub fn unlock<F, R>(&self, f: F) -> R
pub fn unlock<F, R>(&self, f: F) -> R
Immutable access to the SecureVec
§Re-entrancy
The closure must not call another unlock* method on this vector: the
pages are unprotected once and re-protected when this call returns, so a
nested unlock would re-lock the memory while the inner scope is still
reading it. The same holds for every unlock* method.
Sourcepub fn unlock_slice<F, R>(&self, f: F) -> R
pub fn unlock_slice<F, R>(&self, f: F) -> R
Immutable access to the SecureVec as &[T]
Sourcepub fn unlock_slice_mut<F, R>(&mut self, f: F) -> R
pub fn unlock_slice_mut<F, R>(&mut self, f: F) -> R
Mutable access to the SecureVec as &mut [T]
Sourcepub fn unlock_iter<F, R>(&self, f: F) -> R
pub fn unlock_iter<F, R>(&self, f: F) -> R
Immutable access to the SecureVec as Iter<T>
Sourcepub fn unlock_iter_mut<F, R>(&mut self, f: F) -> R
pub fn unlock_iter_mut<F, R>(&mut self, f: F) -> R
Mutable access to the SecureVec as IterMut<T>
Sourcepub fn erase(&mut self)
pub fn erase(&mut self)
Erase the underlying data and clears the vector
The memory is locked again and the capacity is preserved for reuse
Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Clear the vector
This just sets the vector’s len to zero it does not erase the underlying data
pub fn push(&mut self, value: T)
Sourcepub fn reserve(&mut self, additional: usize)
pub fn reserve(&mut self, additional: usize)
Ensures that the vector has enough capacity for at least additional more elements.
If more capacity is needed, it will reallocate. This may cause the buffer location to change.
§Panics
Panics if the new capacity overflows usize or if the allocation fails.
Sourcepub fn drain<R>(&mut self, range: R) -> Drain<'_, T> ⓘwhere
R: RangeBounds<usize>,
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T> ⓘwhere
R: RangeBounds<usize>,
Creates a draining iterator that removes the specified range from the vector and yields the removed items.
Note: the memory is only unlocked while an item is read and while the iterator
is dropped, so it is left locked once the iterator is gone even if the
iterator is leaked with mem::forget.
§Panics
Panics if the starting point is greater than the end point or if the end point is greater than the length of the vector.
Trait Implementations§
Source§impl<T: Clone + Zeroize, const LENGTH: usize> From<SecureArray<T, LENGTH>> for SecureVec<T>
impl<T: Clone + Zeroize, const LENGTH: usize> From<SecureArray<T, LENGTH>> for SecureVec<T>
Source§fn from(array: SecureArray<T, LENGTH>) -> Self
fn from(array: SecureArray<T, LENGTH>) -> Self
§Panics
Panics if the new secure allocation cannot be made or locked.
impl<T: Zeroize + Send> Send for SecureVec<T>
Source§impl<T: Clone + Zeroize, const LENGTH: usize> TryFrom<SecureVec<T>> for SecureArray<T, LENGTH>
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>
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.