Coverage Report

Created: 2026-05-16 06:08

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