1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(feature = "alloc")]
49extern crate alloc;
50
51#[cfg(not(feature = "std"))]
52#[cfg(feature = "alloc")]
53use alloc::vec::Vec;
54
55#[cfg(feature = "std")]
56use std::vec::Vec;
57
58#[cfg(feature = "std")]
59use std::time::Duration;
60
61#[cfg(not(feature = "std"))]
62use core::time::Duration;
63
64use ::core::marker::PhantomData;
65use rand::{CryptoRng, RngCore};
66
67use crate::error::{Error, Result};
69use crate::hash::HashFunction;
70use crate::types::Salt;
71use zeroize::Zeroize;
72
73pub mod common;
74pub mod params;
75
76#[cfg(feature = "alloc")]
77pub mod hkdf;
78
79#[cfg(feature = "alloc")]
80pub mod pbkdf2;
81
82#[cfg(feature = "alloc")]
83pub mod argon2;
84
85pub use common::SecurityLevel;
86pub use params::{ParamProvider, PasswordHash};
87
88#[cfg(feature = "alloc")]
90pub use hkdf::Hkdf;
91
92#[cfg(feature = "alloc")]
93pub use pbkdf2::{Pbkdf2, Pbkdf2Params};
94
95#[cfg(feature = "alloc")]
96pub use argon2::{Algorithm as Argon2Type, Argon2, Params as Argon2Params};
97
98pub trait KdfAlgorithm {
100 const MIN_SALT_SIZE: usize;
102
103 const DEFAULT_OUTPUT_SIZE: usize;
105
106 const ALGORITHM_ID: &'static str;
108
109 fn name() -> String {
111 Self::ALGORITHM_ID.to_string()
112 }
113
114 fn security_level() -> SecurityLevel;
116}
117
118pub trait KdfOperation<'a, A: KdfAlgorithm, T = Vec<u8>>: Sized {
120 fn with_ikm(self, ikm: &'a [u8]) -> Self;
122
123 fn with_salt(self, salt: &'a [u8]) -> Self;
125
126 fn with_info(self, info: &'a [u8]) -> Self;
128
129 fn with_output_length(self, length: usize) -> Self;
131
132 fn derive(self) -> Result<T>;
134
135 fn derive_array<const N: usize>(self) -> Result<[u8; N]>;
137}
138
139pub trait KeyDerivationFunction {
141 type Algorithm: KdfAlgorithm;
143
144 type Salt: AsRef<[u8]> + AsMut<[u8]> + Clone;
146
147 fn new() -> Self;
149
150 #[cfg(feature = "alloc")]
161 fn derive_key(
162 &self,
163 input: &[u8],
164 salt: Option<&[u8]>,
165 info: Option<&[u8]>,
166 length: usize,
167 ) -> Result<Vec<u8>>;
168
169 fn builder(&self) -> impl KdfOperation<'_, Self::Algorithm>
171 where
172 Self: Sized;
173
174 fn security_level() -> SecurityLevel {
176 Self::Algorithm::security_level()
177 }
178
179 fn generate_salt<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Salt;
181}
182
183pub enum HkdfAlgorithm<H: HashFunction> {
185 _Hash(PhantomData<H>),
187}
188
189impl<H: HashFunction> KdfAlgorithm for HkdfAlgorithm<H> {
190 const MIN_SALT_SIZE: usize = 16;
191 const DEFAULT_OUTPUT_SIZE: usize = 32;
192 const ALGORITHM_ID: &'static str = "HKDF";
193
194 fn name() -> String {
195 format!("{}-{}", Self::ALGORITHM_ID, H::name())
196 }
197
198 fn security_level() -> SecurityLevel {
199 match H::output_size() * 8 {
200 bits if bits >= 512 => SecurityLevel::L256,
201 bits if bits >= 384 => SecurityLevel::L192,
202 bits if bits >= 256 => SecurityLevel::L128,
203 bits => SecurityLevel::Custom(bits as u32 / 2),
204 }
205 }
206}
207
208#[cfg(feature = "alloc")]
210pub struct TypedHkdf<H: HashFunction + Clone> {
211 inner: hkdf::Hkdf<H, 16>, _phantom: PhantomData<H>,
213}
214
215#[cfg(feature = "alloc")]
216impl<H: HashFunction + Clone> KeyDerivationFunction for TypedHkdf<H> {
217 type Algorithm = HkdfAlgorithm<H>;
218 type Salt = Salt<16>; fn new() -> Self {
221 Self {
222 inner: hkdf::Hkdf::new(),
223 _phantom: PhantomData,
224 }
225 }
226
227 #[cfg(feature = "alloc")]
228 fn derive_key(
229 &self,
230 input: &[u8],
231 salt: Option<&[u8]>,
232 info: Option<&[u8]>,
233 length: usize,
234 ) -> Result<Vec<u8>> {
235 self.inner.derive_key(input, salt, info, length)
236 }
237
238 fn builder(&self) -> impl KdfOperation<'_, Self::Algorithm> {
240 HKdfOperation {
241 kdf: self,
242 ikm: None,
243 salt: None,
244 info: None,
245 length: Self::Algorithm::DEFAULT_OUTPUT_SIZE,
246 }
247 }
248
249 fn generate_salt<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Salt {
251 Salt::random_with_size(rng, Self::Algorithm::MIN_SALT_SIZE).expect("Salt generation failed")
252 }
253}
254
255#[cfg(feature = "alloc")]
257pub struct HKdfOperation<'a, H: HashFunction + Clone> {
258 kdf: &'a TypedHkdf<H>,
259 ikm: Option<&'a [u8]>,
260 salt: Option<&'a [u8]>,
261 info: Option<&'a [u8]>,
262 length: usize,
263}
264
265#[cfg(feature = "alloc")]
266impl<'a, H: HashFunction + Clone> KdfOperation<'a, HkdfAlgorithm<H>> for HKdfOperation<'a, H> {
267 fn with_ikm(mut self, ikm: &'a [u8]) -> Self {
268 self.ikm = Some(ikm);
269 self
270 }
271
272 fn with_salt(mut self, salt: &'a [u8]) -> Self {
273 self.salt = Some(salt);
274 self
275 }
276
277 fn with_info(mut self, info: &'a [u8]) -> Self {
278 self.info = Some(info);
279 self
280 }
281
282 fn with_output_length(mut self, length: usize) -> Self {
283 self.length = length;
284 self
285 }
286
287 fn derive(self) -> Result<Vec<u8>> {
288 let ikm = self
289 .ikm
290 .ok_or_else(|| Error::param("ikm", "Input keying material is required"))?;
291
292 self.kdf.derive_key(ikm, self.salt, self.info, self.length)
293 }
294
295 fn derive_array<const N: usize>(self) -> Result<[u8; N]> {
296 if self.length != N {
298 return Err(Error::Length {
299 context: "HKDF output",
300 expected: N,
301 actual: self.length,
302 });
303 }
304
305 let vec = self.derive()?;
306
307 let mut array = [0u8; N];
309 array.copy_from_slice(&vec);
310 Ok(array)
311 }
312}
313
314pub enum Pbkdf2Algorithm<H: HashFunction> {
316 _Hash(PhantomData<H>),
318}
319
320impl<H: HashFunction> KdfAlgorithm for Pbkdf2Algorithm<H> {
321 const MIN_SALT_SIZE: usize = 16;
322 const DEFAULT_OUTPUT_SIZE: usize = 32;
323 const ALGORITHM_ID: &'static str = "PBKDF2";
324
325 fn name() -> String {
326 format!("{}-{}", Self::ALGORITHM_ID, H::name())
327 }
328
329 fn security_level() -> SecurityLevel {
330 match H::output_size() * 8 {
332 bits if bits >= 512 => SecurityLevel::L128, bits if bits >= 384 => SecurityLevel::L128,
334 bits if bits >= 256 => SecurityLevel::L128,
335 bits => SecurityLevel::Custom(bits as u32 / 2),
336 }
337 }
338}
339
340#[cfg(feature = "alloc")]
342pub struct TypedPbkdf2<H: HashFunction + Clone> {
343 inner: pbkdf2::Pbkdf2<H, 16>, _phantom: PhantomData<H>,
345}
346
347#[cfg(feature = "alloc")]
348impl<H: HashFunction + Clone> KeyDerivationFunction for TypedPbkdf2<H> {
349 type Algorithm = Pbkdf2Algorithm<H>;
350 type Salt = Salt<16>; fn new() -> Self {
353 Self {
354 inner: pbkdf2::Pbkdf2::new(),
355 _phantom: PhantomData,
356 }
357 }
358
359 #[cfg(feature = "alloc")]
360 fn derive_key(
361 &self,
362 input: &[u8],
363 salt: Option<&[u8]>,
364 info: Option<&[u8]>,
365 length: usize,
366 ) -> Result<Vec<u8>> {
367 self.inner.derive_key(input, salt, info, length)
368 }
369
370 fn builder(&self) -> impl KdfOperation<'_, Self::Algorithm> {
372 Pbkdf2Builder {
373 kdf: self,
374 password: None,
375 salt: None,
376 iterations: 600_000, length: Self::Algorithm::DEFAULT_OUTPUT_SIZE,
378 }
379 }
380
381 fn generate_salt<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Salt {
383 Salt::random_with_size(rng, Self::Algorithm::MIN_SALT_SIZE).expect("Salt generation failed")
384 }
385}
386
387#[cfg(feature = "alloc")]
389pub struct Pbkdf2Builder<'a, H: HashFunction + Clone> {
390 kdf: &'a TypedPbkdf2<H>,
391 password: Option<&'a [u8]>,
392 salt: Option<&'a [u8]>,
393 iterations: u32,
394 length: usize,
395}
396
397#[cfg(feature = "alloc")]
399impl<H: HashFunction + Clone> Pbkdf2Builder<'_, H> {
400 pub fn with_iterations(mut self, iterations: u32) -> Self {
402 self.iterations = iterations;
403 self
404 }
405}
406
407#[cfg(feature = "alloc")]
408impl<'a, H: HashFunction + Clone> KdfOperation<'a, Pbkdf2Algorithm<H>> for Pbkdf2Builder<'a, H> {
409 fn with_ikm(mut self, password: &'a [u8]) -> Self {
410 self.password = Some(password);
411 self
412 }
413
414 fn with_salt(mut self, salt: &'a [u8]) -> Self {
415 self.salt = Some(salt);
416 self
417 }
418
419 fn with_info(self, _info: &'a [u8]) -> Self {
420 self
422 }
423
424 fn with_output_length(mut self, length: usize) -> Self {
425 self.length = length;
426 self
427 }
428
429 fn derive(self) -> Result<Vec<u8>> {
430 let password = self
431 .password
432 .ok_or_else(|| Error::param("password", "Password is required"))?;
433 let salt = self
434 .salt
435 .ok_or_else(|| Error::param("salt", "Salt is required"))?;
436
437 let mut params = self.kdf.inner.params().clone();
439 params.iterations = self.iterations;
440 params.key_length = self.length;
441
442 let mut kdf = self.kdf.inner.clone();
444 kdf.set_params(params);
445
446 kdf.derive_key(password, Some(salt), None, self.length)
447 }
448
449 fn derive_array<const N: usize>(self) -> Result<[u8; N]> {
450 if self.length != N {
452 return Err(Error::Length {
453 context: "PBKDF2 output",
454 expected: N,
455 actual: self.length,
456 });
457 }
458
459 let vec = self.derive()?;
460
461 let mut array = [0u8; N];
463 array.copy_from_slice(&vec);
464 Ok(array)
465 }
466}
467
468pub trait PasswordHashFunction: KeyDerivationFunction + ParamProvider {
470 type Password: AsRef<[u8]> + AsMut<[u8]> + Clone + Zeroize;
472
473 fn hash_password(&self, password: &Self::Password) -> Result<PasswordHash>;
475
476 fn verify(&self, password: &Self::Password, hash: &PasswordHash) -> Result<bool>;
478
479 fn benchmark(&self) -> Duration;
481
482 fn recommended_params(target_duration: Duration) -> Self::Params;
484}