1use crate::error::Unspecified;
9use native_ossl::digest::DigestAlg;
10use native_ossl::kdf::{HkdfBuilder, HkdfMode};
11use native_ossl::util::SecretBuf;
12
13#[derive(Clone, Copy, Debug)]
15pub struct Algorithm(pub(crate) &'static crate::digest::Algorithm);
16
17pub static HKDF_SHA256: Algorithm = Algorithm(&crate::digest::SHA256);
18pub static HKDF_SHA384: Algorithm = Algorithm(&crate::digest::SHA384);
19pub static HKDF_SHA512: Algorithm = Algorithm(&crate::digest::SHA512);
20
21impl Algorithm {
22 #[must_use]
23 pub fn hmac_algorithm(&self) -> crate::hmac::Algorithm {
24 crate::hmac::Algorithm(self.0)
25 }
26}
27
28pub trait KeyType {
30 fn len(&self) -> usize;
31 fn is_empty(&self) -> bool {
32 self.len() == 0
33 }
34}
35
36#[derive(Debug)]
39pub struct Salt {
40 alg: Algorithm,
41 salt: Vec<u8>,
42}
43
44impl Salt {
45 #[must_use]
46 pub fn new(algorithm: Algorithm, value: &[u8]) -> Self {
47 Self {
48 alg: algorithm,
49 salt: value.to_vec(),
50 }
51 }
52
53 #[must_use]
59 pub fn extract(self, secret: &[u8]) -> Prk {
60 let digest_alg = DigestAlg::fetch(self.alg.0.name, None)
61 .unwrap_or_else(|e| panic!("OpenSSL digest unavailable: {e}"));
62 let prk = HkdfBuilder::new(&digest_alg)
63 .mode(HkdfMode::ExtractOnly)
64 .key(secret)
65 .salt(&self.salt)
66 .derive_to_vec(self.alg.0.output_len)
67 .unwrap_or_else(|e| panic!("HKDF extract failed: {e}"));
68 Prk {
69 alg: self.alg,
70 prk: SecretBuf::new(prk),
71 }
72 }
73
74 #[must_use]
75 pub fn algorithm(&self) -> Algorithm {
76 self.alg
77 }
78}
79
80pub struct Prk {
83 alg: Algorithm,
84 prk: SecretBuf,
85}
86
87impl std::fmt::Debug for Prk {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 f.debug_struct("Prk")
90 .field("alg", &self.alg)
91 .finish_non_exhaustive()
92 }
93}
94
95impl Prk {
96 #[must_use]
98 pub fn new_less_safe(algorithm: Algorithm, value: &[u8]) -> Self {
99 Self {
100 alg: algorithm,
101 prk: SecretBuf::from_slice(value),
102 }
103 }
104
105 pub fn expand<'a, L: KeyType>(
111 &'a self,
112 info: &'a [&'a [u8]],
113 len: L,
114 ) -> Result<Okm<'a, L>, Unspecified> {
115 Ok(Okm {
116 prk: self,
117 info,
118 len,
119 })
120 }
121}
122
123pub struct Okm<'a, L: KeyType> {
126 prk: &'a Prk,
127 info: &'a [&'a [u8]],
128 len: L,
129}
130
131impl<L: KeyType> Okm<'_, L> {
132 #[must_use]
133 pub fn len(&self) -> &L {
134 &self.len
135 }
136
137 pub fn fill(self, out: &mut [u8]) -> Result<(), Unspecified> {
144 if out.len() != self.len.len() {
145 return Err(Unspecified);
146 }
147 let digest_alg = DigestAlg::fetch(self.prk.alg.0.name, None).map_err(|_| Unspecified)?;
148
149 let info_concat: Vec<u8> = self.info.iter().flat_map(|s| s.iter().copied()).collect();
151
152 HkdfBuilder::new(&digest_alg)
153 .mode(HkdfMode::ExpandOnly)
154 .key(self.prk.prk.as_ref())
155 .info(&info_concat)
156 .derive(out)
157 .map_err(|_| Unspecified)
158 }
159}