Skip to main content

zeroize/
zeroize.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4//! Securely zero memory (a.k.a. zeroize) while avoiding compiler
5//! optimizations.
6//!
7//! This crate implements a portable approach to securely zeroing memory using
8//! techniques which guarantee they won't be "optimized away" by the compiler.
9//!
10//! The [`Zeroize`] trait is the crate's primary API.
11//!
12//! ## About
13//!
14//! Zeroing memory securely is hard: compilers optimize for performance, and in
15//! doing so they love to "optimize away" unnecessary zeroing calls. There are
16//! many documented "tricks" to attempt to avoid these optimizations and ensure
17//! that a zeroing routine is performed reliably.
18//!
19//! This crate isn't about tricks: it uses [`core::ptr::write_volatile`] to
20//! provide easy-to-use, portable zeroing behavior which works on all of Rust's
21//! core number types and slices thereof. On supported architectures a minimal
22//! inline-assembly optimization barrier stops the compiler from eliding the
23//! writes, with a portable `core::hint::black_box` fallback on every other
24//! target.
25//!
26//! - No insecure fallbacks!
27//! - No required dependencies!
28//! - No FFI! A minimal optimization barrier uses inline assembly on supported
29//!   targets, with a portable fallback that keeps **WASM** working.
30//! - `#![no_std]`, i.e. **embedded-friendly**!
31//! - No functionality besides securely zeroing memory!
32//! - (Optional) Custom derive support for zeroing complex structures
33//!
34//! ## Example
35//!
36//! ```
37//! use zeroize::Zeroize;
38//!
39//! // Protip: don't embed secrets in your source code.
40//! // This is just an example.
41//! let mut secret = b"Air shield password: 1,2,3,4,5".to_vec();
42//! // [ ... ] open the air shield here
43//!
44//! // Now that we're done using the secret, zero it out.
45//! secret.zeroize();
46//! ```
47//!
48//! ## Usage
49//!
50//! ### Traits
51//!
52//! The [`Zeroize`] trait is the core API of this crate. It's intended to be impl'd on values that
53//! may-or-may-not contain secrets, for example the `zeroize` crate itself defines them on the
54//! core integers e.g. `u8`, `u16`, `i8`, `i16`, as well as arrays thereof. Its core API is
55//! [`Zeroize::zeroize`], a method which takes `&mut self` and writes over the type's internal
56//! memory with some placeholder value, typically some form of `0`.
57//!
58//! The [`DefaultIsZeroes`] marker trait can be impl'd on types which have a [`Default`] impl that
59//! can be used for [`Zeroize`]. Types which implement this trait receive a blanket impl of the
60//! [`Zeroize`] trait.
61//!
62//! We recommend that types which always contain secrets, and especially ones which need to maintain
63//! complex invariants, do NOT impl the [`Zeroize`] trait, but instead provide a [`Drop`] impl which
64//! takes care of erasing the secret values from memory directly. Such types can mark that they're
65//! doing this with the [`ZeroizeOnDrop`] marker trait. Note that [`ZeroizeOnDrop`] is *just* a
66//! marker trait, and making it actually work requires actually providing a [`Drop`] impl which
67//! takes care of zeroizing secrets.
68//!
69//! Why not impl [`Zeroize`] for such types, e.g. a `SecretKey` type? The problem is [`Zeroize`]
70//! would effectively leave such types in an invalid state, and a sort of use-after-zeroize
71//! condition becomes possible. For that reason, we recommend these types automatically handle
72//! zeroization in their [`Drop`] handler alone.
73//!
74//! ### Supported types
75//!
76//! The [`Zeroize`] trait is impl'd on all of Rust's core scalar types including
77//! integers, floats, `bool`, and `char`.
78//!
79//! Additionally, it's implemented on slices and `IterMut`s of the above types.
80//!
81//! When the `alloc` feature is enabled (which it is by default), it's also
82//! impl'd for `Vec<T>` for the above types as well as `String`, where it provides
83//! [`Vec::clear`] / [`String::clear`]-like behavior (truncating to zero-length)
84//! but ensures the backing memory is securely zeroed with some caveats.
85//!
86//! With the `std` feature enabled (which it is **not** by default), [`Zeroize`]
87//! is also implemented for [`CString`]. After calling `zeroize()` on a `CString`,
88//! its internal buffer will contain exactly one nul byte. The backing
89//! memory is zeroed by converting it to a `Vec<u8>` and back into a `CString`.
90//! (NOTE: see "Stack/Heap Zeroing Notes" for important `Vec`/`String`/`CString` details)
91//!
92//! [`CString`]: https://doc.rust-lang.org/std/ffi/struct.CString.html
93//!
94//! The [`DefaultIsZeroes`] marker trait can be impl'd on types which also
95//! impl [`Default`], which implements [`Zeroize`] by overwriting a value with
96//! the default value.
97//!
98//! ### Custom Derive Support
99//!
100//! This crate has custom derive support for the `Zeroize` trait,
101//! gated under the `zeroize` crate's `derive` Cargo feature,
102//! which automatically calls `zeroize()` on all members of a struct
103//! or tuple struct.
104//!
105//! Attributes supported for `Zeroize`:
106//!
107//! On the item level:
108//! - `#[zeroize(bound = "T: MyTrait")]`: this replaces any trait bounds
109//!   inferred by zeroize
110//!
111//! On the field level:
112//! - `#[zeroize(skip)]`: skips this field or variant when calling `zeroize()`
113//!
114//! Attributes supported for `ZeroizeOnDrop`:
115//!
116//! On the field level:
117//! - `#[zeroize(skip)]`: skips this field or variant when calling `zeroize()`
118//!
119//! Note that the `Zeroize` derive infers a `Zeroize` bound for every type parameter used in a
120//! field. The `ZeroizeOnDrop` derive does not infer any bounds: its generated `Drop` impl
121//! requires each field to implement either `Zeroize` or `ZeroizeOnDrop`, so generic types must
122//! carry the necessary bounds themselves.
123//!
124//! Example which derives `Drop`:
125//!
126//! ```
127//! # #[cfg(feature = "derive")]
128//! # {
129//! use zeroize::{Zeroize, ZeroizeOnDrop};
130//!
131//! // This struct will be zeroized on drop
132//! #[derive(Zeroize, ZeroizeOnDrop)]
133//! struct MyStruct([u8; 32]);
134//! # }
135//! ```
136//!
137//! Example which does not derive `Drop` (useful for e.g. `Copy` types)
138//!
139//! ```
140//! #[cfg(feature = "derive")]
141//! # {
142//! use zeroize::Zeroize;
143//!
144//! // This struct will *NOT* be zeroized on drop
145//! #[derive(Copy, Clone, Zeroize)]
146//! struct MyStruct([u8; 32]);
147//! # }
148//! ```
149//!
150//! Example which only derives `Drop`:
151//!
152//! ```
153//! # #[cfg(feature = "derive")]
154//! # {
155//! use zeroize::ZeroizeOnDrop;
156//!
157//! // This struct will be zeroized on drop
158//! #[derive(ZeroizeOnDrop)]
159//! struct MyStruct([u8; 32]);
160//! # }
161//! ```
162//!
163//! ### `Zeroizing<Z>`: wrapper for zeroizing arbitrary values on drop
164//!
165//! `Zeroizing<Z: Zeroize>` is a generic wrapper type that impls `Deref`
166//! and `DerefMut`, allowing access to an inner value of type `Z`, and also
167//! impls a `Drop` handler which calls `zeroize()` on its contents:
168//!
169//! ```
170//! use zeroize::Zeroizing;
171//!
172//! fn use_secret() {
173//!     let mut secret = Zeroizing::new([0u8; 5]);
174//!
175//!     // Set the air shield password
176//!     // Protip (again): don't embed secrets in your source code.
177//!     secret.copy_from_slice(&[1, 2, 3, 4, 5]);
178//!     assert_eq!(secret.as_ref(), &[1, 2, 3, 4, 5]);
179//!
180//!     // The contents of `secret` will be automatically zeroized on drop
181//! }
182//!
183//! # use_secret()
184//! ```
185//!
186//! ## What guarantees does this crate provide?
187//!
188//! This crate guarantees the zeroing operation can't be "optimized away" by the compiler, as
189//! ensured by LLVM's volatile semantics.
190//!
191//! Previously there were worries that the approach used by this crate (mixing volatile and
192//! non-volatile accesses) was undefined behavior due to language contained
193//! in the documentation for `write_volatile`, however after some discussion
194//! within the [Unsafe Code Guidelines Working Group], [these remarks have been removed] and the
195//! specific usage pattern in this crate is considered to be well-defined.
196//!
197//! All of that said, there is still potential for microarchitectural attacks
198//! (ala Spectre/Meltdown) to leak "zeroized" secrets through covert channels.
199//! This crate makes no guarantees that zeroized values cannot be leaked
200//! through such channels, as they represent flaws in the underlying hardware.
201//!
202//! ## Stack/Heap Zeroing Notes
203//!
204//! This crate can be used to zero values from either the stack or the heap. We recommend storing
205//! sensitive data on the heap whenever possible to reduce the potential for making copies in memory
206//! via Rust move semantics, however note that stack spilling and other optimizations may leave
207//! temporary copies of data from the heap on the stack.
208//!
209//! This crate deliberately does not provide a portable "zeroize the stack" API: identifying the
210//! stack region used by a computation cannot be done reliably from safe Rust, so such an API
211//! tends to give a false sense of security.
212//!
213//! [`Pin`][`core::pin::Pin`] can be leveraged in conjunction with this crate to ensure data kept
214//! on the stack isn't moved.
215//!
216//! The `Zeroize` impls for `Vec`, `String` and `CString` zeroize the entire capacity of their
217//! backing buffer, but cannot guarantee copies of the data were not previously made by buffer
218//! reallocation. It's therefore important when attempting to zeroize such buffers to initialize
219//! them to the correct capacity, and take care to prevent subsequent reallocation.
220//!
221//! The [`secrecy`] crate provides higher-level abstractions for eliminating
222//! usage patterns which can cause reallocations:
223//!
224//! [`secrecy`]: https://docs.rs/secrecy
225//!
226//! ## What about: clearing registers, `mlock()`, `mprotect()`, etc?
227//!
228//! This crate is focused on providing simple, unobtrusive support for reliably
229//! zeroing memory using the best approach possible on stable Rust.
230//!
231//! Clearing registers is a difficult problem that can't easily be solved by
232//! something like a crate, and requires either inline ASM or rustc support.
233//! See <https://github.com/rust-lang/rust/issues/17046> for background on
234//! this particular problem.
235//!
236//! Other memory protection mechanisms are interesting and useful, but often
237//! overkill (e.g. defending against RAM scraping or attackers with swap access).
238//! In as much as there may be merit to these approaches, there are also many
239//! other crates that already implement more sophisticated memory protections.
240//! Such protections are explicitly out-of-scope for this crate.
241//!
242//! Zeroing memory is [good cryptographic hygiene] and this crate seeks to promote
243//! it in the most unobtrusive manner possible. This includes omitting complex
244//! `unsafe` memory protection systems and just trying to make the best memory
245//! zeroing crate available.
246//!
247//! [Unsafe Code Guidelines Working Group]: https://github.com/rust-lang/unsafe-code-guidelines
248//! [these remarks have been removed]: https://github.com/rust-lang/rust/pull/60972
249//! [good cryptographic hygiene]: https://github.com/veorq/cryptocoding#clean-memory-of-secret-data
250//! [`Ordering::SeqCst`]: core::sync::atomic::Ordering::SeqCst
251
252#[cfg(feature = "alloc")]
253extern crate alloc;
254#[cfg(feature = "std")]
255extern crate std;
256
257#[cfg(feature = "derive")]
258pub use zeroize_derive::{Zeroize, ZeroizeOnDrop};
259
260#[cfg(target_arch = "aarch64")]
261mod aarch64;
262#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
263mod x86;
264
265mod barrier;
266#[cfg(feature = "alloc")]
267use alloc::{boxed::Box, string::String, vec::Vec};
268use core::{
269    marker::{PhantomData, PhantomPinned},
270    mem::{MaybeUninit, size_of},
271    num::{
272        self, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8, NonZeroU16,
273        NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
274    },
275    ops, ptr,
276    slice::IterMut,
277};
278#[cfg(feature = "std")]
279use std::ffi::CString;
280
281pub use barrier::optimization_barrier;
282
283/// Trait for securely erasing values from memory.
284pub trait Zeroize {
285    /// Zero out this object from memory using Rust intrinsics which ensure the
286    /// zeroization operation is not "optimized away" by the compiler.
287    fn zeroize(&mut self);
288
289    /// Zeroize every element of `slice`.
290    ///
291    /// This is an implementation detail used by the container impls (`[Z; N]`, `Vec<Z>`,
292    /// `Box<[Z]>`) so they can select the most efficient strategy for the element type: the
293    /// blanket impl for [`DefaultIsZeroes`] types overrides it with a single bulk volatile
294    /// write, while other element types fall back to calling [`zeroize`][Zeroize::zeroize] on
295    /// each element.
296    #[doc(hidden)]
297    fn zeroize_slice(slice: &mut [Self])
298    where
299        Self: Sized,
300    {
301        for elem in slice {
302            elem.zeroize();
303        }
304    }
305}
306
307/// Marker trait signifying that this type will [`Zeroize::zeroize`] itself on [`Drop`].
308pub trait ZeroizeOnDrop {}
309
310/// Marker trait for types whose [`Default`] is the desired zeroization result
311pub trait DefaultIsZeroes: Copy + Default + Sized {}
312
313/// Fallible trait for representing cases where zeroization may or may not be
314/// possible.
315///
316/// This is primarily useful for scenarios like reference counted data, where
317/// zeroization is only possible when the last reference is dropped.
318pub trait TryZeroize {
319    /// Try to zero out this object from memory using Rust intrinsics which
320    /// ensure the zeroization operation is not "optimized away" by the
321    /// compiler.
322    #[must_use]
323    fn try_zeroize(&mut self) -> bool;
324}
325
326impl<Z> Zeroize for Z
327where
328    Z: DefaultIsZeroes,
329{
330    fn zeroize(&mut self) {
331        volatile_write(self, Z::default());
332    }
333
334    fn zeroize_slice(slice: &mut [Z]) {
335        zeroize_slice_default(slice);
336    }
337}
338
339/// Bulk zeroization of a mutable slice of [`DefaultIsZeroes`] elements.
340///
341/// This performs a single volatile set over the whole slice, which is considerably faster than
342/// calling [`Zeroize::zeroize`] once per element.
343#[inline(always)]
344fn zeroize_slice_default<Z: DefaultIsZeroes>(slice: &mut [Z]) {
345    let size = slice.len().checked_mul(size_of::<Z>()).expect("overflow");
346    assert!(isize::try_from(size).is_ok());
347
348    // Safety:
349    //
350    // The slice is well aligned and backed by a single allocation of at least `slice.len()`
351    // elements of type `Z`. `slice.len() * size_of::<Z>()` is at most `isize::MAX` because of the
352    // assertion above, so the memory does not wrap around the address space.
353    unsafe { volatile_set(slice.as_mut_ptr(), Z::default(), slice.len()) };
354}
355
356macro_rules! impl_zeroize_with_default {
357    ($($type:ty),+) => {
358        $(impl DefaultIsZeroes for $type {})+
359    };
360}
361
362#[rustfmt::skip]
363impl_zeroize_with_default! {
364    PhantomPinned, (), bool, char,
365    f32, f64,
366    i8, i16, i32, i64, i128, isize,
367    u8, u16, u32, u64, u128, usize
368}
369
370/// `PhantomPinned` is zero sized so provide a `ZeroizeOnDrop` implementation.
371impl ZeroizeOnDrop for PhantomPinned {}
372
373/// `()` is zero sized so provide a `ZeroizeOnDrop` implementation.
374impl ZeroizeOnDrop for () {}
375
376macro_rules! impl_zeroize_for_non_zero {
377    ($($type:ty),+) => {
378        $(
379            impl Zeroize for $type {
380                fn zeroize(&mut self) {
381                    const ONE: $type = match <$type>::new(1) {
382                        Some(one) => one,
383                        None => unreachable!(),
384                    };
385                    volatile_write(self, ONE);
386                }
387            }
388        )+
389    };
390}
391
392impl_zeroize_for_non_zero!(
393    NonZeroI8,
394    NonZeroI16,
395    NonZeroI32,
396    NonZeroI64,
397    NonZeroI128,
398    NonZeroIsize,
399    NonZeroU8,
400    NonZeroU16,
401    NonZeroU32,
402    NonZeroU64,
403    NonZeroU128,
404    NonZeroUsize
405);
406
407impl<Z> Zeroize for num::Wrapping<Z>
408where
409    Z: Zeroize,
410{
411    fn zeroize(&mut self) {
412        self.0.zeroize();
413    }
414}
415
416/// Impl [`Zeroize`] on arrays of types that impl [`Zeroize`].
417impl<Z, const N: usize> Zeroize for [Z; N]
418where
419    Z: Zeroize,
420{
421    fn zeroize(&mut self) {
422        Z::zeroize_slice(self);
423    }
424}
425
426/// Impl [`ZeroizeOnDrop`] on arrays of types that impl [`ZeroizeOnDrop`].
427impl<Z, const N: usize> ZeroizeOnDrop for [Z; N] where Z: ZeroizeOnDrop {}
428
429impl<Z> Zeroize for IterMut<'_, Z>
430where
431    Z: Zeroize,
432{
433    fn zeroize(&mut self) {
434        for elem in self {
435            elem.zeroize();
436        }
437    }
438}
439
440impl<Z> Zeroize for Option<Z>
441where
442    Z: Zeroize,
443{
444    fn zeroize(&mut self) {
445        if let Some(value) = self {
446            value.zeroize();
447
448            // Ensures self is None and that the value was dropped. Without the take, the drop
449            // of the (zeroized) value isn't called, which might lead to a leak or other
450            // unexpected behavior. For example, if this were Option<Vec<T>>, the above call to
451            // zeroize would not free the allocated memory, but the `take` call will.
452            self.take();
453        }
454
455        // Ensure that if the `Option` were previously `Some` but a value was copied/moved out
456        // that the remaining space in the `Option` is zeroized.
457        //
458        // Safety:
459        //
460        // The memory pointed to by `self` is valid for `size_of::<Self>()` bytes.
461        // It is also properly aligned, because `u8` has an alignment of `1`.
462        unsafe {
463            volatile_set(ptr::from_mut::<Self>(self).cast::<u8>(), 0, size_of::<Self>());
464        }
465
466        // Ensures self is overwritten with the `None` bit pattern. volatile_write can't be
467        // used because Option<Z> is not copy.
468        //
469        // Safety:
470        //
471        // self is safe to replace with `None`, which the take() call above should have
472        // already done semantically. Any value which needed to be dropped will have been
473        // done so by take().
474        unsafe { ptr::write_volatile(self, None) }
475    }
476}
477
478impl<Z> ZeroizeOnDrop for Option<Z> where Z: ZeroizeOnDrop {}
479
480/// Impl [`Zeroize`] on [`MaybeUninit`] types.
481///
482/// This fills the memory with zeroes.
483/// Note that this ignore invariants that `Z` might have, because
484/// [`MaybeUninit`] removes all invariants.
485impl<Z> Zeroize for MaybeUninit<Z> {
486    fn zeroize(&mut self) {
487        // SAFETY: `MaybeUninit` is valid for any byte pattern, including zeros.
488        unsafe { ptr::write_volatile(self, MaybeUninit::zeroed()) }
489    }
490}
491
492/// Impl [`Zeroize`] on slices of [`MaybeUninit`] types.
493///
494/// This impl can eventually be optimized using an memset intrinsic,
495/// such as [`core::intrinsics::volatile_set_memory`].
496///
497/// This fills the slice with zeroes.
498///
499/// Note that this ignore invariants that `Z` might have, because
500/// [`MaybeUninit`] removes all invariants.
501impl<Z> Zeroize for [MaybeUninit<Z>] {
502    fn zeroize(&mut self) {
503        let ptr = self.as_mut_ptr().cast::<MaybeUninit<u8>>();
504        let size = self.len().checked_mul(size_of::<Z>()).expect("overflow");
505        assert!(isize::try_from(size).is_ok());
506
507        // Safety:
508        //
509        // This is safe, because every valid pointer is well aligned for u8
510        // and it is backed by a single allocated object for at least `self.len() * size_of::<Z>()` bytes.
511        // and 0 is a valid value for `MaybeUninit<Z>`
512        // The memory of the slice should not wrap around the address space.
513        unsafe { volatile_set(ptr, MaybeUninit::zeroed(), size) }
514    }
515}
516
517/// Impl [`Zeroize`] on slices of types that can be zeroized with [`Default`].
518///
519/// This impl can eventually be optimized using an memset intrinsic,
520/// such as [`core::intrinsics::volatile_set_memory`]. For that reason the
521/// blanket impl on slices is bounded by [`DefaultIsZeroes`].
522///
523/// To zeroize a mut slice of `Z: Zeroize` which does not impl
524/// [`DefaultIsZeroes`], call `iter_mut().zeroize()`.
525impl<Z> Zeroize for [Z]
526where
527    Z: DefaultIsZeroes,
528{
529    fn zeroize(&mut self) {
530        zeroize_slice_default(self);
531    }
532}
533
534/// Overwrites the contents of the string slice with NUL (`\0`) bytes.
535///
536/// Note that, unlike the `String` implementation, this cannot change the length of the string,
537/// because `str` is a dynamically sized view whose length is stored in the pointer. The result is
538/// therefore a string of the same length whose bytes are all `\0`, which is still valid UTF-8.
539impl Zeroize for str {
540    fn zeroize(&mut self) {
541        // Safety:
542        // A zeroized byte slice is a valid UTF-8 string.
543        unsafe { self.as_bytes_mut().zeroize() }
544    }
545}
546
547/// [`PhantomData`] is always zero sized so provide a [`Zeroize`] implementation.
548impl<Z> Zeroize for PhantomData<Z> {
549    fn zeroize(&mut self) {}
550}
551
552/// [`PhantomData`] is always zero sized so provide a [`ZeroizeOnDrop`] implementation.
553impl<Z> ZeroizeOnDrop for PhantomData<Z> {}
554
555macro_rules! impl_zeroize_tuple {
556    ( $( $type_name:ident ),+ ) => {
557        impl<$($type_name: Zeroize),+> Zeroize for ($($type_name,)+) {
558            fn zeroize(&mut self) {
559                #[allow(non_snake_case)]
560                let ($($type_name,)+) = self;
561                $($type_name.zeroize());+
562            }
563        }
564
565        impl<$($type_name: ZeroizeOnDrop),+> ZeroizeOnDrop for ($($type_name,)+) { }
566    }
567}
568
569// Generic implementations for tuples up to 10 parameters.
570impl_zeroize_tuple!(A);
571impl_zeroize_tuple!(A, B);
572impl_zeroize_tuple!(A, B, C);
573impl_zeroize_tuple!(A, B, C, D);
574impl_zeroize_tuple!(A, B, C, D, E);
575impl_zeroize_tuple!(A, B, C, D, E, F);
576impl_zeroize_tuple!(A, B, C, D, E, F, G);
577impl_zeroize_tuple!(A, B, C, D, E, F, G, H);
578impl_zeroize_tuple!(A, B, C, D, E, F, G, H, I);
579impl_zeroize_tuple!(A, B, C, D, E, F, G, H, I, J);
580
581#[cfg(feature = "alloc")]
582impl<Z> Zeroize for Vec<Z>
583where
584    Z: Zeroize,
585{
586    /// "Best effort" zeroization for `Vec`.
587    ///
588    /// Call `Zeroize` on all `Vec` elements and spare capacity. Cannot ensure that
589    /// previous reallocations did not leave values on the heap.
590    fn zeroize(&mut self) {
591        // Zero the spare (uninitialized) capacity first, i.e. everything
592        // beyond `len`. This must happen before `clear()` resets `len` to 0,
593        // otherwise `spare_capacity_mut()` would cover the whole allocation
594        // and re-zero the initialized elements a second time below.
595        self.spare_capacity_mut().zeroize();
596
597        // Zeroize all the initialized elements.
598        Z::zeroize_slice(self);
599
600        // Set the Vec's length to 0 and drop all the (already-zeroized) elements.
601        self.clear();
602    }
603}
604
605#[cfg(feature = "alloc")]
606impl<Z> ZeroizeOnDrop for Vec<Z> where Z: ZeroizeOnDrop {}
607
608#[cfg(feature = "alloc")]
609impl<Z> Zeroize for Box<[Z]>
610where
611    Z: Zeroize,
612{
613    /// Unlike `Vec`, `Box<[Z]>` cannot reallocate, so we can be sure that we are not leaving
614    /// values on the heap.
615    fn zeroize(&mut self) {
616        Z::zeroize_slice(self);
617    }
618}
619
620#[cfg(feature = "alloc")]
621impl<Z> ZeroizeOnDrop for Box<[Z]> where Z: ZeroizeOnDrop {}
622
623#[cfg(feature = "alloc")]
624impl Zeroize for Box<str> {
625    fn zeroize(&mut self) {
626        self.as_mut().zeroize();
627    }
628}
629
630#[cfg(feature = "alloc")]
631impl Zeroize for String {
632    fn zeroize(&mut self) {
633        // Safety:
634        //
635        // The bytes are immediately zeroized, and a slice of NUL bytes is valid UTF-8, so the
636        // `String` remains a valid UTF-8 buffer (with length 0) when the borrow ends.
637        unsafe { self.as_mut_vec() }.zeroize();
638    }
639}
640
641#[cfg(feature = "std")]
642impl Zeroize for CString {
643    fn zeroize(&mut self) {
644        use core::mem;
645
646        // mem::take uses replace internally to swap the pointer
647        // Unfortunately this results in an allocation for a Box::new(&[0]) as CString must
648        // contain a trailing zero byte
649        let this = mem::take(self);
650
651        // - CString::into_bytes_with_nul calls ::into_vec which takes ownership of the heap pointer
652        // as a Vec<u8>
653        // - Calling .zeroize() on the resulting vector clears out the bytes
654        // From: https://github.com/RustCrypto/utils/pull/759#issuecomment-1087976570
655        let mut buf = this.into_bytes_with_nul();
656        buf.zeroize();
657
658        // expect() should never fail, because zeroize() truncates the Vec
659        let zeroed = CString::new(buf).expect("buf not truncated");
660
661        // Replace the (now empty) `self` with the zeroed `CString`. The original buffer has
662        // already been zeroed above; it may be reused or shrunk in place here, but its previous
663        // contents are gone either way.
664        let _ = mem::replace(self, zeroed);
665    }
666}
667
668/// `Zeroizing` is a wrapper for any `Z: Zeroize` type which implements a
669/// `Drop` handler which zeroizes dropped values.
670///
671/// `Zeroizing<T>` is defined with `repr(transparent)`, which means it is
672/// guaranteed to have the same physical representation as the underlying type.
673#[derive(Default, Eq, PartialEq)]
674#[repr(transparent)]
675pub struct Zeroizing<Z: Zeroize + ?Sized>(Z);
676
677impl<Z: Zeroize + ?Sized> core::fmt::Debug for Zeroizing<Z> {
678    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
679        f.debug_struct("Zeroizing").finish_non_exhaustive()
680    }
681}
682
683impl<Z> Zeroizing<Z>
684where
685    Z: Zeroize,
686{
687    /// Move value inside a `Zeroizing` wrapper which ensures it will be
688    /// zeroized when it's dropped.
689    #[inline(always)]
690    pub fn new(value: Z) -> Self {
691        Self(value)
692    }
693}
694
695impl<Z: Zeroize + Clone> Clone for Zeroizing<Z> {
696    #[inline(always)]
697    fn clone(&self) -> Self {
698        Self(self.0.clone())
699    }
700
701    #[inline(always)]
702    fn clone_from(&mut self, source: &Self) {
703        self.0.zeroize();
704        self.0.clone_from(&source.0);
705    }
706}
707
708impl<Z> From<Z> for Zeroizing<Z>
709where
710    Z: Zeroize,
711{
712    #[inline(always)]
713    fn from(value: Z) -> Zeroizing<Z> {
714        Zeroizing(value)
715    }
716}
717
718impl<Z> ops::Deref for Zeroizing<Z>
719where
720    Z: Zeroize + ?Sized,
721{
722    type Target = Z;
723
724    #[inline(always)]
725    fn deref(&self) -> &Z {
726        &self.0
727    }
728}
729
730impl<Z> ops::DerefMut for Zeroizing<Z>
731where
732    Z: Zeroize + ?Sized,
733{
734    #[inline(always)]
735    fn deref_mut(&mut self) -> &mut Z {
736        &mut self.0
737    }
738}
739
740impl<T, Z> AsRef<T> for Zeroizing<Z>
741where
742    T: ?Sized,
743    Z: AsRef<T> + Zeroize + ?Sized,
744{
745    #[inline(always)]
746    fn as_ref(&self) -> &T {
747        self.0.as_ref()
748    }
749}
750
751impl<T, Z> AsMut<T> for Zeroizing<Z>
752where
753    T: ?Sized,
754    Z: AsMut<T> + Zeroize + ?Sized,
755{
756    #[inline(always)]
757    fn as_mut(&mut self) -> &mut T {
758        self.0.as_mut()
759    }
760}
761
762impl<Z> Zeroize for Zeroizing<Z>
763where
764    Z: Zeroize + ?Sized,
765{
766    fn zeroize(&mut self) {
767        self.0.zeroize();
768    }
769}
770
771impl<Z> ZeroizeOnDrop for Zeroizing<Z> where Z: Zeroize + ?Sized {}
772
773impl<Z> Drop for Zeroizing<Z>
774where
775    Z: Zeroize + ?Sized,
776{
777    fn drop(&mut self) {
778        self.0.zeroize();
779    }
780}
781
782#[cfg(feature = "serde")]
783impl<Z> serde::Serialize for Zeroizing<Z>
784where
785    Z: Zeroize + serde::Serialize + ?Sized,
786{
787    #[inline(always)]
788    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
789    where
790        S: serde::Serializer,
791    {
792        self.0.serialize(serializer)
793    }
794}
795
796#[cfg(feature = "serde")]
797impl<'de, Z> serde::Deserialize<'de> for Zeroizing<Z>
798where
799    Z: Zeroize + serde::Deserialize<'de>,
800{
801    #[inline(always)]
802    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
803    where
804        D: serde::Deserializer<'de>,
805    {
806        Ok(Self(Z::deserialize(deserializer)?))
807    }
808}
809
810/// Perform a volatile write to the destination
811#[inline(always)]
812fn volatile_write<T: Copy + Sized>(dst: &mut T, src: T) {
813    // Safety:
814    //
815    // `dst` is a valid, aligned reference, so it is valid for a write of `size_of::<T>()` bytes,
816    // and `src` is a valid `T`.
817    unsafe { ptr::write_volatile(dst, src) }
818}
819
820/// Perform a volatile `memset` operation which fills a slice with a value
821///
822/// # Safety
823/// The memory pointed to by `dst` must be a single allocated object that is valid for `count`
824/// contiguous elements of `T`.
825/// `count` must not be larger than an `isize`.
826/// `dst` being offset by `size_of::<T> * count` bytes must not wrap around the address space.
827/// Also `dst` must be properly aligned.
828#[inline(always)]
829unsafe fn volatile_set<T: Copy + Sized>(dst: *mut T, src: T, count: usize) {
830    // TODO(tarcieri): use `volatile_set_memory` when stabilized
831    //
832    // Zero-sized types have nothing to write.
833    if size_of::<T>() == 0 {
834        return;
835    }
836
837    // Fast path: for 1-byte types (e.g. `u8`, `i8`, `bool` or `MaybeUninit<u8>`) the value's
838    // bytes can be replicated across machine words and written with far fewer volatile stores.
839    // This is the common case for byte buffers such as `Vec<u8>` and `String`.
840    if size_of::<T>() == 1 {
841        // Safety:
842        //
843        // `T` has size 1 and implements `Copy`, so `src` consists of exactly one initialized,
844        // valid byte with no padding, and may be read as a `u8`.
845        let byte = unsafe { *(&src as *const T).cast::<u8>() };
846
847        // Safety:
848        //
849        // `dst` and `count` satisfy the requirements of `volatile_set_bytes` (which are the same
850        // as this function's), and `byte` is a valid `u8`.
851        unsafe { volatile_set_bytes(dst.cast::<u8>(), byte, count) };
852        return;
853    }
854
855    for i in 0..count {
856        // Safety:
857        //
858        // This is safe because there is room for at least `count` objects of type `T` in the
859        // allocation pointed to by `dst`, because `count <= isize::MAX` and because
860        // `dst.add(count)` must not wrap around the address space.
861        let ptr = unsafe { dst.add(i) };
862
863        // Safety:
864        //
865        // This is safe, because the pointer is valid and because `dst` is well aligned for `T` and
866        // `ptr` is an offset of `dst` by a multiple of `size_of::<T>()` bytes.
867        unsafe { ptr::write_volatile(ptr, src) };
868    }
869}
870
871/// Volatile `memset` of `count` bytes at `dst` with `byte`.
872///
873/// Writes are performed a machine word at a time once the destination is word-aligned (with
874/// leading/trailing single-byte writes to cover any misalignment), which issues substantially
875/// fewer volatile stores than a byte-at-a-time loop.
876///
877/// # Safety
878/// Same requirements as [`volatile_set`], for `T = u8`.
879#[inline(always)]
880unsafe fn volatile_set_bytes(dst: *mut u8, byte: u8, count: usize) {
881    let word_size = size_of::<usize>();
882
883    // Write single bytes until the destination is aligned for a `usize` store.
884    let head = (word_size - (dst as usize % word_size)) % word_size;
885    let head = head.min(count);
886    for i in 0..head {
887        // Safety:
888        //
889        // `i < head <= count`, so `dst.add(i)` is within the allocation, and `dst` is a valid
890        // (align 1) pointer.
891        unsafe { ptr::write_volatile(dst.add(i), byte) };
892    }
893
894    let word = usize::from_ne_bytes([byte; size_of::<usize>()]);
895    let mut i = head;
896    while i + word_size <= count {
897        // Safety:
898        //
899        // `i + word_size <= count`, so `dst.add(i)` covers `word_size` in-bounds bytes, and it is
900        // aligned for `usize` because `i` is a multiple of `word_size` past an aligned `head`.
901        unsafe { ptr::write_volatile(dst.add(i).cast::<usize>(), word) };
902        i += word_size;
903    }
904
905    while i < count {
906        // Safety:
907        //
908        // `i < count`, so `dst.add(i)` is within the allocation.
909        unsafe { ptr::write_volatile(dst.add(i), byte) };
910        i += 1;
911    }
912}
913
914/// Internal module used as support for `AssertZeroizeOnDrop`.
915#[doc(hidden)]
916pub mod __internal {
917    use super::*;
918
919    /// Auto-deref workaround for deriving `ZeroizeOnDrop`.
920    pub trait AssertZeroizeOnDrop {
921        fn zeroize_or_on_drop(self);
922    }
923
924    impl<T: ZeroizeOnDrop + ?Sized> AssertZeroizeOnDrop for &&mut T {
925        fn zeroize_or_on_drop(self) {}
926    }
927
928    /// Auto-deref workaround for deriving `ZeroizeOnDrop`.
929    pub trait AssertZeroize {
930        fn zeroize_or_on_drop(&mut self);
931    }
932
933    impl<T: Zeroize + ?Sized> AssertZeroize for T {
934        fn zeroize_or_on_drop(&mut self) {
935            self.zeroize();
936        }
937    }
938}