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