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