secrecy/
lib.rs

1//! [`Secret`] wrapper type for more carefully handling secret values
2//! (e.g. passwords, cryptographic keys, access tokens or other credentials)
3//!
4//! # Goals
5//!
6//! - Make secret access explicit and easy-to-audit via the
7//!   [`ExposeSecret`] trait. This also makes secret values immutable which
8//!   helps avoid making accidental copies (e.g. reallocating the backing
9//!   buffer for a `Vec`)
10//! - Prevent accidental leakage of secrets via channels like debug logging
11//! - Ensure secrets are wiped from memory on drop securely
12//!   (using the [`zeroize`] crate)
13//!
14//! Presently this crate favors a simple, `no_std`-friendly, safe i.e.
15//! `forbid(unsafe_code)`-based implementation and does not provide more advanced
16//! memory protection mechanisms e.g. ones based on `mlock(2)`/`mprotect(2)`.
17//! We may explore more advanced protection mechanisms in the future.
18//!
19//! # `Box`, `String`, and `Vec` wrappers
20//!
21//! Most users of this crate will simply want [`Secret`] wrappers around Rust's
22//! core collection types: i.e. `Box`, `String`, and `Vec`.
23//!
24//! When the `alloc` feature of this crate is enabled (which it is by default),
25//! [`SecretBox`], [`SecretString`], and [`SecretVec`] type aliases are
26//! available.
27//!
28//! There's nothing particularly fancy about these: they're just the simple
29//! composition of `Secret<Box<_>>`, `Secret<String>`, and `Secret<Vec<_>>`!
30//! However, in many cases they're all you will need.
31//!
32//! # Advanced usage
33//!
34//! If you are hitting limitations on what's possible with the collection type
35//! wrappers, you'll want to define your own newtype which lets you customize
36//! the implementation:
37//!
38//! ```rust
39//! use secrecy::{CloneableSecret, DebugSecret, Secret, Zeroize};
40//!
41//! #[derive(Clone)]
42//! pub struct AccountNumber(String);
43//!
44//! impl Zeroize for AccountNumber {
45//!     fn zeroize(&mut self) {
46//!         self.0.zeroize();
47//!     }
48//! }
49//!
50//! /// Permits cloning
51//! impl CloneableSecret for AccountNumber {}
52//!
53//! /// Provides a `Debug` impl (by default `[[REDACTED]]`)
54//! impl DebugSecret for AccountNumber {}
55//!
56//! /// Use this alias when storing secret values
57//! pub type SecretAccountNumber = Secret<AccountNumber>;
58//! ```
59//!
60//! # `serde` support
61//!
62//! When the `serde` feature of this crate is enabled, the [`Secret`] type will
63//! receive a [`Deserialize`] impl for all `Secret<T>` types where
64//! `T: DeserializeOwned`. This allows *loading* secret values from data
65//! deserialized from `serde` (be careful to clean up any intermediate secrets
66//! when doing this, e.g. the unparsed input!)
67//!
68//! To prevent exfiltration of secret values via `serde`, by default `Secret<T>`
69//! does *not* receive a corresponding [`Serialize`] impl. If you would like
70//! types of `Secret<T>` to be serializable with `serde`, you will need to impl
71//! the [`SerializableSecret`] marker trait on `T`.
72
73#![no_std]
74#![cfg_attr(docsrs, feature(doc_cfg))]
75#![doc(html_root_url = "https://docs.rs/secrecy/0.8.0")]
76#![forbid(unsafe_code)]
77#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
78
79#[cfg(feature = "alloc")]
80extern crate alloc;
81
82#[cfg(feature = "alloc")]
83mod boxed;
84#[cfg(feature = "bytes")]
85mod bytes;
86#[cfg(feature = "alloc")]
87mod string;
88#[cfg(feature = "alloc")]
89mod vec;
90
91pub use zeroize::{self, Zeroize};
92
93#[cfg(feature = "alloc")]
94pub use self::{boxed::SecretBox, string::SecretString, vec::SecretVec};
95
96#[cfg(feature = "bytes")]
97pub use self::bytes::SecretBytesMut;
98
99use core::{
100    any,
101    fmt::{self, Debug},
102};
103
104#[cfg(feature = "serde")]
105use serde::{de, ser, Deserialize, Serialize};
106
107/// Wrapper type for values that contains secrets, which attempts to limit
108/// accidental exposure and ensure secrets are wiped from memory when dropped.
109/// (e.g. passwords, cryptographic keys, access tokens or other credentials)
110///
111/// Access to the secret inner value occurs through the [`ExposeSecret`] trait,
112/// which provides an `expose_secret()` method for accessing the inner secret
113/// value.
114pub struct Secret<S>
115where
116    S: Zeroize,
117{
118    /// Inner secret value
119    inner_secret: S,
120}
121
122impl<S> Secret<S>
123where
124    S: Zeroize,
125{
126    /// Take ownership of a secret value
127    pub fn new(secret: S) -> Self {
128        Secret {
129            inner_secret: secret,
130        }
131    }
132}
133
134impl<S> ExposeSecret<S> for Secret<S>
135where
136    S: Zeroize,
137{
138    fn expose_secret(&self) -> &S {
139        &self.inner_secret
140    }
141}
142
143impl<S> From<S> for Secret<S>
144where
145    S: Zeroize,
146{
147    fn from(secret: S) -> Self {
148        Self::new(secret)
149    }
150}
151
152impl<S> Clone for Secret<S>
153where
154    S: CloneableSecret,
155{
156    fn clone(&self) -> Self {
157        Secret {
158            inner_secret: self.inner_secret.clone(),
159        }
160    }
161}
162
163impl<S> Debug for Secret<S>
164where
165    S: Zeroize + DebugSecret,
166{
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        f.write_str("Secret(")?;
169        S::debug_secret(f)?;
170        f.write_str(")")
171    }
172}
173
174impl<S> Drop for Secret<S>
175where
176    S: Zeroize,
177{
178    fn drop(&mut self) {
179        // Zero the secret out from memory
180        self.inner_secret.zeroize();
181    }
182}
183
184/// Marker trait for secrets which are allowed to be cloned
185pub trait CloneableSecret: Clone + Zeroize {}
186
187/// Implement `CloneableSecret` on arrays of types that impl `Clone` and
188/// `Zeroize`.
189macro_rules! impl_cloneable_secret_for_array {
190    ($($size:expr),+) => {
191        $(
192            impl<T: Clone + Zeroize> CloneableSecret for [T; $size] {}
193        )+
194     };
195}
196
197// TODO(tarcieri): const generics
198impl_cloneable_secret_for_array!(
199    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
200    27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
201    51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
202);
203
204/// Expose a reference to an inner secret
205pub trait ExposeSecret<S> {
206    /// Expose secret: this is the only method providing access to a secret.
207    fn expose_secret(&self) -> &S;
208}
209
210/// Debugging trait which is specialized for handling secret values
211pub trait DebugSecret {
212    /// Format information about the secret's type.
213    ///
214    /// This can be thought of as an equivalent to [`Debug::fmt`], but one
215    /// which by design does not permit access to the secret value.
216    fn debug_secret(f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
217        f.write_str("[REDACTED ")?;
218        f.write_str(any::type_name::<Self>())?;
219        f.write_str("]")
220    }
221}
222
223/// Implement `DebugSecret` on arrays of types that impl `Debug`.
224macro_rules! impl_debug_secret_for_array {
225    ($($size:expr),+) => {
226        $(
227            impl<T: Debug> DebugSecret for [T; $size] {}
228        )+
229     };
230}
231
232// TODO(tarcieri): const generics
233impl_debug_secret_for_array!(
234    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
235    27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
236    51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
237);
238
239/// Marker trait for secret types which can be [`Serialize`]-d by [`serde`].
240///
241/// When the `serde` feature of this crate is enabled and types are marked with
242/// this trait, they receive a [`Serialize` impl][1] for `Secret<T>`.
243/// (NOTE: all types which impl `DeserializeOwned` receive a [`Deserialize`]
244/// impl)
245///
246/// This is done deliberately to prevent accidental exfiltration of secrets
247/// via `serde` serialization.
248///
249/// If you are working with [`SecretString`] or [`SecretVec`], not that
250/// by design these types do *NOT* impl this trait.
251///
252/// If you really want to have `serde` serialize those types, use the
253/// [`serialize_with`][2] attribute to specify a serializer that exposes the secret.
254///
255/// [1]: https://docs.rs/secrecy/latest/secrecy/struct.Secret.html#implementations
256/// [2]: https://serde.rs/field-attrs.html#serialize_with
257#[cfg(feature = "serde")]
258#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
259pub trait SerializableSecret: Serialize {}
260
261#[cfg(feature = "serde")]
262impl<'de, T> Deserialize<'de> for Secret<T>
263where
264    T: Zeroize + Clone + de::DeserializeOwned + Sized,
265{
266    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
267    where
268        D: de::Deserializer<'de>,
269    {
270        T::deserialize(deserializer).map(Secret::new)
271    }
272}
273
274#[cfg(feature = "serde")]
275impl<T> Serialize for Secret<T>
276where
277    T: Zeroize + SerializableSecret + Serialize + Sized,
278{
279    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
280    where
281        S: ser::Serializer,
282    {
283        self.expose_secret().serialize(serializer)
284    }
285}