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