secure_types/
vec.rs

1#[cfg(not(feature = "std"))]
2use alloc::{Layout, alloc, dealloc};
3
4#[cfg(feature = "std")]
5use std::vec::Vec;
6
7use super::{Error, SecureArray};
8use core::{
9   marker::PhantomData,
10   mem,
11   ops::{Bound, RangeBounds},
12   ptr::{self, NonNull},
13};
14use zeroize::{DefaultIsZeroes, Zeroize};
15
16#[cfg(feature = "std")]
17use super::page_size;
18#[cfg(feature = "std")]
19use memsec::Prot;
20
21pub type SecureBytes = SecureVec<u8>;
22
23/// A securely allocated, growable vector, analogous to `std::vec::Vec`.
24///
25/// `SecureVec<T>` is designed to hold a sequence of sensitive data elements. It serves as the
26/// foundational secure collection in this crate.
27///
28/// ## Security Model
29///
30/// When compiled with the `std` feature (the default), it provides several layers of protection:
31/// - **Zeroization on Drop**: The memory region is securely zeroized when the vector is dropped.
32/// - **Memory Locking**: The underlying memory pages are locked using `mlock` (Unix) or
33///   `VirtualLock` (Windows) to prevent the OS from swapping them to disk.
34/// - **Memory Encryption**: On Windows, the memory is also encrypted using `CryptProtectMemory`.
35///
36/// In a `no_std` environment, it falls back to providing only the **zeroization-on-drop** guarantee.
37///
38/// ## Program Termination
39///
40/// Direct indexing (e.g., `vec[0]`) on a locked vector will cause the operating system
41/// to terminate the process with an access violation error.
42///
43/// Always use the provided scope methods (`slice_scope`, `slice_mut_scope`) for safe access.
44///
45/// # Examples
46///
47/// Using `SecureBytes` (a type alias for `SecureVec<u8>`) to handle a secret key.
48///
49/// ```
50/// use secure_types::SecureBytes;
51///
52/// // Create a new, empty secure vector.
53/// let mut secret_key = SecureBytes::new().unwrap();
54///
55/// // Push some sensitive data into it.
56/// secret_key.push(0xAB);
57/// secret_key.push(0xCD);
58/// secret_key.push(0xEF);
59///
60/// // The memory is locked here.
61///
62/// // Use a scope to safely access the contents as a slice.
63/// secret_key.slice_scope(|unlocked_slice| {
64///     assert_eq!(unlocked_slice, &[0xAB, 0xCD, 0xEF]);
65///     println!("Secret Key: {:?}", unlocked_slice);
66/// });
67///
68/// // The memory is automatically locked again when the scope ends.
69///
70/// // When `secret_key` is dropped, its memory is securely zeroized.
71/// ```
72pub struct SecureVec<T>
73where
74   T: Zeroize,
75{
76   ptr: NonNull<T>,
77   pub(crate) len: usize,
78   pub(crate) capacity: usize,
79   _marker: PhantomData<T>,
80}
81
82unsafe impl<T: Zeroize + Send> Send for SecureVec<T> {}
83unsafe impl<T: Zeroize + Send + Sync> Sync for SecureVec<T> {}
84
85impl<T: Zeroize> SecureVec<T> {
86   pub fn new() -> Result<Self, Error> {
87      // Give at least a capacity of 1 so encryption/decryption can be done.
88      let capacity = 1;
89      let size = capacity * mem::size_of::<T>();
90
91      #[cfg(feature = "std")]
92      let ptr = unsafe {
93         let aligned_size = (size + page_size() - 1) & !(page_size() - 1);
94         let allocated_ptr = memsec::malloc_sized(aligned_size);
95         let ptr = allocated_ptr.ok_or(Error::AllocationFailed)?;
96         ptr.as_ptr() as *mut T
97      };
98
99      #[cfg(not(feature = "std"))]
100      let ptr = {
101         let layout = Layout::from_size_align(size, mem::align_of::<T>())
102            .map_err(|_| Error::AllocationFailed)?;
103         let ptr = unsafe { alloc::alloc(layout) as *mut T };
104         if ptr.is_null() {
105            return Err(Error::AllocationFailed);
106         }
107         ptr
108      };
109
110      let non_null = NonNull::new(ptr).ok_or(Error::NullAllocation)?;
111      let secure = SecureVec {
112         ptr: non_null,
113         len: 0,
114         capacity,
115         _marker: PhantomData,
116      };
117
118      let (encrypted, locked) = secure.lock_memory();
119
120      #[cfg(feature = "std")]
121      if !locked {
122         return Err(Error::LockFailed);
123      }
124
125      #[cfg(feature = "std")]
126      if !encrypted {
127         return Err(Error::CryptProtectMemoryFailed);
128      }
129
130      Ok(secure)
131   }
132
133   pub fn new_with_capacity(mut capacity: usize) -> Result<Self, Error> {
134      if capacity == 0 {
135         capacity = 1;
136      }
137
138      let size = capacity * mem::size_of::<T>();
139
140      #[cfg(feature = "std")]
141      let ptr = unsafe {
142         let aligned_size = (size + page_size() - 1) & !(page_size() - 1);
143         let allocated_ptr = memsec::malloc_sized(aligned_size);
144         let ptr = allocated_ptr.ok_or(Error::AllocationFailed)?;
145         ptr.as_ptr() as *mut T
146      };
147
148      #[cfg(not(feature = "std"))]
149      let ptr = {
150         let layout = Layout::from_size_align(size, mem::align_of::<T>())
151            .map_err(|_| Error::AllocationFailed)?;
152         let ptr = unsafe { alloc::alloc(layout) as *mut T };
153         if ptr.is_null() {
154            return Err(Error::AllocationFailed);
155         }
156         ptr
157      };
158
159      let non_null = NonNull::new(ptr).ok_or(Error::NullAllocation)?;
160
161      let secure = SecureVec {
162         ptr: non_null,
163         len: 0,
164         capacity,
165         _marker: PhantomData,
166      };
167
168      let (encrypted, locked) = secure.lock_memory();
169
170      #[cfg(feature = "std")]
171      if !locked {
172         return Err(Error::LockFailed);
173      }
174
175      #[cfg(feature = "std")]
176      if !encrypted {
177         return Err(Error::CryptProtectMemoryFailed);
178      }
179
180      Ok(secure)
181   }
182
183   #[cfg(feature = "std")]
184   pub fn from_vec(mut vec: Vec<T>) -> Result<Self, Error> {
185      if vec.capacity() == 0 {
186         vec.reserve(1);
187      }
188
189      let capacity = vec.capacity();
190      let len = vec.len();
191
192      // Allocate memory
193      let size = capacity * mem::size_of::<T>();
194
195      let ptr = unsafe {
196         let aligned_size = (size + page_size() - 1) & !(page_size() - 1);
197         let allocated_ptr = memsec::malloc_sized(aligned_size);
198         if allocated_ptr.is_none() {
199            vec.zeroize();
200            return Err(Error::AllocationFailed);
201         } else {
202            allocated_ptr.unwrap().as_ptr() as *mut T
203         }
204      };
205
206      // Copy data from the old pointer to the new one
207      unsafe {
208         core::ptr::copy_nonoverlapping(vec.as_ptr(), ptr, len);
209      }
210
211      // Zeroize and drop the original Vec
212      vec.zeroize();
213      drop(vec);
214
215      let non_null = NonNull::new(ptr).ok_or(Error::NullAllocation)?;
216
217      let secure = SecureVec {
218         ptr: non_null,
219         len,
220         capacity,
221         _marker: PhantomData,
222      };
223
224      let (encrypted, locked) = secure.lock_memory();
225
226      if !locked {
227         return Err(Error::LockFailed);
228      }
229
230      if !encrypted {
231         return Err(Error::CryptProtectMemoryFailed);
232      }
233
234      Ok(secure)
235   }
236
237   /// Create a new `SecureVec` from a mutable slice.
238   /// The slice is zeroized afterwards
239   pub fn from_slice_mut(slice: &mut [T]) -> Result<Self, Error>
240   where
241      T: Clone + DefaultIsZeroes,
242   {
243      let mut secure_vec = SecureVec::new_with_capacity(slice.len())?;
244      secure_vec.len = slice.len();
245      secure_vec.slice_mut_scope(|dest_slice| {
246         dest_slice.clone_from_slice(slice);
247      });
248      slice.zeroize();
249      Ok(secure_vec)
250   }
251
252   /// Create a new `SecureVec` from a slice.
253   /// The slice is not zeroized, you are responsible for zeroizing it
254   pub fn from_slice(slice: &[T]) -> Result<Self, Error>
255   where
256      T: Clone,
257   {
258      let mut secure_vec = SecureVec::new_with_capacity(slice.len())?;
259      secure_vec.len = slice.len();
260      secure_vec.slice_mut_scope(|dest_slice| {
261         dest_slice.clone_from_slice(slice);
262      });
263      Ok(secure_vec)
264   }
265
266   pub fn len(&self) -> usize {
267      self.len
268   }
269
270   pub fn as_ptr(&self) -> *const T {
271      self.ptr.as_ptr()
272   }
273
274   pub fn as_mut_ptr(&mut self) -> *mut u8 {
275      self.ptr.as_ptr() as *mut u8
276   }
277
278   #[allow(dead_code)]
279   fn allocated_byte_size(&self) -> usize {
280      let size = self.capacity * mem::size_of::<T>();
281      #[cfg(feature = "std")]
282      {
283         (size + page_size() - 1) & !(page_size() - 1)
284      }
285      #[cfg(not(feature = "std"))]
286      {
287         size // No page alignment in no_std
288      }
289   }
290
291   #[cfg(all(feature = "std", windows))]
292   fn encypt_memory(&self) -> bool {
293      let ptr = self.as_ptr() as *mut u8;
294      super::crypt_protect_memory(ptr, self.allocated_byte_size())
295   }
296
297   #[cfg(all(feature = "std", windows))]
298   fn decrypt_memory(&self) -> bool {
299      let ptr = self.as_ptr() as *mut u8;
300      super::crypt_unprotect_memory(ptr, self.allocated_byte_size())
301   }
302
303   /// Lock the memory region
304   ///
305   /// On Windows also calls `CryptProtectMemory` to encrypt the memory
306   ///
307   /// On Unix it just calls `mprotect` to lock the memory
308   pub(crate) fn lock_memory(&self) -> (bool, bool) {
309      #[cfg(feature = "std")]
310      {
311         #[cfg(windows)]
312         {
313            let encrypt_ok = self.encypt_memory();
314            let mprotect_ok = super::mprotect(self.ptr, Prot::NoAccess);
315            (encrypt_ok, mprotect_ok)
316         }
317         #[cfg(unix)]
318         {
319            let mprotect_ok = super::mprotect(self.ptr, Prot::NoAccess);
320            (true, mprotect_ok)
321         }
322      }
323      #[cfg(not(feature = "std"))]
324      {
325         (true, true) // No-op: always "succeeds"
326      }
327   }
328
329   /// Unlock the memory region
330   ///
331   /// On Windows also calls `CryptUnprotectMemory` to decrypt the memory
332   ///
333   /// On Unix it just calls `mprotect` to unlock the memory
334   pub(crate) fn unlock_memory(&self) -> (bool, bool) {
335      #[cfg(feature = "std")]
336      {
337         #[cfg(windows)]
338         {
339            let mprotect_ok = super::mprotect(self.ptr, Prot::ReadWrite);
340            if !mprotect_ok {
341               return (false, false);
342            }
343            let decrypt_ok = self.decrypt_memory();
344            (decrypt_ok, mprotect_ok)
345         }
346         #[cfg(unix)]
347         {
348            let mprotect_ok = super::mprotect(self.ptr, Prot::ReadWrite);
349            (true, mprotect_ok)
350         }
351      }
352
353      #[cfg(not(feature = "std"))]
354      {
355         (true, true) // No-op: always "succeeds"
356      }
357   }
358
359   /// Immutable access to the `SecureVec`
360   pub fn unlock_scope<F, R>(&self, f: F) -> R
361   where
362      F: FnOnce(&SecureVec<T>) -> R,
363   {
364      self.unlock_memory();
365      let result = f(self);
366      self.lock_memory();
367      result
368   }
369
370   /// Immutable access to the `SecureVec` as `&[T]`
371   pub fn slice_scope<F, R>(&self, f: F) -> R
372   where
373      F: FnOnce(&[T]) -> R,
374   {
375      unsafe {
376         self.unlock_memory();
377         let slice = core::slice::from_raw_parts(self.ptr.as_ptr(), self.len);
378         let result = f(slice);
379         self.lock_memory();
380         result
381      }
382   }
383
384   /// Mutable access to the `SecureVec` as `&mut [T]`
385   pub fn slice_mut_scope<F, R>(&mut self, f: F) -> R
386   where
387      F: FnOnce(&mut [T]) -> R,
388   {
389      unsafe {
390         self.unlock_memory();
391         let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
392         let result = f(slice);
393         self.lock_memory();
394         result
395      }
396   }
397
398   /// Immutable access to the `SecureVec` as `Iter<T>`
399   ///
400   /// ## Use with caution
401   ///
402   /// You can actually return a new allocated `Vec` from this function
403   ///
404   /// If you do that you are responsible for zeroizing its contents
405   pub fn iter_scope<F, R>(&self, f: F) -> R
406   where
407      F: FnOnce(core::slice::Iter<T>) -> R,
408   {
409      unsafe {
410         self.unlock_memory();
411         let slice = core::slice::from_raw_parts(self.ptr.as_ptr(), self.len);
412         let iter = slice.iter();
413         let result = f(iter);
414         self.lock_memory();
415         result
416      }
417   }
418
419   /// Mutable access to the `SecureVec` as `IterMut<T>`
420   ///
421   /// ## Use with caution
422   ///
423   /// You can actually return a new allocated `Vec` from this function
424   ///
425   /// If you do that you are responsible for zeroizing its contents
426   pub fn iter_mut_scope<F, R>(&mut self, f: F) -> R
427   where
428      F: FnOnce(core::slice::IterMut<T>) -> R,
429   {
430      unsafe {
431         self.unlock_memory();
432         let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
433         let iter = slice.iter_mut();
434         let result = f(iter);
435         self.lock_memory();
436         result
437      }
438   }
439
440   /// Erase the underlying data and clears the vector
441   ///
442   /// The memory is locked again and the capacity is preserved for reuse
443   pub fn erase(&mut self) {
444      unsafe {
445         self.unlock_memory();
446         let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
447         for elem in slice.iter_mut() {
448            elem.zeroize();
449         }
450         self.clear();
451         self.lock_memory();
452      }
453   }
454
455   /// Clear the vector
456   ///
457   /// This just sets the vector's len to zero it does not erase the underlying data
458   pub fn clear(&mut self) {
459      self.len = 0;
460   }
461
462   pub fn push(&mut self, value: T) {
463      // Ensure there is enough capacity for at least one more element.
464      // The `reserve` method will handle reallocation if necessary, using
465      // an amortized growth strategy. It leaves the vector
466      // locked upon returning.
467      self.reserve(1);
468
469      self.unlock_memory();
470
471      unsafe {
472         // Write the new value at the end of the vector.
473         core::ptr::write(self.ptr.as_ptr().add(self.len), value);
474
475         self.len += 1;
476      }
477
478      self.lock_memory();
479   }
480
481   /// Ensures that the vector has enough capacity for at least `additional` more elements.
482   ///
483   /// If more capacity is needed, it will reallocate. This may cause the buffer location to change.
484   ///
485   /// # Panics
486   ///
487   /// Panics if the new capacity overflows `usize` or if the allocation fails.
488   pub fn reserve(&mut self, additional: usize) {
489      if self.len() + additional <= self.capacity {
490         return;
491      }
492
493      // Use an amortized growth strategy to avoid reallocating on every push
494      let required_capacity = self.len() + additional;
495      let new_capacity = (self.capacity.max(1) * 2).max(required_capacity);
496
497      let new_items_byte_size = new_capacity * mem::size_of::<T>();
498
499      // Allocate new memory
500      #[cfg(feature = "std")]
501      let new_ptr = unsafe {
502         let aligned_allocation_size = (new_items_byte_size + page_size() - 1) & !(page_size() - 1);
503         memsec::malloc_sized(aligned_allocation_size)
504            .expect("Failed to allocate memory for SecureVec reserve")
505            .as_ptr() as *mut T
506      };
507
508      #[cfg(not(feature = "std"))]
509      let new_ptr = {
510         let layout = Layout::from_size_align(new_items_byte_size, mem::align_of::<T>())
511            .expect("Failed to create layout for SecureVec reserve");
512         let ptr = unsafe { alloc::alloc(layout) as *mut T };
513         if ptr.is_null() {
514            panic!("Memory allocation failed for SecureVec reserve");
515         }
516         ptr
517      };
518
519      // Copy data to new pointer, then erase and free old memory
520      unsafe {
521         self.unlock_memory();
522         core::ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_ptr, self.len());
523
524         // Erase and free the old memory
525         if self.capacity > 0 {
526            let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
527            for elem in slice.iter_mut() {
528               elem.zeroize();
529            }
530         }
531         #[cfg(feature = "std")]
532         memsec::free(self.ptr);
533
534         #[cfg(not(feature = "std"))]
535         {
536            let old_size = self.capacity * mem::size_of::<T>();
537            let old_layout = Layout::from_size_align_unchecked(old_size, mem::align_of::<T>());
538            dealloc(self.ptr.as_ptr() as *mut u8, old_layout);
539         }
540      }
541
542      // Update pointer and capacity, then re-lock the new memory region
543      self.ptr = NonNull::new(new_ptr).expect("New pointer was null");
544      self.capacity = new_capacity;
545      self.lock_memory();
546   }
547
548   /// Creates a draining iterator that removes the specified range from the vector
549   /// and yields the removed items.
550   ///
551   /// Note: The vector is unlocked during the lifetime of the `Drain` iterator.
552   /// The memory is relocked when the `Drain` iterator is dropped.
553   ///
554   /// # Panics
555   /// Panics if the starting point is greater than the end point or if the end point
556   /// is greater than the length of the vector.
557   pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
558   where
559      R: RangeBounds<usize>,
560   {
561      self.unlock_memory();
562
563      let original_len = self.len;
564
565      let (drain_start_idx, drain_end_idx) = resolve_range_indices(range, original_len);
566
567      let tail_len = original_len - drain_end_idx;
568
569      self.len = drain_start_idx;
570
571      Drain {
572         vec_ref: self,
573         drain_start_index: drain_start_idx,
574         current_drain_iter_index: drain_start_idx,
575         drain_end_index: drain_end_idx,
576         original_vec_len: original_len,
577         tail_len,
578         _marker: PhantomData,
579      }
580   }
581}
582
583impl<T: Clone + Zeroize> Clone for SecureVec<T> {
584   fn clone(&self) -> Self {
585      let mut new_vec = SecureVec::new_with_capacity(self.capacity).unwrap();
586      new_vec.len = self.len;
587
588      self.slice_scope(|src_slice| {
589         new_vec.slice_mut_scope(|dest_slice| {
590            dest_slice.clone_from_slice(src_slice);
591         });
592      });
593
594      new_vec
595   }
596}
597
598impl<const LENGTH: usize> From<SecureArray<u8, LENGTH>> for SecureVec<u8> {
599   fn from(array: SecureArray<u8, LENGTH>) -> Self {
600      let mut new_vec = SecureVec::new_with_capacity(LENGTH)
601         .expect("Failed to allocate SecureVec during conversion");
602      new_vec.len = array.len();
603
604      array.unlocked_scope(|array_slice| {
605         new_vec.slice_mut_scope(|vec_slice| {
606            vec_slice.copy_from_slice(array_slice);
607         });
608      });
609
610      new_vec
611   }
612}
613
614impl<T: Zeroize> Drop for SecureVec<T> {
615   fn drop(&mut self) {
616      self.erase();
617      self.unlock_memory();
618      unsafe {
619         #[cfg(feature = "std")]
620         memsec::free(self.ptr);
621
622         #[cfg(not(feature = "std"))]
623         {
624            // Recreate the layout to deallocate correctly
625            let layout =
626               Layout::from_size_align_unchecked(self.allocated_byte_size(), mem::align_of::<T>());
627            dealloc(self.ptr.as_ptr() as *mut u8, layout);
628         }
629      }
630   }
631}
632
633impl<T: Zeroize> core::ops::Index<usize> for SecureVec<T> {
634   type Output = T;
635
636   fn index(&self, index: usize) -> &Self::Output {
637      assert!(index < self.len, "Index out of bounds");
638      unsafe {
639         let ptr = self.ptr.as_ptr().add(index);
640         let reference = &*ptr;
641         reference
642      }
643   }
644}
645
646#[cfg(feature = "serde")]
647impl serde::Serialize for SecureVec<u8> {
648   fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
649   where
650      S: serde::Serializer,
651   {
652      let res = self.slice_scope(|slice| serializer.collect_seq(slice.iter()));
653      res
654   }
655}
656
657#[cfg(feature = "serde")]
658impl<'de> serde::Deserialize<'de> for SecureVec<u8> {
659   fn deserialize<D>(deserializer: D) -> Result<SecureVec<u8>, D::Error>
660   where
661      D: serde::Deserializer<'de>,
662   {
663      struct SecureVecVisitor;
664      impl<'de> serde::de::Visitor<'de> for SecureVecVisitor {
665         type Value = SecureVec<u8>;
666         fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
667            write!(formatter, "a sequence of bytes")
668         }
669         fn visit_seq<A>(
670            self,
671            mut seq: A,
672         ) -> Result<<Self as serde::de::Visitor<'de>>::Value, A::Error>
673         where
674            A: serde::de::SeqAccess<'de>,
675         {
676            let mut vec = Vec::new();
677            while let Some(byte) = seq.next_element::<u8>()? {
678               vec.push(byte);
679            }
680            SecureVec::from_vec(vec).map_err(serde::de::Error::custom)
681         }
682      }
683      deserializer.deserialize_seq(SecureVecVisitor)
684   }
685}
686
687/// A draining iterator for `SecureVec<T>`.
688///
689/// This struct is created by the `drain` method on `SecureVec`.
690///
691/// # Safety
692/// The returned `Drain` iterator must not be forgotten (via `mem::forget`).
693/// Forgetting the iterator sets the len of `SecureVec` to 0 and the memory will remain unlocked
694pub struct Drain<'a, T: Zeroize + 'a> {
695   vec_ref: &'a mut SecureVec<T>,
696   drain_start_index: usize,
697   current_drain_iter_index: usize,
698   drain_end_index: usize,
699
700   original_vec_len: usize, // Original length of vec_ref before drain
701   tail_len: usize,         // Number of elements after the drain range in the original vec
702
703   _marker: PhantomData<&'a T>,
704}
705
706impl<'a, T: Zeroize> Iterator for Drain<'a, T> {
707   type Item = T;
708
709   fn next(&mut self) -> Option<T> {
710      if self.current_drain_iter_index < self.drain_end_index {
711         // SecureVec is already unlocked by the `drain` method.
712         unsafe {
713            let item_ptr = self.vec_ref.ptr.as_ptr().add(self.current_drain_iter_index);
714            let item = ptr::read(item_ptr);
715            self.current_drain_iter_index += 1;
716            Some(item)
717         }
718      } else {
719         None
720      }
721   }
722
723   fn size_hint(&self) -> (usize, Option<usize>) {
724      let remaining = self.drain_end_index - self.current_drain_iter_index;
725      (remaining, Some(remaining))
726   }
727}
728
729impl<'a, T: Zeroize> ExactSizeIterator for Drain<'a, T> {}
730
731impl<'a, T: Zeroize> Drop for Drain<'a, T> {
732   fn drop(&mut self) {
733      unsafe {
734         // The vec_ref's memory is currently unlocked.
735         if mem::needs_drop::<T>() {
736            let mut current_ptr =
737               self.vec_ref.ptr.as_ptr().add(self.current_drain_iter_index) as *mut T;
738            let end_ptr = self.vec_ref.ptr.as_ptr().add(self.drain_end_index) as *mut T;
739            while current_ptr < end_ptr {
740               ptr::drop_in_place(current_ptr);
741               current_ptr = current_ptr.add(1);
742            }
743         }
744
745         let hole_dst_ptr = self.vec_ref.ptr.as_ptr().add(self.drain_start_index) as *mut T;
746         let tail_src_ptr = self.vec_ref.ptr.as_ptr().add(self.drain_end_index) as *mut T;
747
748         if self.tail_len > 0 {
749            ptr::copy(tail_src_ptr, hole_dst_ptr, self.tail_len);
750         }
751
752         // The new length of the vector.
753         let new_len = self.drain_start_index + self.tail_len;
754
755         // Process the memory region that is no longer part of the active vector's content.
756         // This region is from `vec_ref.ptr + new_len` up to `vec_ref.ptr + original_vec_len`.
757         // It contains:
758         //    a) Original data of the latter part of the drained slice (if not overwritten by tail).
759         //       These were dropped in step 1 if T:Drop.
760         //    b) Original data of the tail items (which have now been copied).
761         //       These need to be dropped if T:Drop, as ptr::copy doesn't drop the source.
762         // After any necessary drops, this entire region must be zeroized.
763
764         let mut current_cleanup_ptr = self.vec_ref.ptr.as_ptr().add(new_len) as *mut T;
765         let end_cleanup_ptr = self.vec_ref.ptr.as_ptr().add(self.original_vec_len) as *mut T;
766
767         // Determine the start of the original tail's memory region
768         let original_tail_start_ptr_val = tail_src_ptr as usize;
769
770         while current_cleanup_ptr < end_cleanup_ptr {
771            if mem::needs_drop::<T>() {
772               let current_ptr_val = current_cleanup_ptr as usize;
773               let original_tail_end_ptr_val =
774                  original_tail_start_ptr_val + self.tail_len * mem::size_of::<T>();
775
776               if current_ptr_val >= original_tail_start_ptr_val
777                  && current_ptr_val < original_tail_end_ptr_val
778               {
779                  // This element was part of the original tail. ptr::copy moved its value.
780                  // The original instance here needs to be dropped.
781                  ptr::drop_in_place(current_cleanup_ptr);
782               }
783               // Else, it was part of the drained range (not covered by tail move).
784               // If it needed dropping, it was handled in step 1.
785            }
786
787            // Zeroize the memory of this element.
788            (*current_cleanup_ptr).zeroize();
789            current_cleanup_ptr = current_cleanup_ptr.add(1);
790         }
791
792         // Update the SecureVec's length.
793         self.vec_ref.len = new_len;
794
795         // Relock the SecureVec's memory.
796         self.vec_ref.lock_memory();
797      }
798   }
799}
800
801// Helper function to resolve RangeBounds to (start, end) indices
802fn resolve_range_indices<R: RangeBounds<usize>>(range: R, len: usize) -> (usize, usize) {
803   let start_bound = range.start_bound();
804   let end_bound = range.end_bound();
805
806   let start = match start_bound {
807      Bound::Included(&s) => s,
808      Bound::Excluded(&s) => s
809         .checked_add(1)
810         .unwrap_or_else(|| panic!("attempted to start drain at Excluded(usize::MAX)")),
811      Bound::Unbounded => 0,
812   };
813
814   let end = match end_bound {
815      Bound::Included(&e) => e
816         .checked_add(1)
817         .unwrap_or_else(|| panic!("attempted to end drain at Included(usize::MAX)")),
818      Bound::Excluded(&e) => e,
819      Bound::Unbounded => len,
820   };
821
822   if start > end {
823      panic!(
824         "drain range start ({}) must be less than or equal to end ({})",
825         start, end
826      );
827   }
828   if end > len {
829      panic!(
830         "drain range end ({}) out of bounds for slice of length {}",
831         end, len
832      );
833   }
834
835   (start, end)
836}
837
838#[cfg(all(test, feature = "std"))]
839mod tests {
840   use super::*;
841   use std::process::{Command, Stdio};
842   use std::sync::{Arc, Mutex};
843
844   #[test]
845   fn test_from_methods() {
846      let vec: Vec<u8> = vec![1, 2, 3];
847      let secure_vec = SecureVec::from_vec(vec).unwrap();
848
849      secure_vec.slice_scope(|slice| {
850         assert_eq!(slice, &[1, 2, 3]);
851      });
852
853      let mut slice = [3u8, 5];
854      let secure_slice = SecureVec::from_slice_mut(&mut slice).unwrap();
855      assert_eq!(slice, [0, 0]);
856
857      secure_slice.slice_scope(|slice| {
858         assert_eq!(slice, &[3, 5]);
859      });
860
861      let slice = [3u8, 5];
862      let secure_slice = SecureVec::from_slice(&slice).unwrap();
863
864      secure_slice.slice_scope(|slice| {
865         assert_eq!(slice, &[3, 5]);
866      });
867   }
868
869   #[test]
870   fn test_from_secure_array() {
871      let array: SecureArray<u8, 3> = SecureArray::new([1, 2, 3]).unwrap();
872      let vec: SecureVec<u8> = array.into();
873      assert_eq!(vec.len(), 3);
874      vec.slice_scope(|slice| {
875         assert_eq!(slice, &[1, 2, 3]);
876      });
877   }
878
879   #[test]
880   fn lock_unlock() {
881      let secure: SecureVec<u8> = SecureVec::new().unwrap();
882      let size = secure.allocated_byte_size();
883      assert_eq!(size > 0, true);
884
885      let (decrypted, unlocked) = secure.unlock_memory();
886      assert!(decrypted);
887      assert!(unlocked);
888
889      let (encrypted, locked) = secure.lock_memory();
890      assert!(encrypted);
891      assert!(locked);
892
893      let secure: SecureVec<u8> = SecureVec::from_vec(vec![]).unwrap();
894      let size = secure.allocated_byte_size();
895      assert_eq!(size > 0, true);
896
897      let (decrypted, unlocked) = secure.unlock_memory();
898      assert!(decrypted);
899      assert!(unlocked);
900
901      let (encrypted, locked) = secure.lock_memory();
902      assert!(encrypted);
903      assert!(locked);
904
905      let secure: SecureVec<u8> = SecureVec::new_with_capacity(0).unwrap();
906      let size = secure.allocated_byte_size();
907      assert_eq!(size > 0, true);
908
909      let (decrypted, unlocked) = secure.unlock_memory();
910      assert!(decrypted);
911      assert!(unlocked);
912
913      let (encrypted, locked) = secure.lock_memory();
914      assert!(encrypted);
915      assert!(locked);
916   }
917
918   #[test]
919   fn test_thread_safety() {
920      let vec: Vec<u8> = vec![];
921      let secure = SecureVec::from_vec(vec).unwrap();
922      let secure = Arc::new(Mutex::new(secure));
923
924      let mut handles = Vec::new();
925      for i in 0..5u8 {
926         let secure_clone = secure.clone();
927         let handle = std::thread::spawn(move || {
928            let mut secure = secure_clone.lock().unwrap();
929            secure.push(i);
930         });
931         handles.push(handle);
932      }
933
934      for handle in handles {
935         handle.join().unwrap();
936      }
937
938      let sec = secure.lock().unwrap();
939      sec.slice_scope(|slice| {
940         assert_eq!(slice.len(), 5);
941      });
942   }
943
944   #[test]
945   fn test_clone() {
946      let vec: Vec<u8> = vec![1, 2, 3];
947      let secure1 = SecureVec::from_vec(vec).unwrap();
948      let secure2 = secure1.clone();
949
950      secure1.slice_scope(|slice| {
951         secure2.slice_scope(|slice2| {
952            assert_eq!(slice, slice2);
953         });
954      });
955   }
956
957   #[test]
958   fn test_do_not_call_forget_on_drain() {
959      let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
960      let mut secure = SecureVec::from_vec(vec).unwrap();
961      let drain = secure.drain(..3);
962      core::mem::forget(drain);
963      // we can still use secure vec but its state is unreachable
964      secure.slice_scope(|secure| {
965         assert_eq!(secure.len(), 0);
966      });
967   }
968
969   #[test]
970   fn test_drain() {
971      let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
972      let mut secure = SecureVec::from_vec(vec).unwrap();
973      let mut drain = secure.drain(..3);
974      assert_eq!(drain.next(), Some(1));
975      assert_eq!(drain.next(), Some(2));
976      assert_eq!(drain.next(), Some(3));
977      assert_eq!(drain.next(), None);
978      drop(drain);
979      secure.slice_scope(|secure| {
980         assert_eq!(secure.len(), 7);
981         assert_eq!(secure, &[4, 5, 6, 7, 8, 9, 10]);
982      });
983   }
984
985   #[cfg(feature = "serde")]
986   #[test]
987   fn test_secure_vec_serde() {
988      let vec: Vec<u8> = vec![1, 2, 3];
989      let secure = SecureVec::from_vec(vec).unwrap();
990      let json = serde_json::to_vec(&secure).expect("Serialization failed");
991      let deserialized: SecureVec<u8> =
992         serde_json::from_slice(&json).expect("Deserialization failed");
993      deserialized.slice_scope(|slice| {
994         assert_eq!(slice, &[1, 2, 3]);
995      });
996   }
997
998   #[test]
999   fn test_erase() {
1000      let vec: Vec<u8> = vec![1, 2, 3];
1001      let mut secure = SecureVec::from_vec(vec).unwrap();
1002      secure.erase();
1003      secure.unlock_scope(|secure| {
1004         assert_eq!(secure.len, 0);
1005         assert_eq!(secure.capacity, 3);
1006      });
1007
1008      secure.push(1);
1009      secure.push(2);
1010      secure.push(3);
1011      secure.unlock_scope(|secure| {
1012         assert_eq!(secure[0], 1);
1013         assert_eq!(secure[1], 2);
1014         assert_eq!(secure[2], 3);
1015         assert_eq!(secure.len, 3);
1016         assert_eq!(secure.capacity, 3);
1017      });
1018   }
1019
1020   #[test]
1021   fn test_push() {
1022      let vec: Vec<u8> = Vec::new();
1023      let mut secure = SecureVec::from_vec(vec).unwrap();
1024      for i in 0..30 {
1025         secure.push(i);
1026      }
1027   }
1028
1029   #[test]
1030   fn test_reserve() {
1031      let mut secure: SecureVec<u8> = SecureVec::new().unwrap();
1032      secure.reserve(10);
1033      assert_eq!(secure.capacity, 10);
1034   }
1035
1036   #[test]
1037   fn test_reserve_doubling() {
1038      let mut secure: SecureVec<u8> = SecureVec::new().unwrap();
1039      secure.reserve(10);
1040
1041      for i in 0..9 {
1042         secure.push(i);
1043      }
1044
1045      secure.push(9);
1046      assert_eq!(secure.capacity, 10);
1047      assert_eq!(secure.len(), 10);
1048
1049      secure.push(10);
1050      assert_eq!(secure.capacity, 20);
1051      assert_eq!(secure.len(), 11);
1052   }
1053
1054   #[test]
1055   fn test_index() {
1056      let vec: Vec<u8> = vec![1, 2, 3];
1057      let secure = SecureVec::from_vec(vec).unwrap();
1058      secure.unlock_scope(|secure| {
1059         assert_eq!(secure[0], 1);
1060         assert_eq!(secure[1], 2);
1061         assert_eq!(secure[2], 3);
1062      });
1063   }
1064
1065   #[test]
1066   fn test_slice_scoped() {
1067      let vec: Vec<u8> = vec![1, 2, 3];
1068      let secure = SecureVec::from_vec(vec).unwrap();
1069      secure.slice_scope(|slice| {
1070         assert_eq!(slice, &[1, 2, 3]);
1071      });
1072   }
1073
1074   #[test]
1075   fn test_slice_mut_scoped() {
1076      let vec: Vec<u8> = vec![1, 2, 3];
1077      let mut secure = SecureVec::from_vec(vec).unwrap();
1078
1079      secure.slice_mut_scope(|slice| {
1080         slice[0] = 4;
1081         assert_eq!(slice, &mut [4, 2, 3]);
1082      });
1083
1084      secure.slice_scope(|slice| {
1085         assert_eq!(slice, &[4, 2, 3]);
1086      });
1087   }
1088
1089   #[test]
1090   fn test_iter_scoped() {
1091      let vec: Vec<u8> = vec![1, 2, 3];
1092      let secure = SecureVec::from_vec(vec).unwrap();
1093      let sum: u8 = secure.iter_scope(|iter| iter.map(|&x| x).sum());
1094
1095      assert_eq!(sum, 6);
1096
1097      let secure: SecureVec<u8> = SecureVec::new_with_capacity(3).unwrap();
1098      let sum: u8 = secure.iter_scope(|iter| iter.map(|&x| x).sum());
1099
1100      assert_eq!(sum, 0);
1101   }
1102
1103   #[test]
1104   fn test_iter_mut_scoped() {
1105      let vec: Vec<u8> = vec![1, 2, 3];
1106      let mut secure = SecureVec::from_vec(vec).unwrap();
1107      secure.iter_mut_scope(|iter| {
1108         for elem in iter {
1109            *elem += 1;
1110         }
1111      });
1112
1113      secure.slice_scope(|slice| {
1114         assert_eq!(slice, &[2, 3, 4]);
1115      });
1116   }
1117
1118   #[test]
1119   fn test_index_should_fail_when_locked() {
1120      let arg = "CRASH_TEST_SECUREVEC_LOCKED";
1121
1122      if std::env::args().any(|a| a == arg) {
1123         let vec: Vec<u8> = vec![1, 2, 3];
1124         let secure = SecureVec::from_vec(vec).unwrap();
1125         let _value = core::hint::black_box(secure[0]);
1126
1127         std::process::exit(1);
1128      }
1129
1130      let child = Command::new(std::env::current_exe().unwrap())
1131         .arg("vec::tests::test_index_should_fail_when_locked")
1132         .arg(arg)
1133         .arg("--nocapture")
1134         .stdout(Stdio::piped())
1135         .stderr(Stdio::piped())
1136         .spawn()
1137         .expect("Failed to spawn child process");
1138
1139      let output = child.wait_with_output().expect("Failed to wait on child");
1140      let status = output.status;
1141
1142      assert!(
1143         !status.success(),
1144         "Process exited successfully with code {:?}, but it should have crashed.",
1145         status.code()
1146      );
1147
1148      #[cfg(unix)]
1149      {
1150         use std::os::unix::process::ExitStatusExt;
1151         let signal = status
1152            .signal()
1153            .expect("Process was not terminated by a signal on Unix.");
1154         assert!(
1155            signal == libc::SIGSEGV || signal == libc::SIGBUS,
1156            "Process terminated with unexpected signal: {}",
1157            signal
1158         );
1159         println!(
1160            "Test passed: Process correctly terminated with signal {}.",
1161            signal
1162         );
1163      }
1164
1165      #[cfg(windows)]
1166      {
1167         const STATUS_ACCESS_VIOLATION: i32 = 0xC0000005_u32 as i32;
1168         assert_eq!(
1169            status.code(),
1170            Some(STATUS_ACCESS_VIOLATION),
1171            "Process exited with unexpected code: {:x?}. Expected STATUS_ACCESS_VIOLATION.",
1172            status.code()
1173         );
1174         eprintln!("Test passed: Process correctly terminated with STATUS_ACCESS_VIOLATION.");
1175      }
1176   }
1177}