zeroize/stack.rs
1/// Zeroize `N` bytes of stack space.
2///
3/// Most algorithm implementations use stack to store temporary data.
4/// Such temporaries may contain sensitive information (e.g. cryptgraphic keys)
5/// and can stay on stack after the computation is finished. If an attacker
6/// is able for some reasons to read stack data freely, it may result in
7/// leaking of the sensitive data.
8///
9/// # WARNING
10/// This function requires you to estimate how much stack space is used by your
11/// sensitive computation. This can be done by tools like [`cargo-call-stack`],
12/// but note that stack usage depends on optimization level and compiler flags.
13///
14/// [`cargo-call-stack`]: https://github.com/japaric/cargo-call-stack
15///
16/// Additionally, you must annotate your sensitive function with `#[inline(never)]`.
17///
18/// For example, the following example **DOES NOT** erase stack properly:
19/// ```
20/// pub fn encrypt_data(key: &[u8; 16], data: &mut [u8]) {
21/// leaking_encryption(key, data);
22/// zeroize::zeroize_stack::<65_536>();
23/// }
24/// # fn leaking_encryption(_: &[u8; 16], _: &mut [u8]) {}
25/// ```
26/// `leaking_encryption` may get inlined and `zeroize_stack` will erase
27/// stack memory above the stack frame reserved by `encrypt_data`, i.e.
28/// it will **NOT** erase stack memory used by `leaking_encryption`.
29///
30/// You should wrap your computation in the following way:
31/// ```
32/// #[inline(never)]
33/// fn encrypt_data_inner(key: &[u8; 16], data: &mut [u8]) {
34/// leaking_encryption(key, data);
35/// }
36///
37/// pub fn encrypt_data(key: &[u8; 16], data: &mut [u8]) {
38/// encrypt_data_inner(key, data);
39/// zeroize::zeroize_stack::<65_536>();
40/// }
41/// # fn leaking_encryption(_: &[u8; 16], _: &mut [u8]) {}
42/// ```
43/// Finally, note that `#[inline(never)]` is just a hint and may be ignored
44/// by the compiler. It works properly in practice, but such stack zeroization
45/// should be considered as "best effort" and in cases where it's not enough
46/// you should inspect the generated binary to verify that you got a desired
47/// codegen.
48#[inline(never)]
49pub fn zeroize_stack<const N: usize>() {
50 let buf = [0u8; N];
51 crate::optimization_barrier(&buf);
52}