Skip to main content

secure_gate/traits/revealed_secrets/
inner_secret.rs

1/// Owned, zeroizing secret extracted via [`RevealSecret::into_inner`].
2///
3/// `InnerSecret<T>` preserves the zeroization contract by wrapping
4/// [`zeroize::Zeroizing<T>`], while restoring a strict redaction policy for `Debug`:
5/// formatting this type always prints `[REDACTED]`, regardless of `T`.
6///
7/// This is **not** a secret wrapper like [`Fixed`](crate::Fixed) or
8/// [`Dynamic`](crate::Dynamic) — it is the owned extraction result from
9/// [`into_inner()`](crate::RevealSecret::into_inner). It implements
10/// `Deref<Target = T>` (the **only** type in this crate that derefs to the secret).
11///
12/// Use [`into_zeroizing`](Self::into_zeroizing) only when an API explicitly requires
13/// a `Zeroizing<T>` value.
14///
15/// # Examples
16///
17/// ```rust
18/// use secure_gate::{Fixed, RevealSecret};
19///
20/// let key = Fixed::new([0xABu8; 4]);
21/// let owned = key.into_inner();
22///
23/// // Deref access to the inner value.
24/// assert_eq!(owned[0], 0xAB);
25///
26/// // Debug is redacted.
27/// assert_eq!(format!("{:?}", owned), "[REDACTED]");
28///
29/// // Convert to Zeroizing<T> for interop.
30/// let z = owned.into_zeroizing();
31/// ```
32///
33/// See also [`EncodedSecret`](crate::EncodedSecret) — the encoded-string counterpart.
34pub struct InnerSecret<T: zeroize::Zeroize>(zeroize::Zeroizing<T>);
35
36impl<T: zeroize::Zeroize> InnerSecret<T> {
37    #[inline(always)]
38    pub(crate) fn new(inner: T) -> Self {
39        Self(zeroize::Zeroizing::new(inner))
40    }
41
42    /// Unwraps and returns the underlying [`zeroize::Zeroizing<T>`].
43    ///
44    /// This is an explicit escape hatch for interoperability with APIs that accept
45    /// `Zeroizing<T>` directly.
46    #[inline(always)]
47    pub fn into_zeroizing(self) -> zeroize::Zeroizing<T> {
48        self.0
49    }
50}
51
52impl<T: zeroize::Zeroize> core::fmt::Debug for InnerSecret<T> {
53    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54        f.write_str("[REDACTED]")
55    }
56}
57
58/// Provides `&T` access via `*inner_secret`. This is the **only** type in the crate
59/// that implements `Deref` to the secret — [`Fixed`](crate::Fixed) and
60/// [`Dynamic`](crate::Dynamic) deliberately do not.
61impl<T: zeroize::Zeroize> core::ops::Deref for InnerSecret<T> {
62    type Target = T;
63
64    #[inline(always)]
65    fn deref(&self) -> &Self::Target {
66        &self.0
67    }
68}