Coverage Report

Created: 2026-07-30 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zeroize-1.9.0/src/lib.rs
Line
Count
Source
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")]
209
extern crate alloc;
210
#[cfg(feature = "std")]
211
extern crate std;
212
213
#[cfg(feature = "zeroize_derive")]
214
pub use zeroize_derive::{Zeroize, ZeroizeOnDrop};
215
216
#[cfg(target_arch = "aarch64")]
217
mod aarch64;
218
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
219
mod x86;
220
221
mod barrier;
222
pub use barrier::optimization_barrier;
223
224
mod stack;
225
pub use stack::zeroize_stack;
226
227
use 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")]
239
use alloc::{boxed::Box, string::String, vec::Vec};
240
241
#[cfg(feature = "std")]
242
use std::ffi::CString;
243
244
/// Trait for securely erasing values from memory.
245
pub 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`].
252
pub trait ZeroizeOnDrop {}
253
254
/// Marker trait for types whose [`Default`] is the desired zeroization result
255
pub 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.
262
pub 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
270
impl<Z> Zeroize for Z
271
where
272
    Z: DefaultIsZeroes,
273
{
274
0
    fn zeroize(&mut self) {
275
0
        volatile_write(self, Z::default());
276
0
        optimization_barrier(self);
277
0
    }
278
}
279
280
macro_rules! impl_zeroize_with_default {
281
    ($($type:ty),+) => {
282
        $(impl DefaultIsZeroes for $type {})+
283
    };
284
}
285
286
#[rustfmt::skip]
287
impl_zeroize_with_default! {
288
    PhantomPinned, (), bool, char,
289
    f32, f64,
290
    i8, i16, i32, i64, i128, isize,
291
    u8, u16, u32, u64, u128, usize
292
}
293
294
/// `PhantomPinned` is zero sized so provide a `ZeroizeOnDrop` implementation.
295
impl ZeroizeOnDrop for PhantomPinned {}
296
297
/// `()` is zero sized so provide a `ZeroizeOnDrop` implementation.
298
impl ZeroizeOnDrop for () {}
299
300
macro_rules! impl_zeroize_for_non_zero {
301
    ($($type:ty),+) => {
302
        $(
303
            impl Zeroize for $type {
304
0
                fn zeroize(&mut self) {
305
                    const ONE: $type = match <$type>::new(1) {
306
                        Some(one) => one,
307
                        None => unreachable!(),
308
                    };
309
0
                    volatile_write(self, ONE);
310
0
                    optimization_barrier(self);
311
0
                }
Unexecuted instantiation: <core::num::nonzero::NonZero<i8> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<i16> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<i32> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<i64> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<i128> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<isize> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<u8> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<u16> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<u32> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<u64> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<u128> as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <core::num::nonzero::NonZero<usize> as zeroize::Zeroize>::zeroize
312
            }
313
        )+
314
    };
315
}
316
317
impl_zeroize_for_non_zero!(
318
    NonZeroI8,
319
    NonZeroI16,
320
    NonZeroI32,
321
    NonZeroI64,
322
    NonZeroI128,
323
    NonZeroIsize,
324
    NonZeroU8,
325
    NonZeroU16,
326
    NonZeroU32,
327
    NonZeroU64,
328
    NonZeroU128,
329
    NonZeroUsize
330
);
331
332
impl<Z> Zeroize for num::Wrapping<Z>
333
where
334
    Z: Zeroize,
335
{
336
0
    fn zeroize(&mut self) {
337
0
        self.0.zeroize();
338
0
    }
339
}
340
341
/// Impl [`Zeroize`] on arrays of types that impl [`Zeroize`].
342
impl<Z, const N: usize> Zeroize for [Z; N]
343
where
344
    Z: Zeroize,
345
{
346
0
    fn zeroize(&mut self) {
347
0
        self.iter_mut().zeroize();
348
0
    }
Unexecuted instantiation: <[u8; 32] as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <[u8; 48] as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <[u8; 64] as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <[_; _] as zeroize::Zeroize>::zeroize
349
}
350
351
/// Impl [`ZeroizeOnDrop`] on arrays of types that impl [`ZeroizeOnDrop`].
352
impl<Z, const N: usize> ZeroizeOnDrop for [Z; N] where Z: ZeroizeOnDrop {}
353
354
impl<Z> Zeroize for IterMut<'_, Z>
355
where
356
    Z: Zeroize,
357
{
358
0
    fn zeroize(&mut self) {
359
0
        for elem in self {
360
0
            elem.zeroize();
361
0
        }
362
0
    }
363
}
364
365
impl<Z> Zeroize for Option<Z>
366
where
367
    Z: Zeroize,
368
{
369
0
    fn zeroize(&mut self) {
370
0
        if let Some(value) = self {
371
0
            value.zeroize();
372
0
373
0
            // Ensures self is None and that the value was dropped. Without the take, the drop
374
0
            // of the (zeroized) value isn't called, which might lead to a leak or other
375
0
            // unexpected behavior. For example, if this were Option<Vec<T>>, the above call to
376
0
            // zeroize would not free the allocated memory, but the `take` call will.
377
0
            self.take();
378
0
        }
379
380
        // Ensure that if the `Option` were previously `Some` but a value was copied/moved out
381
        // that the remaining space in the `Option` is zeroized.
382
        //
383
        // Safety:
384
        //
385
        // The memory pointed to by `self` is valid for `size_of::<Self>()` bytes.
386
        // It is also properly aligned, because `u8` has an alignment of `1`.
387
0
        unsafe {
388
0
            volatile_set(
389
0
                ptr::from_mut::<Self>(self).cast::<u8>(),
390
0
                0,
391
0
                size_of::<Self>(),
392
0
            );
393
0
        }
394
395
        // Ensures self is overwritten with the `None` bit pattern. volatile_write can't be
396
        // used because Option<Z> is not copy.
397
        //
398
        // Safety:
399
        //
400
        // self is safe to replace with `None`, which the take() call above should have
401
        // already done semantically. Any value which needed to be dropped will have been
402
        // done so by take().
403
0
        unsafe { ptr::write_volatile(self, None) }
404
405
0
        optimization_barrier(self);
406
0
    }
407
}
408
409
impl<Z> ZeroizeOnDrop for Option<Z> where Z: ZeroizeOnDrop {}
410
411
/// Impl [`Zeroize`] on [`MaybeUninit`] types.
412
///
413
/// This fills the memory with zeroes.
414
/// Note that this ignore invariants that `Z` might have, because
415
/// [`MaybeUninit`] removes all invariants.
416
impl<Z> Zeroize for MaybeUninit<Z> {
417
0
    fn zeroize(&mut self) {
418
        // Safety:
419
        // `MaybeUninit` is valid for any byte pattern, including zeros.
420
0
        unsafe { ptr::write_volatile(self, MaybeUninit::zeroed()) }
421
0
        optimization_barrier(self);
422
0
    }
423
}
424
425
/// Impl [`Zeroize`] on slices of [`MaybeUninit`] types.
426
///
427
/// This impl can eventually be optimized using an memset intrinsic,
428
/// such as [`core::intrinsics::volatile_set_memory`].
429
///
430
/// This fills the slice with zeroes.
431
///
432
/// Note that this ignore invariants that `Z` might have, because
433
/// [`MaybeUninit`] removes all invariants.
434
impl<Z> Zeroize for [MaybeUninit<Z>] {
435
0
    fn zeroize(&mut self) {
436
0
        let ptr = self.as_mut_ptr().cast::<MaybeUninit<u8>>();
437
0
        let size = self.len().checked_mul(size_of::<Z>()).expect("overflow");
438
0
        assert!(isize::try_from(size).is_ok());
439
440
        // Safety:
441
        //
442
        // This is safe, because every valid pointer is well aligned for u8
443
        // and it is backed by a single allocated object for at least `self.len() * size_pf::<Z>()` bytes.
444
        // and 0 is a valid value for `MaybeUninit<Z>`
445
        // The memory of the slice should not wrap around the address space.
446
0
        unsafe { volatile_set(ptr, MaybeUninit::zeroed(), size) }
447
0
        optimization_barrier(self);
448
0
    }
449
}
450
451
/// Impl [`Zeroize`] on slices of types that can be zeroized with [`Default`].
452
///
453
/// This impl can eventually be optimized using an memset intrinsic,
454
/// such as [`core::intrinsics::volatile_set_memory`]. For that reason the
455
/// blanket impl on slices is bounded by [`DefaultIsZeroes`].
456
///
457
/// To zeroize a mut slice of `Z: Zeroize` which does not impl
458
/// [`DefaultIsZeroes`], call `iter_mut().zeroize()`.
459
impl<Z> Zeroize for [Z]
460
where
461
    Z: DefaultIsZeroes,
462
{
463
0
    fn zeroize(&mut self) {
464
0
        assert!(isize::try_from(self.len()).is_ok());
465
466
        // Safety:
467
        //
468
        // This is safe, because the slice is well aligned and is backed by a single allocated
469
        // object for at least `self.len()` elements of type `Z`.
470
        // `self.len()` is also not larger than an `isize`, because of the assertion above.
471
        // The memory of the slice should not wrap around the address space.
472
0
        unsafe { volatile_set(self.as_mut_ptr(), Z::default(), self.len()) };
473
0
        optimization_barrier(self);
474
0
    }
475
}
476
477
impl Zeroize for str {
478
0
    fn zeroize(&mut self) {
479
        // Safety:
480
        // A zeroized byte slice is a valid UTF-8 string.
481
0
        unsafe { self.as_bytes_mut().zeroize() }
482
0
    }
483
}
484
485
/// [`PhantomData`] is always zero sized so provide a [`Zeroize`] implementation.
486
impl<Z> Zeroize for PhantomData<Z> {
487
0
    fn zeroize(&mut self) {}
488
}
489
490
/// [`PhantomData` is always zero sized so provide a `ZeroizeOnDrop` implementation.
491
impl<Z> ZeroizeOnDrop for PhantomData<Z> {}
492
493
macro_rules! impl_zeroize_tuple {
494
    ( $( $type_name:ident ),+ ) => {
495
        impl<$($type_name: Zeroize),+> Zeroize for ($($type_name,)+) {
496
0
            fn zeroize(&mut self) {
497
                #[allow(non_snake_case)]
498
0
                let ($($type_name,)+) = self;
499
0
                $($type_name.zeroize());+
500
0
            }
Unexecuted instantiation: <(_, _, _) as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <(_, _, _, _) as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <(_, _, _, _, _) as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <(_, _, _, _, _, _) as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <(_, _, _, _, _, _, _) as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <(_, _, _, _, _, _, _, _) as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _) as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _) as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <(_,) as zeroize::Zeroize>::zeroize
Unexecuted instantiation: <(_, _) as zeroize::Zeroize>::zeroize
501
        }
502
503
        impl<$($type_name: ZeroizeOnDrop),+> ZeroizeOnDrop for ($($type_name,)+) { }
504
    }
505
}
506
507
// Generic implementations for tuples up to 10 parameters.
508
impl_zeroize_tuple!(A);
509
impl_zeroize_tuple!(A, B);
510
impl_zeroize_tuple!(A, B, C);
511
impl_zeroize_tuple!(A, B, C, D);
512
impl_zeroize_tuple!(A, B, C, D, E);
513
impl_zeroize_tuple!(A, B, C, D, E, F);
514
impl_zeroize_tuple!(A, B, C, D, E, F, G);
515
impl_zeroize_tuple!(A, B, C, D, E, F, G, H);
516
impl_zeroize_tuple!(A, B, C, D, E, F, G, H, I);
517
impl_zeroize_tuple!(A, B, C, D, E, F, G, H, I, J);
518
519
#[cfg(feature = "alloc")]
520
impl<Z> Zeroize for Vec<Z>
521
where
522
    Z: Zeroize,
523
{
524
    /// "Best effort" zeroization for `Vec`.
525
    ///
526
    /// Ensures the entire capacity of the `Vec` is zeroed. Cannot ensure that
527
    /// previous reallocations did not leave values on the heap.
528
0
    fn zeroize(&mut self) {
529
        // Zeroize all the initialized elements.
530
0
        self.iter_mut().zeroize();
531
532
        // Set the Vec's length to 0 and drop all the elements.
533
0
        self.clear();
534
535
        // Zero the full capacity of `Vec`.
536
0
        self.spare_capacity_mut().zeroize();
537
0
    }
538
}
539
540
#[cfg(feature = "alloc")]
541
impl<Z> ZeroizeOnDrop for Vec<Z> where Z: ZeroizeOnDrop {}
542
543
#[cfg(feature = "alloc")]
544
impl<Z> Zeroize for Box<[Z]>
545
where
546
    Z: Zeroize,
547
{
548
    /// Unlike `Vec`, `Box<[Z]>` cannot reallocate, so we can be sure that we are not leaving
549
    /// values on the heap.
550
0
    fn zeroize(&mut self) {
551
0
        self.iter_mut().zeroize();
552
0
    }
553
}
554
555
#[cfg(feature = "alloc")]
556
impl<Z> ZeroizeOnDrop for Box<[Z]> where Z: ZeroizeOnDrop {}
557
558
#[cfg(feature = "alloc")]
559
impl Zeroize for Box<str> {
560
0
    fn zeroize(&mut self) {
561
0
        self.as_mut().zeroize();
562
0
    }
563
}
564
565
#[cfg(feature = "alloc")]
566
impl Zeroize for String {
567
0
    fn zeroize(&mut self) {
568
0
        unsafe { self.as_mut_vec() }.zeroize();
569
0
    }
570
}
571
572
#[cfg(feature = "std")]
573
impl Zeroize for CString {
574
    fn zeroize(&mut self) {
575
        use core::mem;
576
577
        // mem::take uses replace internally to swap the pointer
578
        // Unfortunately this results in an allocation for a Box::new(&[0]) as CString must
579
        // contain a trailing zero byte
580
        let this = mem::take(self);
581
582
        // - CString::into_bytes_with_nul calls ::into_vec which takes ownership of the heap pointer
583
        // as a Vec<u8>
584
        // - Calling .zeroize() on the resulting vector clears out the bytes
585
        // From: https://github.com/RustCrypto/utils/pull/759#issuecomment-1087976570
586
        let mut buf = this.into_bytes_with_nul();
587
        buf.zeroize();
588
589
        // expect() should never fail, because zeroize() truncates the Vec
590
        let zeroed = CString::new(buf).expect("buf not truncated");
591
592
        // Replace self by the zeroed CString to maintain the original ptr of the buffer
593
        let _ = mem::replace(self, zeroed);
594
    }
595
}
596
597
/// `Zeroizing` is a wrapper for any `Z: Zeroize` type which implements a
598
/// `Drop` handler which zeroizes dropped values.
599
///
600
/// `Zeroizing<T>` is defined with `repr(transparent)`, which means it is
601
/// guaranteed to have the same physical representation as the underlying type.
602
#[derive(Debug, Default, Eq, PartialEq)]
603
#[repr(transparent)]
604
pub struct Zeroizing<Z: Zeroize + ?Sized>(Z);
605
606
impl<Z> Zeroizing<Z>
607
where
608
    Z: Zeroize,
609
{
610
    /// Move value inside a `Zeroizing` wrapper which ensures it will be
611
    /// zeroized when it's dropped.
612
    #[inline(always)]
613
0
    pub fn new(value: Z) -> Self {
614
0
        Self(value)
615
0
    }
Unexecuted instantiation: <zeroize::Zeroizing<rustls::msgs::base::PayloadU8>>::new
Unexecuted instantiation: <zeroize::Zeroizing<_>>::new
616
}
617
618
impl<Z: Zeroize + Clone> Clone for Zeroizing<Z> {
619
    #[inline(always)]
620
0
    fn clone(&self) -> Self {
621
0
        Self(self.0.clone())
622
0
    }
Unexecuted instantiation: <zeroize::Zeroizing<rustls::msgs::base::PayloadU8> as core::clone::Clone>::clone
Unexecuted instantiation: <zeroize::Zeroizing<_> as core::clone::Clone>::clone
623
624
    #[inline(always)]
625
0
    fn clone_from(&mut self, source: &Self) {
626
0
        self.0.zeroize();
627
0
        self.0.clone_from(&source.0);
628
0
    }
629
}
630
631
impl<Z> From<Z> for Zeroizing<Z>
632
where
633
    Z: Zeroize,
634
{
635
    #[inline(always)]
636
0
    fn from(value: Z) -> Zeroizing<Z> {
637
0
        Zeroizing(value)
638
0
    }
639
}
640
641
impl<Z> ops::Deref for Zeroizing<Z>
642
where
643
    Z: Zeroize + ?Sized,
644
{
645
    type Target = Z;
646
647
    #[inline(always)]
648
0
    fn deref(&self) -> &Z {
649
0
        &self.0
650
0
    }
Unexecuted instantiation: <zeroize::Zeroizing<rustls::msgs::base::PayloadU8> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zeroize::Zeroizing<_> as core::ops::deref::Deref>::deref
651
}
652
653
impl<Z> ops::DerefMut for Zeroizing<Z>
654
where
655
    Z: Zeroize + ?Sized,
656
{
657
    #[inline(always)]
658
0
    fn deref_mut(&mut self) -> &mut Z {
659
0
        &mut self.0
660
0
    }
661
}
662
663
impl<T, Z> AsRef<T> for Zeroizing<Z>
664
where
665
    T: ?Sized,
666
    Z: AsRef<T> + Zeroize + ?Sized,
667
{
668
    #[inline(always)]
669
0
    fn as_ref(&self) -> &T {
670
0
        self.0.as_ref()
671
0
    }
672
}
673
674
impl<T, Z> AsMut<T> for Zeroizing<Z>
675
where
676
    T: ?Sized,
677
    Z: AsMut<T> + Zeroize + ?Sized,
678
{
679
    #[inline(always)]
680
0
    fn as_mut(&mut self) -> &mut T {
681
0
        self.0.as_mut()
682
0
    }
683
}
684
685
impl<Z> Zeroize for Zeroizing<Z>
686
where
687
    Z: Zeroize + ?Sized,
688
{
689
0
    fn zeroize(&mut self) {
690
0
        self.0.zeroize();
691
0
    }
692
}
693
694
impl<Z> ZeroizeOnDrop for Zeroizing<Z> where Z: Zeroize + ?Sized {}
695
696
impl<Z> Drop for Zeroizing<Z>
697
where
698
    Z: Zeroize + ?Sized,
699
{
700
0
    fn drop(&mut self) {
701
0
        self.0.zeroize();
702
0
    }
Unexecuted instantiation: <zeroize::Zeroizing<rustls::msgs::base::PayloadU8> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <zeroize::Zeroizing<_> as core::ops::drop::Drop>::drop
703
}
704
705
#[cfg(feature = "serde")]
706
impl<Z> serde::Serialize for Zeroizing<Z>
707
where
708
    Z: Zeroize + serde::Serialize + ?Sized,
709
{
710
    #[inline(always)]
711
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
712
    where
713
        S: serde::Serializer,
714
    {
715
        self.0.serialize(serializer)
716
    }
717
}
718
719
#[cfg(feature = "serde")]
720
impl<'de, Z> serde::Deserialize<'de> for Zeroizing<Z>
721
where
722
    Z: Zeroize + serde::Deserialize<'de>,
723
{
724
    #[inline(always)]
725
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
726
    where
727
        D: serde::Deserializer<'de>,
728
    {
729
        Ok(Self(Z::deserialize(deserializer)?))
730
    }
731
}
732
733
/// Perform a volatile write to the destination
734
#[inline(always)]
735
0
fn volatile_write<T: Copy + Sized>(dst: &mut T, src: T) {
736
0
    unsafe { ptr::write_volatile(dst, src) }
737
0
}
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<i8>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<u8>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<isize>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<usize>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<i32>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<u32>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<i128>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<u128>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<i16>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<u16>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<i64>>
Unexecuted instantiation: zeroize::volatile_write::<core::num::nonzero::NonZero<u64>>
Unexecuted instantiation: zeroize::volatile_write::<u8>
738
739
/// Perform a volatile `memset` operation which fills a slice with a value
740
///
741
/// # Safety
742
/// The memory pointed to by `dst` must be a single allocated object that is valid for `count`
743
/// contiguous elements of `T`.
744
/// `count` must not be larger than an `isize`.
745
/// `dst` being offset by `size_of::<T> * count` bytes must not wrap around the address space.
746
/// Also `dst` must be properly aligned.
747
#[inline(always)]
748
0
unsafe fn volatile_set<T: Copy + Sized>(dst: *mut T, src: T, count: usize) {
749
    // TODO(tarcieri): use `volatile_set_memory` when stabilized
750
0
    for i in 0..count {
751
0
        // Safety:
752
0
        //
753
0
        // This is safe because there is room for at least `count` objects of type `T` in the
754
0
        // allocation pointed to by `dst`, because `count <= isize::MAX` and because
755
0
        // `dst.add(count)` must not wrap around the address space.
756
0
        let ptr = unsafe { dst.add(i) };
757
0
758
0
        // Safety:
759
0
        //
760
0
        // This is safe, because the pointer is valid and because `dst` is well aligned for `T` and
761
0
        // `ptr` is an offset of `dst` by a multiple of `size_of::<T>()` bytes.
762
0
        unsafe { ptr::write_volatile(ptr, src) };
763
0
    }
764
0
}
Unexecuted instantiation: zeroize::volatile_set::<core::mem::maybe_uninit::MaybeUninit<u8>>
Unexecuted instantiation: zeroize::volatile_set::<u8>
765
766
/// Zeroizes a flat type/struct. Only zeroizes the values that it owns, and it does not work on
767
/// dynamically sized values or trait objects. It would be inefficient to use this function on a
768
/// type that already implements `ZeroizeOnDrop`.
769
///
770
/// # Safety
771
/// - The type must not contain references to outside data or dynamically sized data, such as
772
///   `Vec<T>` or `String`.
773
/// - Values stored in the type must not have `Drop` impls.
774
/// - This function can invalidate the type if it is used after this function is called on it.
775
///   It is advisable to call this function only in `impl Drop`.
776
/// - The bit pattern of all zeroes must be valid for the data being zeroized. This may not be
777
///   true for enums and pointers.
778
///
779
/// # Incompatible data types
780
/// Some data types that cannot be safely zeroized using `zeroize_flat_type` include,
781
/// but are not limited to:
782
/// - References: `&T` and `&mut T`
783
/// - Non-nullable types: `NonNull<T>`, `NonZeroU32`, etc.
784
/// - Enums with explicit non-zero tags.
785
/// - Smart pointers and collections: `Arc<T>`, `Box<T>`, `Vec<T>`, `HashMap<K, V>`, `String`, etc.
786
///
787
/// # Examples
788
/// Safe usage for a struct containing strictly flat data:
789
/// ```
790
/// use zeroize::{ZeroizeOnDrop, zeroize_flat_type};
791
///
792
/// struct DataToZeroize {
793
///     flat_data_1: [u8; 32],
794
///     flat_data_2: SomeMoreFlatData,
795
/// }
796
///
797
/// struct SomeMoreFlatData(u64);
798
///
799
/// impl Drop for DataToZeroize {
800
///     fn drop(&mut self) {
801
///         unsafe { zeroize_flat_type(self as *mut Self) }
802
///     }
803
/// }
804
/// impl ZeroizeOnDrop for DataToZeroize {}
805
///
806
/// let mut data = DataToZeroize {
807
///     flat_data_1: [3u8; 32],
808
///     flat_data_2: SomeMoreFlatData(123u64)
809
/// };
810
///
811
/// // data gets zeroized when dropped
812
/// ```
813
#[inline(always)]
814
0
pub unsafe fn zeroize_flat_type<F: Sized>(data: *mut F) {
815
0
    let size = size_of::<F>();
816
    // Safety:
817
    //
818
    // This is safe because `size_of<T>()` returns the exact size of the object in memory, and
819
    // `data_ptr` points directly to the first byte of the data.
820
0
    unsafe {
821
0
        volatile_set(data.cast::<u8>(), 0, size);
822
0
    }
823
0
    optimization_barrier(&data);
824
0
}
825
826
/// Internal module used as support for `AssertZeroizeOnDrop`.
827
#[doc(hidden)]
828
pub 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
0
        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
0
        fn zeroize_or_on_drop(&mut self) {
847
0
            self.zeroize();
848
0
        }
849
    }
850
}