Skip to main content

zeroize/
lib.rs

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