did_utils/jwk/
secret.rs

1extern crate alloc;
2use alloc::boxed::Box;
3
4use core::{
5    fmt::Debug,
6    ops::{Deref, DerefMut},
7};
8
9use base64ct::Base64UrlUnpadded;
10use serde::{Deserialize, Serialize};
11use subtle::ConstantTimeEq;
12use zeroize::{Zeroize, Zeroizing};
13
14use super::Bytes;
15
16/// A serde wrapper for base64-encoded secrets.
17///
18/// A secret is like the [`Bytes`] type, with some additional protections:
19///
20///   1. It is zeroed on drop.
21///   2. Its equality implementation is constant time.
22///   3. Its contents are not printed in the debug formatter.
23#[derive(Clone, Serialize, Deserialize)]
24#[serde(transparent)]
25#[serde(bound(serialize = "Bytes<T, E>: Serialize"))]
26#[serde(bound(deserialize = "Bytes<T, E>: Deserialize<'de>"))]
27pub struct Secret<T: Zeroize = Box<[u8]>, E = Base64UrlUnpadded>(Zeroizing<Bytes<T, E>>);
28
29impl<T: Zeroize, E> Debug for Secret<T, E> {
30    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31        write!(f, "Secret(***)")
32    }
33}
34
35impl<T: Zeroize, U: Into<Bytes<T, E>>, E> From<U> for Secret<T, E> {
36    fn from(value: U) -> Self {
37        Self(Zeroizing::new(value.into()))
38    }
39}
40
41impl<T: Zeroize, E> Deref for Secret<T, E> {
42    type Target = Bytes<T, E>;
43
44    fn deref(&self) -> &Self::Target {
45        &self.0
46    }
47}
48
49impl<T: Zeroize, E> DerefMut for Secret<T, E> {
50    fn deref_mut(&mut self) -> &mut Self::Target {
51        &mut self.0
52    }
53}
54
55impl<T: Zeroize, U, E> AsRef<U> for Secret<T, E>
56where
57    Bytes<T, E>: AsRef<U>,
58{
59    fn as_ref(&self) -> &U {
60        self.0.as_ref()
61    }
62}
63
64impl<T: Zeroize, U, E> AsMut<U> for Secret<T, E>
65where
66    Bytes<T, E>: AsMut<U>,
67{
68    fn as_mut(&mut self) -> &mut U {
69        self.0.as_mut()
70    }
71}
72
73impl<T: Zeroize + AsRef<[u8]> + Sized, E> ConstantTimeEq for Secret<T, E> {
74    fn ct_eq(&self, other: &Self) -> subtle::Choice {
75        self.0.as_ref().ct_eq(other.0.as_ref())
76    }
77}
78
79impl<T: Zeroize + AsRef<[u8]>, E> Eq for Secret<T, E> {}
80impl<T: Zeroize + AsRef<[u8]>, E> PartialEq for Secret<T, E> {
81    fn eq(&self, other: &Self) -> bool {
82        self.ct_eq(other).unwrap_u8() == 1
83    }
84}
85
86impl<T: Zeroize + Default, E> Default for Secret<T, E> {
87    fn default() -> Self {
88        Self(Zeroizing::new(Bytes::default()))
89    }
90}