pub struct Secret<T: Bytes> { /* private fields */ }
Expand description
A type for protecting secrets allocated on the stack.
Stack-allocated secrets have distinct security needs from heap-allocated secrets, and should be preferred when possible. They provide the following guarantees:
mlock(2)
is called on the underlying memorymunlock(2)
is called on the underlying memory when no longer in use- the underlying memory is zeroed out when no longer in use
- they are borrowed for their entire lifespan, so cannot be moved
- they are best-effort compared in constant time
- they are best-effort prevented from being printed by
Debug
- they are best-effort prevented from being
Clone
d
To fulfill these guarantees, Secret
s are constructed in an
atypical pattern. Rather than having new
return a
newly-created instance, new
accepts a callback
argument that is provided with a mutably borrowed wrapper around the
data in question. This wrapper Deref
s into the desired type,
with replacement implementations of Debug
, PartialEq
, and
Eq
to prevent accidental misuse.
Users must take care when dereferencing secrets as this will
provide direct access to the underlying type. If the bare type
implements traits like Clone
, Debug
, and PartialEq
,
those methods can be called directly and will not benefit from the
protections provided by this wrapper.
Users must also take care to avoid unintentionally invoking
Copy
on the underlying data, as doing so will result in
secret data being copied out of the Secret
, thus losing the
protections provided by this library. Be careful not to invoke
methods that take ownership of self
or functions that move
parameters with secret data, since doing so will implicitly create
copies.
§Example: generate a cryptographically-random 128-bit Secret
Initialize a Secret
with cryptographically random data:
Secret::<[u8; 16]>::random(|s| {
// use `s` as if it were a `&mut [u8; 16]`
});
§Example: move mutable data into a Secret
Existing data can be moved into a Secret
. When doing so, we make
a best-effort attempt to zero out the data in the original location.
Any prior copies will be unaffected, so please exercise as much
caution as possible when handling data before it can be protected.
let mut value = [1u8, 2, 3, 4];
// the contents of `value` will be copied into the Secret before
// being zeroed out
Secret::from(&mut value, |s| {
assert_eq!(*s, [1, 2, 3, 4]);
});
// the contents of `value` have been zeroed
assert_eq!(value, [0, 0, 0, 0]);
Implementations§
Source§impl<T: Bytes> Secret<T>
impl<T: Bytes> Secret<T>
Sourcepub fn new<F, U>(f: F) -> Uwhere
F: FnOnce(RefMut<'_, T>) -> U,
pub fn new<F, U>(f: F) -> Uwhere
F: FnOnce(RefMut<'_, T>) -> U,
Creates a new Secret
and invokes the provided callback with
a wrapper to the protected memory. This memory will be filled
with a well-defined, arbitrary byte pattern, and should be
initialized to something meaningful before actual use.
§Panics
This function will panic if the underlying call to mlock(2)
(VirtualLock
on windows) fails.
use std::fs::File;
use std::io::prelude::*;
Secret::<[u8; 32]>::new(|mut s| {
File::open("/dev/urandom")?.read_exact(&mut s[..])
});
Source§impl<T: Bytes + Zeroable> Secret<T>
impl<T: Bytes + Zeroable> Secret<T>
Sourcepub fn zero<F, U>(f: F) -> Uwhere
F: FnOnce(RefMut<'_, T>) -> U,
pub fn zero<F, U>(f: F) -> Uwhere
F: FnOnce(RefMut<'_, T>) -> U,
Creates a new Secret
filled with zeroed bytes and invokes the
callback with a wrapper to the protected memory.
Secret::<u8>::zero(|s| {
assert_eq!(*s, 0);
});
Sourcepub fn from<F, U>(v: &mut T, f: F) -> Uwhere
F: FnOnce(RefMut<'_, T>) -> U,
pub fn from<F, U>(v: &mut T, f: F) -> Uwhere
F: FnOnce(RefMut<'_, T>) -> U,
Creates a new Secret
from existing, unprotected data, and
immediately zeroes out the memory of the data being moved in.
Invokes the callback with a wrapper to the protected memory.
let mut bytes : [u32; 4] = [1, 2, 3, 4];
Secret::from(&mut bytes, |s| {
assert_eq!(*s, [1, 2, 3, 4]);
});
assert_eq!(bytes, [0, 0, 0, 0]);