Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions zeroize/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## 1.9.0 (unreleased)
### Added
- `optimization_barrier` function ([#1261])
- `zeroize_stack` function ([#1331])

### Changed
- Edition changed to 2024 and MSRV bumped to 1.85 ([#1149])

[#1149]: https://github.com/RustCrypto/utils/pull/1149
[#1261]: https://github.com/RustCrypto/utils/pull/1261
[#1331]: https://github.com/RustCrypto/utils/pull/1331

## 1.8.2 (2025-09-29)
### Changed
Expand Down Expand Up @@ -164,15 +166,15 @@ if you would like to support older Rust versions.
## 1.3.0 (2021-04-19)
### Added
- impl `Zeroize` for `Box<[Z]>`
- Clear residual space within `Option
- Clear residual space within `Option`

### Changed
- Ensure `Option` is `None` when zeroized
- Bump MSRV to 1.47

## 1.2.0 (2020-12-09)
### Added
- `Zeroize` support for x86(_64) SIMD registers
- `Zeroize` support for x86(-64) SIMD registers

### Changed
- Simplify `String::zeroize`
Expand Down
3 changes: 3 additions & 0 deletions zeroize/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ mod x86;
mod barrier;
pub use barrier::optimization_barrier;

mod stack;
pub use stack::zeroize_stack;

use core::{
marker::{PhantomData, PhantomPinned},
mem::{MaybeUninit, size_of},
Expand Down
52 changes: 52 additions & 0 deletions zeroize/src/stack.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/// Zeroize `N` bytes of stack space.
///
/// Most algorithm implementations use stack to store temporary data.
/// Such temporaries may contain sensitive information (e.g. cryptgraphic keys)
/// and can stay on stack after the computation is finished. If an attacker
/// is able for some reasons to read stack data freely, it may result in
/// leaking of the sensitive data.
///
/// # WARNING
/// This function requires you to estimate how much stack space is used by your
/// sensitive computation. This can be done by tools like [`cargo-call-stack`],
/// but note that stack usage depends on optimization level and compiler flags.
///
/// [`cargo-call-stack`]: https://github.com/japaric/cargo-call-stack
///
/// Additionally, you must annotate your sensitive function with `#[inline(never)]`.
///
/// For example, the following example **DOES NOT** erase stack properly:
/// ```
/// pub fn encrypt_data(key: &[u8; 16], data: &mut [u8]) {
/// leaking_encryption(key, data);
/// zeroize::zeroize_stack::<65_536>();
/// }
/// # fn leaking_encryption(_: &[u8; 16], _: &mut [u8]) {}
/// ```
/// `leaking_encryption` may get inlined and `zeroize_stack` will erase
/// stack memory above the stack frame reserved by `encrypt_data`, i.e.
/// it will **NOT** erase stack memory used by `leaking_encryption`.
///
/// You should wrap your computation in the following way:
/// ```
/// #[inline(never)]
/// fn encrypt_data_inner(key: &[u8; 16], data: &mut [u8]) {
/// leaking_encryption(key, data);
/// }
///
/// pub fn encrypt_data(key: &[u8; 16], data: &mut [u8]) {
/// encrypt_data_inner(key, data);
/// zeroize::zeroize_stack::<65_536>();
/// }
/// # fn leaking_encryption(_: &[u8; 16], _: &mut [u8]) {}
/// ```
/// Finally, note that `#[inline(never)]` is just a hint and may be ignored
/// by the compiler. It works properly in practice, but such stack zeroization
/// should be considered as "best effort" and in cases where it's not enough
/// you should inspect the generated binary to verify that you got a desired
/// codegen.
#[inline(never)]
pub fn zeroize_stack<const N: usize>() {
let buf = [0u8; N];
crate::optimization_barrier(&buf);
}