1#![no_std]
33#![cfg_attr(docsrs, feature(doc_auto_cfg))]
34#![forbid(unsafe_code)]
35#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
36
37extern crate alloc;
38
39use alloc::{boxed::Box, string::String, vec::Vec};
40use core::{
41 any,
42 fmt::{self, Debug},
43};
44
45use zeroize::{Zeroize, ZeroizeOnDrop};
46
47#[cfg(feature = "serde")]
48use serde::{de, ser, Deserialize, Serialize};
49
50pub use zeroize;
51
52pub struct SecretBox<S: Zeroize + ?Sized> {
59 inner_secret: Box<S>,
60}
61
62impl<S: Zeroize + ?Sized> Zeroize for SecretBox<S> {
63 fn zeroize(&mut self) {
64 self.inner_secret.as_mut().zeroize()
65 }
66}
67
68impl<S: Zeroize + ?Sized> Drop for SecretBox<S> {
69 fn drop(&mut self) {
70 self.zeroize()
71 }
72}
73
74impl<S: Zeroize + ?Sized> ZeroizeOnDrop for SecretBox<S> {}
75
76impl<S: Zeroize + ?Sized> From<Box<S>> for SecretBox<S> {
77 fn from(source: Box<S>) -> Self {
78 Self::new(source)
79 }
80}
81
82impl<S: Zeroize + ?Sized> SecretBox<S> {
83 pub fn new(boxed_secret: Box<S>) -> Self {
85 Self {
86 inner_secret: boxed_secret,
87 }
88 }
89}
90
91impl<S: Zeroize + Default> SecretBox<S> {
92 pub fn init_with_mut(ctr: impl FnOnce(&mut S)) -> Self {
94 let mut secret = Self::default();
95 ctr(secret.expose_secret_mut());
96 secret
97 }
98}
99
100impl<S: Zeroize + Clone> SecretBox<S> {
101 pub fn init_with(ctr: impl FnOnce() -> S) -> Self {
110 let mut data = ctr();
111 let secret = Self {
112 inner_secret: Box::new(data.clone()),
113 };
114 data.zeroize();
115 secret
116 }
117
118 pub fn try_init_with<E>(ctr: impl FnOnce() -> Result<S, E>) -> Result<Self, E> {
124 let mut data = ctr()?;
125 let secret = Self {
126 inner_secret: Box::new(data.clone()),
127 };
128 data.zeroize();
129 Ok(secret)
130 }
131}
132
133impl<S: Zeroize + Default> Default for SecretBox<S> {
134 fn default() -> Self {
135 Self {
136 inner_secret: Box::<S>::default(),
137 }
138 }
139}
140
141impl<S: Zeroize + ?Sized> Debug for SecretBox<S> {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 write!(f, "SecretBox<{}>([REDACTED])", any::type_name::<S>())
144 }
145}
146
147impl<S> Clone for SecretBox<S>
148where
149 S: CloneableSecret,
150{
151 fn clone(&self) -> Self {
152 SecretBox {
153 inner_secret: self.inner_secret.clone(),
154 }
155 }
156}
157
158impl<S: Zeroize + ?Sized> ExposeSecret<S> for SecretBox<S> {
159 fn expose_secret(&self) -> &S {
160 self.inner_secret.as_ref()
161 }
162}
163
164impl<S: Zeroize + ?Sized> ExposeSecretMut<S> for SecretBox<S> {
165 fn expose_secret_mut(&mut self) -> &mut S {
166 self.inner_secret.as_mut()
167 }
168}
169
170pub type SecretSlice<S> = SecretBox<[S]>;
176
177impl<S> From<Vec<S>> for SecretSlice<S>
178where
179 S: Zeroize,
180 [S]: Zeroize,
181{
182 fn from(vec: Vec<S>) -> Self {
183 Self::from(vec.into_boxed_slice())
184 }
185}
186
187impl<S> Clone for SecretSlice<S>
188where
189 S: CloneableSecret + Zeroize,
190 [S]: Zeroize,
191{
192 fn clone(&self) -> Self {
193 SecretBox {
194 inner_secret: Vec::from(&*self.inner_secret).into_boxed_slice(),
195 }
196 }
197}
198
199impl<S> Default for SecretSlice<S>
200where
201 S: Zeroize,
202 [S]: Zeroize,
203{
204 fn default() -> Self {
205 Vec::new().into()
206 }
207}
208
209pub type SecretString = SecretBox<str>;
215
216impl From<String> for SecretString {
217 fn from(s: String) -> Self {
218 Self::from(s.into_boxed_str())
219 }
220}
221
222impl From<&str> for SecretString {
223 fn from(s: &str) -> Self {
224 Self::from(String::from(s))
225 }
226}
227
228impl Clone for SecretString {
229 fn clone(&self) -> Self {
230 SecretBox {
231 inner_secret: self.inner_secret.clone(),
232 }
233 }
234}
235
236impl Default for SecretString {
237 fn default() -> Self {
238 String::default().into()
239 }
240}
241
242pub trait CloneableSecret: Clone + Zeroize {}
244
245impl CloneableSecret for i8 {}
248impl CloneableSecret for i16 {}
249impl CloneableSecret for i32 {}
250impl CloneableSecret for i64 {}
251impl CloneableSecret for i128 {}
252impl CloneableSecret for isize {}
253
254impl CloneableSecret for u8 {}
255impl CloneableSecret for u16 {}
256impl CloneableSecret for u32 {}
257impl CloneableSecret for u64 {}
258impl CloneableSecret for u128 {}
259impl CloneableSecret for usize {}
260
261pub trait ExposeSecret<S: ?Sized> {
263 fn expose_secret(&self) -> &S;
265}
266
267pub trait ExposeSecretMut<S: ?Sized> {
269 fn expose_secret_mut(&mut self) -> &mut S;
271}
272
273#[cfg(feature = "serde")]
289pub trait SerializableSecret: Serialize {}
290
291#[cfg(feature = "serde")]
292impl<'de, T> Deserialize<'de> for SecretBox<T>
293where
294 T: Zeroize + Clone + de::DeserializeOwned + Sized,
295{
296 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
297 where
298 D: de::Deserializer<'de>,
299 {
300 Self::try_init_with(|| T::deserialize(deserializer))
301 }
302}
303
304#[cfg(feature = "serde")]
305impl<'de> Deserialize<'de> for SecretString {
306 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
307 where
308 D: de::Deserializer<'de>,
309 {
310 String::deserialize(deserializer).map(Into::into)
311 }
312}
313
314#[cfg(feature = "serde")]
315impl<T> Serialize for SecretBox<T>
316where
317 T: Zeroize + SerializableSecret + Serialize + Sized,
318{
319 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
320 where
321 S: ser::Serializer,
322 {
323 self.expose_secret().serialize(serializer)
324 }
325}