1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6)]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![forbid(unsafe_code)]
9#![warn(missing_docs)]
10
11use core::{fmt, marker::PhantomData, ops::Mul};
12use digest::{
13 KeyInit, Mac,
14 array::{Array, ArraySize, typenum::Unsigned},
15 common::KeySizeUser,
16 consts::{U8, U32},
17 typenum::op,
18};
19
20pub mod sealed;
21
22#[derive(Debug, PartialEq)]
24pub enum Error {
25 InvalidRequestSize,
27}
28
29impl fmt::Display for Error {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 match self {
32 Error::InvalidRequestSize => write!(
33 f,
34 "Request output size is too large for the value of R specified"
35 ),
36 }
37 }
38}
39
40impl core::error::Error for Error {}
41
42pub struct Params<'k, 'l, 'c> {
46 pub kin: &'k [u8],
50 pub label: &'l [u8],
54 pub context: &'c [u8],
59 pub use_l: bool,
61 pub use_separator: bool,
63 pub use_counter: bool,
65}
66
67impl<'k, 'l, 'c> Params<'k, 'l, 'c> {
68 pub fn builder(kin: &'k [u8]) -> ParamsBuilder<'k, 'l, 'c> {
70 let params = Params {
71 kin,
72 label: &[],
73 context: &[],
74 use_l: true,
75 use_separator: true,
76 use_counter: true,
77 };
78 ParamsBuilder(params)
79 }
80}
81
82pub struct ParamsBuilder<'k, 'l, 'c>(Params<'k, 'l, 'c>);
84
85impl<'k, 'l, 'c> ParamsBuilder<'k, 'l, 'c> {
86 pub fn build(self) -> Params<'k, 'l, 'c> {
88 self.0
89 }
90
91 pub fn with_label(mut self, label: &'l [u8]) -> Self {
93 self.0.label = label;
94 self
95 }
96
97 pub fn with_context(mut self, context: &'c [u8]) -> Self {
99 self.0.context = context;
100 self
101 }
102
103 pub fn use_l(mut self, use_l: bool) -> Self {
105 self.0.use_l = use_l;
106 self
107 }
108
109 pub fn use_separator(mut self, use_separator: bool) -> Self {
111 self.0.use_separator = use_separator;
112 self
113 }
114
115 pub fn use_counter(mut self, use_counter: bool) -> Self {
117 self.0.use_counter = use_counter;
118 self
119 }
120}
121
122struct KbkdfCore<OutputLen, PrfOutputLen> {
124 _marker: PhantomData<(OutputLen, PrfOutputLen)>,
125}
126
127trait KbkdfUser {
128 type L;
132
133 type H;
136}
137
138impl<OutputLen, PrfOutputLen> KbkdfUser for KbkdfCore<OutputLen, PrfOutputLen>
139where
140 OutputLen: ArraySize + Mul<U8>,
141 <OutputLen as Mul<U8>>::Output: Unsigned,
142 PrfOutputLen: ArraySize + Mul<U8>,
143 <PrfOutputLen as Mul<U8>>::Output: Unsigned,
144{
145 type L = op!(OutputLen * U8);
146 type H = op!(PrfOutputLen * U8);
147}
148
149pub trait Kbkdf<Prf, K, R: sealed::R>
156where
157 Prf: Mac + KeyInit,
158 K: KeySizeUser,
159 K::KeySize: ArraySize + Mul<U8>,
160 <K::KeySize as Mul<U8>>::Output: Unsigned,
161 Prf::OutputSize: ArraySize + Mul<U8>,
162 <Prf::OutputSize as Mul<U8>>::Output: Unsigned,
163{
164 fn derive(&self, params: Params<'_, '_, '_>) -> Result<Array<u8, K::KeySize>, Error> {
166 let n: u32 = <KbkdfCore<K::KeySize, Prf::OutputSize> as KbkdfUser>::L::U32
169 .div_ceil(<KbkdfCore<K::KeySize, Prf::OutputSize> as KbkdfUser>::H::U32);
170
171 if n as usize > 2usize.pow(R::U32) - 1 {
172 return Err(Error::InvalidRequestSize);
173 }
174
175 let mut output = Array::<u8, K::KeySize>::default();
176 let mut builder = output.as_mut_slice();
177
178 let mut ki = None;
179 self.input_iv(&mut ki);
180 let mut a = {
181 let mut h = Prf::new_from_slice(params.kin).unwrap();
182 h.update(params.label);
183 if params.use_separator {
184 h.update(&[0]);
185 }
186 h.update(params.context);
187 h.finalize().into_bytes()
188 };
189
190 for counter in 1..=n {
191 if counter > 1 {
192 a = {
193 let mut h = Prf::new_from_slice(params.kin).unwrap();
194 h.update(a.as_slice());
195 h.finalize().into_bytes()
196 };
197 }
198
199 let mut h = Prf::new_from_slice(params.kin).unwrap();
200
201 if Self::FEEDBACK_KI {
202 if let Some(ki) = ki {
203 h.update(ki.as_slice());
204 }
205 }
206
207 if Self::DOUBLE_PIPELINE {
208 h.update(a.as_slice());
209 }
210 if params.use_counter {
211 h.update(&counter.to_be_bytes()[(4 - R::USIZE / 8)..]);
218 }
219
220 h.update(params.label);
222 if params.use_separator {
223 h.update(&[0]);
224 }
225 h.update(params.context);
226 if params.use_l {
227 h.update(
228 &(<KbkdfCore<K::KeySize, Prf::OutputSize> as KbkdfUser>::L::U32).to_be_bytes()
229 [..],
230 );
231 }
232
233 let buf = h.finalize().into_bytes();
234 ki = Some(buf.clone());
235
236 let remaining = usize::min(buf.len(), builder.len());
237
238 builder[..remaining].copy_from_slice(&buf[..remaining]);
239 builder = &mut builder[remaining..];
240 }
241
242 assert_eq!(builder.len(), 0, "output has uninitialized bytes");
243
244 Ok(output)
245 }
246
247 fn input_iv(&self, _ki: &mut Option<Array<u8, Prf::OutputSize>>) {}
249
250 const FEEDBACK_KI: bool = false;
254
255 const DOUBLE_PIPELINE: bool = false;
257}
258
259pub struct Counter<Prf, K, R = U32> {
261 _marker: PhantomData<(Prf, K, R)>,
262}
263
264impl<Prf, K, R> Default for Counter<Prf, K, R> {
265 fn default() -> Self {
266 Self {
267 _marker: PhantomData,
268 }
269 }
270}
271
272impl<Prf, K, R> Kbkdf<Prf, K, R> for Counter<Prf, K, R>
273where
274 Prf: Mac + KeyInit,
275 K: KeySizeUser,
276 K::KeySize: ArraySize + Mul<U8>,
277 <K::KeySize as Mul<U8>>::Output: Unsigned,
278 Prf::OutputSize: ArraySize + Mul<U8>,
279 <Prf::OutputSize as Mul<U8>>::Output: Unsigned,
280 R: sealed::R,
281{
282}
283
284pub struct Feedback<'a, Prf, K, R = U32>
286where
287 Prf: Mac,
288{
289 iv: Option<&'a Array<u8, Prf::OutputSize>>,
290 _marker: PhantomData<(Prf, K, R)>,
291}
292
293impl<'a, Prf, K, R> Feedback<'a, Prf, K, R>
294where
295 Prf: Mac,
296{
297 pub fn new(iv: Option<&'a Array<u8, Prf::OutputSize>>) -> Self {
299 Self {
300 iv,
301 _marker: PhantomData,
302 }
303 }
304}
305
306impl<Prf, K, R> Kbkdf<Prf, K, R> for Feedback<'_, Prf, K, R>
307where
308 Prf: Mac + KeyInit,
309 K: KeySizeUser,
310 K::KeySize: ArraySize + Mul<U8>,
311 <K::KeySize as Mul<U8>>::Output: Unsigned,
312 Prf::OutputSize: ArraySize + Mul<U8>,
313 <Prf::OutputSize as Mul<U8>>::Output: Unsigned,
314 R: sealed::R,
315{
316 fn input_iv(&self, ki: &mut Option<Array<u8, Prf::OutputSize>>) {
317 if let Some(iv) = self.iv {
318 *ki = Some(iv.clone())
319 }
320 }
321
322 const FEEDBACK_KI: bool = true;
323}
324
325pub struct DoublePipeline<Prf, K, R = U32>
327where
328 Prf: Mac,
329{
330 _marker: PhantomData<(Prf, K, R)>,
331}
332
333impl<Prf, K, R> Default for DoublePipeline<Prf, K, R>
334where
335 Prf: Mac,
336{
337 fn default() -> Self {
338 Self {
339 _marker: PhantomData,
340 }
341 }
342}
343
344impl<Prf, K, R> Kbkdf<Prf, K, R> for DoublePipeline<Prf, K, R>
345where
346 Prf: Mac + KeyInit,
347 K: KeySizeUser,
348 K::KeySize: ArraySize + Mul<U8>,
349 <K::KeySize as Mul<U8>>::Output: Unsigned,
350 Prf::OutputSize: ArraySize + Mul<U8>,
351 <Prf::OutputSize as Mul<U8>>::Output: Unsigned,
352 R: sealed::R,
353{
354 const DOUBLE_PIPELINE: bool = true;
355}
356
357#[cfg(test)]
358mod tests;