flex_alloc_secure/
protect.rs

1use core::any::type_name;
2use core::fmt;
3use core::mem::MaybeUninit;
4use core::ops;
5use core::ptr;
6
7use rand_core::RngCore;
8use zeroize::{DefaultIsZeroes, Zeroize};
9
10use crate::boxed::SecureBox;
11use crate::bytes::FillBytes;
12
13/// Access a protected value for reading or writing.
14///
15/// While the value is being accessed, the protections
16/// offered by the container (including memory protections
17/// and/or encryption) will be inactive.
18pub trait ExposeProtected {
19    /// The type of the referenced value.
20    type Target: ?Sized;
21
22    /// Expose the protected value for reading.
23    fn expose_read<F>(&self, f: F)
24    where
25        F: FnOnce(SecureRef<&Self::Target>);
26
27    /// Expose the protected value for updating.
28    fn expose_write<F>(&mut self, f: F)
29    where
30        F: FnOnce(SecureRef<&mut Self::Target>);
31
32    /// Unwrap the protected value.
33    fn unprotect(self) -> SecureBox<Self::Target>;
34}
35
36/// Initialize a protected container type for a sized value.
37pub trait ProtectedInit: ExposeProtected + From<SecureBox<Self::Target>> + Sized {
38    /// For a concrete type implementing `FillBytes`, initialize with the
39    /// standard indicator value and call the closure `f` with a mutable
40    /// reference to the contained value before applying protections.
41    fn init<F>(f: F) -> Self
42    where
43        F: FnOnce(SecureRef<&mut Self::Target>),
44        Self::Target: Copy + FillBytes,
45    {
46        let mut boxed = unsafe { SecureBox::<Self::Target>::new_uninit().assume_init() };
47        f(SecureRef::new_mut(boxed.as_mut()));
48        boxed.into()
49    }
50
51    /// Initialize with the default value for `Self::Target`, and call the
52    /// closure `f` with a mutable reference to the contained value before
53    /// applying protections.
54    fn init_default<F>(f: F) -> Self
55    where
56        F: FnOnce(SecureRef<&mut Self::Target>),
57        Self::Target: Default,
58    {
59        let mut boxed = SecureBox::<Self::Target>::default();
60        f(SecureRef::new_mut(boxed.as_mut()));
61        boxed.into()
62    }
63
64    /// Initialize with a randomized value for `Self::Target`, and call the
65    /// closure `f` with a mutable reference to the contained value before
66    /// applying protections.
67    fn init_random<F>(rng: impl RngCore, f: F) -> Self
68    where
69        F: FnOnce(SecureRef<&mut Self::Target>),
70        Self::Target: Copy + FillBytes,
71    {
72        let mut boxed = SecureBox::<Self::Target>::new_uninit();
73        boxed.fill_random(rng);
74        let mut boxed = unsafe { boxed.assume_init() };
75        f(SecureRef::new_mut(boxed.as_mut()));
76        boxed.into()
77    }
78
79    /// Initialize by copying the value contained in `from` and zeroizing the
80    /// existing copy. Call the closure `f` with a mutable reference to the
81    /// contained value before applying protections.
82    fn init_take<F>(from: &mut Self::Target, f: F) -> Self
83    where
84        F: FnOnce(SecureRef<&mut Self::Target>),
85        Self::Target: DefaultIsZeroes,
86    {
87        let boxed = SecureBox::new_uninit();
88        let mut boxed = SecureBox::write(boxed, *from);
89        from.zeroize();
90        f(SecureRef::new_mut(boxed.as_mut()));
91        boxed.into()
92    }
93
94    /// Initialize by calling the closure `f`, store the resulting
95    /// instance of `Self::Target` and apply protections.
96    #[inline(always)]
97    fn init_with<F>(f: F) -> Self
98    where
99        F: FnOnce() -> Self::Target,
100        Self::Target: Sized,
101    {
102        let boxed = SecureBox::new_uninit();
103        SecureBox::write(boxed, f()).into()
104    }
105
106    /// Initialize by calling the fallible closure `f`, store the resulting
107    /// instance of `Self::Target` and apply protections. On failure, return
108    /// the error type `E`.
109    #[inline(always)]
110    fn try_init_with<F, E>(f: F) -> Result<Self, E>
111    where
112        F: FnOnce() -> Result<Self::Target, E>,
113        Self::Target: Sized,
114    {
115        let boxed = SecureBox::new_uninit();
116        Ok(SecureBox::write(boxed, f()?).into())
117    }
118
119    /// Create a new protected instance containing a random value.
120    fn random(rng: impl RngCore) -> Self
121    where
122        Self::Target: Copy + FillBytes,
123    {
124        Self::init_random(rng, |_| ())
125    }
126
127    /// Create a new protected instance by copying and zeroizing an
128    /// existing value.
129    fn take(from: &mut Self::Target) -> Self
130    where
131        Self::Target: DefaultIsZeroes,
132    {
133        Self::init_take(from, |_| ())
134    }
135}
136
137impl<T, W> ProtectedInit for W where W: From<SecureBox<T>> + ExposeProtected<Target = T> {}
138
139/// Initialize a protected container type for a slice of elements.
140pub trait ProtectedInitSlice:
141    ExposeProtected<Target = [Self::Item]> + From<SecureBox<[Self::Item]>> + Sized
142{
143    /// The type of the elements contained in the slice.
144    type Item;
145
146    /// For a concrete type implementing `FillBytes`, initialize a slice
147    /// of length `len` with the standard indicator value and call the closure
148    /// `f` with a mutable reference to the slice before applying protections.
149    fn init_slice<F>(len: usize, f: F) -> Self
150    where
151        F: FnOnce(SecureRef<&mut [Self::Item]>),
152        Self::Item: Copy + FillBytes,
153    {
154        let mut boxed = unsafe { SecureBox::<[Self::Item]>::new_uninit_slice(len).assume_init() };
155        f(SecureRef::new_mut(boxed.as_mut()));
156        boxed.into()
157    }
158
159    /// Initialize with a slice of length `len` containing the default value for
160    /// `Self::Item`, and call the closure `f` with a mutable reference to the
161    /// slice before applying protections.
162    fn init_default_slice<F>(len: usize, f: F) -> Self
163    where
164        F: FnOnce(SecureRef<&mut [Self::Item]>),
165        Self::Item: Default,
166    {
167        let mut boxed = SecureBox::<[Self::Item]>::new_uninit_slice(len);
168        boxed
169            .as_mut()
170            .fill_with(|| MaybeUninit::new(Default::default()));
171        let mut boxed = unsafe { boxed.assume_init() };
172        f(SecureRef::new_mut(boxed.as_mut()));
173        boxed.into()
174    }
175
176    /// Initialize with a randomized slice of length `len`, and call the
177    /// closure `f` with a mutable reference to the slice before
178    /// applying protections.
179    fn init_random_slice<F>(len: usize, rng: impl RngCore, f: F) -> Self
180    where
181        F: FnOnce(SecureRef<&mut [Self::Item]>),
182        Self::Item: Copy + FillBytes,
183    {
184        let mut boxed = SecureBox::<[Self::Item]>::new_uninit_slice(len);
185        boxed.fill_random(rng);
186        let mut boxed = unsafe { boxed.assume_init() };
187        f(SecureRef::new_mut(boxed.as_mut()));
188        boxed.into()
189    }
190
191    /// Initialize by copying the slice `from` and zeroizing the existing
192    /// copy. Call the closure `f` with a mutable reference to the contained
193    /// slice before applying protections.
194    fn init_take_slice<F>(from: &mut [Self::Item], f: F) -> Self
195    where
196        F: FnOnce(SecureRef<&mut [Self::Item]>),
197        Self::Item: DefaultIsZeroes,
198    {
199        let len = from.len();
200        let mut boxed = SecureBox::<[Self::Item]>::new_uninit_slice(len);
201        unsafe {
202            ptr::copy_nonoverlapping(
203                from.as_ptr(),
204                boxed.as_mut().as_mut_ptr() as *mut Self::Item,
205                len,
206            )
207        };
208        from.zeroize();
209        let mut boxed = unsafe { boxed.assume_init() };
210        f(SecureRef::new_mut(boxed.as_mut()));
211        boxed.into()
212    }
213
214    /// Create a new protected instance containing a random slice of length `len`.
215    fn random_slice(len: usize, rng: impl RngCore) -> Self
216    where
217        Self::Item: Copy + FillBytes,
218    {
219        Self::init_random_slice(len, rng, |_| ())
220    }
221
222    /// Create a new protected slice instance by copying and zeroizing an
223    /// existing slice.
224    fn take_slice(from: &mut [Self::Item]) -> Self
225    where
226        Self::Item: DefaultIsZeroes,
227    {
228        Self::init_take_slice(from, |_| ())
229    }
230}
231
232impl<T, W> ProtectedInitSlice for W
233where
234    W: From<SecureBox<[T]>> + ExposeProtected<Target = [T]>,
235{
236    type Item = T;
237}
238
239/// A managed reference to the value of a [`ProtectedBox`].
240pub struct SecureRef<T: ?Sized>(T);
241
242impl<'a, T: ?Sized> SecureRef<&'a T> {
243    pub(crate) fn new(inner: &'a T) -> Self {
244        Self(inner)
245    }
246}
247
248impl<'a, T: ?Sized> SecureRef<&'a mut T> {
249    pub(crate) fn new_mut(inner: &'a mut T) -> Self {
250        Self(inner)
251    }
252}
253
254impl<'a, T> SecureRef<&'a mut MaybeUninit<T>> {
255    /// Convert this reference into an initialized state.
256    /// # Safety
257    /// If the inner value is not properly initialized, then
258    /// undetermined behavior may result.
259    #[inline]
260    pub unsafe fn assume_init(self) -> SecureRef<&'a mut T> {
261        SecureRef(self.0.assume_init_mut())
262    }
263
264    /// Write a value to the uninitialized reference and
265    /// safely initialize it.
266    #[inline(always)]
267    pub fn write(slf: Self, value: T) -> SecureRef<&'a mut T> {
268        slf.0.write(value);
269        SecureRef(unsafe { slf.0.assume_init_mut() })
270    }
271}
272
273impl<T: ?Sized> AsRef<T> for SecureRef<&'_ T> {
274    #[inline]
275    fn as_ref(&self) -> &T {
276        self.0
277    }
278}
279
280impl<T: ?Sized> AsRef<T> for SecureRef<&'_ mut T> {
281    #[inline]
282    fn as_ref(&self) -> &T {
283        self.0
284    }
285}
286
287impl<T: ?Sized> AsMut<T> for SecureRef<&'_ mut T> {
288    #[inline]
289    fn as_mut(&mut self) -> &mut T {
290        self.0
291    }
292}
293
294impl<T: ?Sized> fmt::Debug for SecureRef<T> {
295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296        f.write_fmt(format_args!("ProtectedRef<{}>", type_name::<T>()))
297    }
298}
299
300impl<T: ?Sized> ops::Deref for SecureRef<&'_ T> {
301    type Target = T;
302
303    #[inline]
304    fn deref(&self) -> &T {
305        self.0
306    }
307}
308
309impl<T: ?Sized> ops::Deref for SecureRef<&'_ mut T> {
310    type Target = T;
311
312    #[inline]
313    fn deref(&self) -> &Self::Target {
314        self.0
315    }
316}
317
318impl<T: ?Sized> ops::DerefMut for SecureRef<&'_ mut T> {
319    fn deref_mut(&mut self) -> &mut Self::Target {
320        self.0
321    }
322}