vitaminc_protected/controlled.rs
1pub use crate::Protected;
2use crate::{private::ControlledPrivate, AsProtectedRef, ProtectedRef, ReplaceT};
3use zeroize::Zeroize;
4
5pub trait Controlled: ControlledPrivate {
6 type Inner;
7
8 fn init_from_inner(x: Self::Inner) -> Self;
9 fn inner_mut(&mut self) -> &mut Self::Inner;
10
11 /// Initialize a new instance of the [Controlled] type from the inner value.
12 fn new(inner: Self::Inner) -> Self
13 where
14 Self: Sized,
15 {
16 Self::init_from_inner(inner)
17 }
18
19 /// Generate a new instance of the [Controlled] type from a function that returns the inner value.
20 ///
21 /// # Example
22 ///
23 /// Generate a new [Protected] from a function that returns an array.
24 ///
25 /// ```
26 /// use vitaminc_protected::{Controlled, Protected};
27 /// fn array_gen<const N: usize>() -> [u8; N] {
28 /// let mut input: [u8; N] = [0; N];
29 /// input.iter_mut().enumerate().for_each(|(i, x)| {
30 /// *x = (i + 1) as u8;
31 /// });
32 /// input
33 /// }
34 /// let input: Protected<[u8; 8]> = Protected::generate(array_gen);
35 /// assert_eq!(input.risky_unwrap(), [1, 2, 3, 4, 5, 6, 7, 8]);
36 /// ```
37 /// // TODO: A Generate Array could handle the MaybeUninit stuff
38 fn generate<F>(f: F) -> Self
39 where
40 Self: Sized,
41 F: FnOnce() -> Self::Inner,
42 {
43 Self::init_from_inner(f())
44 }
45
46 /// Generate a new [Controlled] type from a function that returns a `Result` with the inner value.
47 ///
48 /// # Example
49 ///
50 /// Generate a new [Protected] from a function that returns a `Result` with the inner value.
51 ///
52 /// ```
53 /// use vitaminc_protected::{Controlled, Protected};
54 /// use std::string::FromUtf8Error;
55 ///
56 /// let input: Result<Protected<String>, FromUtf8Error> = Protected::generate_ok(|| {
57 /// String::from_utf8(vec![1, 2, 3, 4, 5, 6, 7, 8])
58 /// });
59 /// ```
60 ///
61 fn generate_ok<F, E>(f: F) -> Result<Self, E>
62 where
63 Self: Sized,
64 F: FnOnce() -> Result<Self::Inner, E>,
65 {
66 f().map(Self::init_from_inner)
67 }
68
69 /// Map the inner value of this [Controlled] type`.
70 /// Conceptually similar to `Option::map`.
71 ///
72 /// # Example
73 ///
74 /// Map the inner value of a [Protected] to a new value.
75 ///
76 /// ```
77 /// use vitaminc_protected::{Controlled, Protected};
78 /// let x = Protected::new(100u8);
79 /// let y = x.map(|x| x + 10);
80 /// assert_eq!(y.risky_unwrap(), 110);
81 /// ```
82 fn map<B, F>(self, f: F) -> <Self as ReplaceT<B>>::Output
83 where
84 Self: Sized + ReplaceT<B>,
85 F: FnOnce(<Self as Controlled>::Inner) -> B,
86 <Self as ReplaceT<B>>::Output: Controlled<Inner = B>,
87 B: Zeroize,
88 {
89 <Self as ReplaceT<B>>::Output::init_from_inner(f(self.risky_unwrap()))
90 }
91
92 /// Similar to `map` but the closure returns a `Result` with the new inner value.
93 /// The result is a `Result` with the new [Controlled] type.
94 ///
95 /// # Example
96 ///
97 /// Map the inner value of a [Protected] to a new value that is wrapped in a `Result`.
98 ///
99 /// ```
100 /// use vitaminc_protected::{Controlled, Protected};
101 /// let x = Protected::new(vec![240, 159, 146, 150]);
102 /// let y = x.map_ok(String::from_utf8);
103 /// assert!(matches!(y, Ok(_)));
104 /// assert_eq!(y.unwrap().risky_unwrap(), "💖");
105 /// ```
106 fn map_ok<B, F, E>(self, f: F) -> Result<<Self as ReplaceT<B>>::Output, E>
107 where
108 Self: Sized + ReplaceT<B>,
109 F: FnOnce(<Self as Controlled>::Inner) -> Result<B, E>,
110 <Self as ReplaceT<B>>::Output: Controlled<Inner = B>,
111 B: Zeroize,
112 {
113 f(self.risky_unwrap()).map(<Self as ReplaceT<B>>::Output::init_from_inner)
114 }
115
116 /// Zip two [Controlled] values of the same type together with a function that combines them.
117 ///
118 /// # Example
119 ///
120 /// Add two [Protected] values together.
121 ///
122 /// ```
123 /// use vitaminc_protected::{Controlled, Protected};
124 /// let x = Protected::new(1);
125 /// let y = Protected::new(2);
126 /// let z = x.zip(y, |x, y| x + y);
127 /// assert_eq!(z.risky_unwrap(), 3);
128 /// ```
129 ///
130 /// TODO: Apply Usage trait bounds to prevent accidental broadening of scope
131 /// e.g. `other` must have the same, or broader scope as `self`
132 fn zip<Other, Out, F>(self, b: Other, f: F) -> Protected<Out>
133 where
134 Self: Sized,
135 Other: Controlled,
136 Out: Zeroize,
137 F: FnOnce(Self::Inner, Other::Inner) -> Out,
138 {
139 // TODO: Use Replace private trait
140 Protected::init_from_inner(f(self.risky_unwrap(), b.risky_unwrap()))
141 }
142
143 /// Like `zip` but the second argument is a reference.
144 ///
145 /// # Example
146 ///
147 /// ```
148 /// use vitaminc_protected::{Controlled, Protected};
149 /// let x = Protected::new(String::from("hello "));
150 /// let y = Protected::new(String::from("world"));
151 /// let z = x.zip_ref(&y, |x, y| x + y);
152 /// assert_eq!(z.risky_unwrap(), "hello world");
153 /// ```
154 ///
155 fn zip_ref<'a, A, Other, Out, F>(
156 self,
157 other: &'a Other,
158 f: F,
159 ) -> <Self as ReplaceT<Out>>::Output
160 where
161 A: ?Sized + 'a,
162 Self: Sized + ReplaceT<Out>,
163 <Self as ReplaceT<Out>>::Output: Controlled<Inner = Out>,
164 Other: AsProtectedRef<'a, A>,
165 Out: Zeroize,
166 F: FnOnce(Self::Inner, &A) -> Out,
167 {
168 let arg: ProtectedRef<'a, A> = other.as_protected_ref();
169 <Self as ReplaceT<Out>>::Output::init_from_inner(f(self.risky_unwrap(), arg.inner_ref()))
170 }
171
172 /// Similar to `map` but using references to that the inner value is updated in place.
173 ///
174 /// # Example
175 ///
176 /// ```
177 /// # use vitaminc_protected::{Controlled, Protected};
178 /// let mut x = Protected::new([0u8; 4]);
179 /// x.update(|x| {
180 /// x.iter_mut().for_each(|x| {
181 /// *x += 1;
182 /// });
183 /// });
184 /// assert_eq!(x.risky_unwrap(), [1, 1, 1, 1]);
185 /// ```
186 ///
187 fn update<F>(&mut self, mut f: F)
188 where
189 F: FnMut(&mut Self::Inner),
190 {
191 f(self.inner_mut());
192 }
193
194 /// Update the inner value with another [Controlled] value.
195 /// The inner value of the second argument is passed to the closure.
196 ///
197 /// # Example
198 ///
199 /// ```
200 /// use vitaminc_protected::{Controlled, Protected};
201 /// let mut x = Protected::new([0u8; 32]);
202 /// let y = Protected::new([1u8; 32]);
203 /// x.update_with(y, |x, y| {
204 /// x.copy_from_slice(&y);
205 /// });
206 /// assert_eq!(x.risky_unwrap(), [1u8; 32]);
207 /// ```
208 ///
209 /// TODO: Apply Usage trait bounds to prevent accidental broadening of scope
210 /// e.g. `other` must have the same, or broader scope as `self`
211 fn update_with<Other, F>(&mut self, other: Other, mut f: F)
212 where
213 F: FnMut(&mut Self::Inner, Other::Inner),
214 Other: Controlled,
215 {
216 // FIXME: There's a chance here that other will be dropped and not zeroized correctly
217 // But not all Zeroize types are ZeroizeOnDrop - we may need to yield a wrapper type that Derefs to the inner value
218 // Ditto for the zip method
219 // Either that or just make sure the caller uses zeroize() on the other value :/
220 f(self.inner_mut(), other.risky_unwrap());
221 }
222
223 /// Like `update_with` but the second argument is a reference.
224 ///
225 /// # Example
226 ///
227 /// ```
228 /// # use vitaminc_protected::{Controlled, Protected};
229 /// use vitaminc_protected::AsProtectedRef;
230 ///
231 /// let mut x = Protected::new([0u8; 32]);
232 /// let y = Protected::new([1u8; 32]);
233 /// x.update_with_ref(y.as_protected_ref(), |x, y| {
234 /// x.copy_from_slice(y);
235 /// });
236 /// assert_eq!(x.risky_unwrap(), [1u8; 32]);
237 /// ```
238 ///
239 fn update_with_ref<'a, A, F>(&mut self, other: ProtectedRef<'a, A>, mut f: F)
240 where
241 A: ?Sized + 'a,
242 F: FnMut(&mut Self::Inner, &A),
243 {
244 f(self.inner_mut(), other.inner_ref());
245 }
246
247 /// Iterate over the inner value and wrap each element in a `Protected`.
248 /// `I` must be `Copy` because [Protected] always takes ownership of the inner value.
249 fn iter<'a, I>(&'a self) -> impl Iterator<Item = Protected<I>>
250 where
251 <Self as Controlled>::Inner: AsRef<[I]>,
252 I: Copy + 'a,
253 {
254 self.risky_ref().as_ref().iter().copied().map(Protected)
255 }
256
257 /// Replace the inner value with a new one.
258 /// The new value must be `Self`.
259 ///
260 /// # Example
261 ///
262 /// ```
263 /// use vitaminc_protected::{Controlled, Protected};
264 /// let mut x = Protected::new([0u8; 32]);
265 /// let y = Protected::new([1u8; 32]);
266 /// x.replace(y);
267 /// assert_eq!(x.risky_unwrap(), [1u8; 32]);
268 /// ```
269 ///
270 fn replace(&mut self, new: Self) -> Self
271 where
272 Self: Sized,
273 {
274 Self::init_from_inner(std::mem::replace(self.inner_mut(), new.risky_unwrap()))
275 }
276
277 /// Unwraps the inner value of the [Controlled] type.
278 /// This is a risky operation because it consumes the [Controlled] type and returns the inner value
279 /// negating the protections that the [Controlled] type provides.
280 ///
281 /// **Use with caution!**
282 ///
283 // TODO: Consider feature flagging this method
284 fn risky_unwrap(self) -> Self::Inner;
285
286 /// Provides a reference to the inner value.
287 /// This is a risky operation because it bypasses the protections that the [Controlled] type provides.
288 /// **Use with caution!**
289 fn risky_ref(&self) -> &Self::Inner;
290
291 /// Provides a mutable reference to the inner value.
292 /// This is a risky operation because it bypasses the protections that the [Controlled] type provides.
293 /// **Use with caution!**
294 // TODO: This is an escape hatch until I find a way to work around it
295 // It is needed for the seal_in_place methods for ring and aws-lc
296 fn risky_inner_mut(&mut self) -> &mut Self::Inner {
297 self.inner_mut()
298 }
299}
300
301// TODO: Implement Collect for Protected (or Paranoid) so we can use collect() on iterators
302
303#[cfg(test)]
304mod tests {
305 use crate::{Controlled, Equatable, Exportable, Protected};
306
307 #[test]
308 fn test_map_homogenous_inner() {
309 let x = Protected::new(100u8);
310 let y = x.map(|x| x + 10);
311 assert_eq!(y.risky_unwrap(), 110u8);
312 }
313
314 #[test]
315 fn test_map_different_inner() {
316 let x = Protected::new(100u8);
317 let y: Protected<u16> = x.map(u16::from);
318 assert_eq!(y.risky_unwrap(), 100u16);
319 }
320
321 #[test]
322 fn test_map_adapter_homogenous_inner() {
323 assert_eq!(
324 Exportable::<Protected<u8>>::new(100)
325 .map(|x| x + 10)
326 .risky_unwrap(),
327 110u8
328 );
329 assert_eq!(
330 Equatable::<Protected<u8>>::new(100)
331 .map(|x| x + 10)
332 .risky_unwrap(),
333 110u8
334 );
335 assert_eq!(
336 Exportable::<Equatable<Protected<u8>>>::new(100)
337 .map(|x| x + 10)
338 .risky_unwrap(),
339 110u8
340 );
341 assert_eq!(
342 Equatable::<Exportable<Protected<u8>>>::new(100)
343 .map(|x| x + 10)
344 .risky_unwrap(),
345 110u8
346 );
347 }
348
349 #[test]
350 fn test_map_adapter_different_inner() {
351 assert_eq!(
352 Exportable::<Protected<u8>>::new(100)
353 .map(u16::from)
354 .risky_unwrap(),
355 100u16
356 );
357 assert_eq!(
358 Equatable::<Protected<u8>>::new(100)
359 .map(u16::from)
360 .risky_unwrap(),
361 100u16
362 );
363 assert_eq!(
364 Exportable::<Equatable<Protected<u8>>>::new(100)
365 .map(u16::from)
366 .risky_unwrap(),
367 100u16
368 );
369 assert_eq!(
370 Equatable::<Exportable<Protected<u8>>>::new(100)
371 .map(u16::from)
372 .risky_unwrap(),
373 100u16
374 );
375 }
376}