Skip to main content

pubhubs/common/
secret.rs

1use curve25519_dalek::Scalar;
2
3/// Secret bytes to derive secrets from via a hash
4pub trait DigestibleSecret {
5    fn as_bytes(&self) -> &[u8];
6
7    /// Inserts this secret in the given digest
8    fn update_digest<D: sha2::digest::Digest>(&self, d: D, domain: impl AsRef<str>) -> D {
9        let domain: &str = domain.as_ref();
10        let bytes: &[u8] = self.as_bytes();
11
12        // NOTE: we include the lengths to prevent collisions
13        d.chain_update(encode_usize(domain.len()))
14            .chain_update(domain)
15            .chain_update(encode_usize(bytes.len()))
16            .chain_update(bytes)
17    }
18
19    /// Creates a [`Scalar`] from this secret
20    fn derive_scalar<D>(&self, d: D, domain: impl AsRef<str>) -> Scalar
21    where
22        D: sha2::digest::Digest<OutputSize = typenum::U64>,
23    {
24        Scalar::from_hash(self.update_digest(d, domain))
25    }
26
27    /// Creates [`Vec<u8>`] from this secret.
28    fn derive_bytes<D>(&self, d: D, domain: impl AsRef<str>) -> Vec<u8>
29    where
30        D: sha2::digest::Digest,
31    {
32        // This code has an unnecessary copy to more loosely couple to the generic_array package.
33        self.update_digest(d, domain)
34            .finalize()
35            .as_slice()
36            .to_owned()
37    }
38
39    /// Creates an [`Id`] from this secret.
40    ///
41    /// [`Id`]: crate::id::Id
42    fn derive_id<D>(&self, d: D, domain: impl AsRef<str>) -> crate::id::Id
43    where
44        D: sha2::digest::Digest<OutputSize = typenum::U32>,
45    {
46        let bytes: [u8; 32] = self.derive_bytes(d, domain).try_into().unwrap();
47
48        bytes.into()
49    }
50
51    /// Creates a [`HS256`] from this secret.
52    ///
53    /// [`HS256`]: crate::misc::jwt::HS256
54    fn derive_hs256<D>(&self, d: D, domain: impl AsRef<str>) -> crate::misc::jwt::HS256
55    where
56        D: sha2::digest::Digest,
57    {
58        crate::misc::jwt::HS256(self.derive_bytes(d, domain))
59    }
60
61    /// Creates a (256-bit) [`crate::misc::crypto::SealingKey`] from this secret.
62    fn derive_sealing_key<D>(
63        &self,
64        d: D,
65        domain: impl AsRef<str>,
66    ) -> crate::misc::crypto::SealingKey
67    where
68        D: sha2::digest::Digest<OutputSize = typenum::U32>,
69    {
70        self.update_digest(d, domain).finalize()
71    }
72}
73
74impl DigestibleSecret for &[u8] {
75    fn as_bytes(&self) -> &[u8] {
76        self
77    }
78}
79
80/// Encodes an usize in a platform independent manner, as `u64` using big-endian byte order.
81pub const fn encode_usize(size: usize) -> [u8; 8] {
82    if size_of::<usize>() > 8 {
83        panic!("can not (yet) deal with usize of size > 8")
84    }
85    (size as u64).to_be_bytes()
86}