umbral_pre/
secret_box.rs

1/*
2This module implements a similar API to what the crate `secrecy` provides.
3So, why our own implementation?
4
5First `secrecy::Secret<T>` does not put its contents in a `Box`.
6Using `Box` is a general recommendation of working with secret data,
7because it prevents the compiler from putting it on stack, thus avoiding possible copies on borrow.
8
9Now, one could use `secrecy::Secret<Box<T>>`.
10The problem here is that `secrecy::Secret` requires its type parameter to implement `Zeroize`.
11This means that for a foreign type `F` (even if it does implement `Zeroize`)
12we need to define `impl Zeroize for Box<F>`.
13But the compiler does not allow impls of foreign traits on foreign types.
14This means that we also need to wrap `F` in a local type, impl `Zeroize` for the wrapper,
15and then for the box of the wrapper.
16This is too much boilerplate.
17
18Additionally, `secrecy::Secret<Box<T>>` means that after each `expose_secret()`
19we will need to deal with opening the `Box` as well.
20It's an inconvenience, albeit a minor one.
21
22The situation may improve in the future, and `secrecy` will actually become usable.
23*/
24
25use alloc::boxed::Box;
26
27use zeroize::{Zeroize, ZeroizeOnDrop};
28
29/// A container for secret data.
30/// Makes the usage of secret data explicit and easy to track,
31/// prevents the secret data from being put on stack,
32/// and zeroizes the contents on drop.
33#[derive(Clone)] // No Debug derivation, to avoid exposing the secret data accidentally.
34pub struct SecretBox<T>(Box<T>)
35where
36    T: Zeroize + Clone;
37
38impl<T: PartialEq + Zeroize + Clone> PartialEq<SecretBox<T>> for SecretBox<T> {
39    fn eq(&self, other: &Self) -> bool {
40        self.0 == other.0
41    }
42}
43
44impl<T> SecretBox<T>
45where
46    T: Zeroize + Clone,
47{
48    pub(crate) fn new(val: T) -> Self {
49        Self(Box::new(val))
50    }
51
52    /// Returns an immutable reference to the secret data.
53    pub fn as_secret(&self) -> &T {
54        self.0.as_ref()
55    }
56
57    /// Returns a mutable reference to the secret data.
58    pub fn as_mut_secret(&mut self) -> &mut T {
59        self.0.as_mut()
60    }
61}
62
63impl<T> Drop for SecretBox<T>
64where
65    T: Zeroize + Clone,
66{
67    fn drop(&mut self) {
68        self.0.zeroize()
69    }
70}
71
72// Alternatively, it could be derived automatically,
73// but there's some compilation problem in the macro.
74// See https://github.com/RustCrypto/utils/issues/786
75// So we're asserting that this object is zeroized on drop, since there is a Drop impl just above.
76impl<T> ZeroizeOnDrop for SecretBox<T> where T: Zeroize + Clone {}