/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pbkdf2-0.11.0/src/lib.rs
Line | Count | Source |
1 | | //! This crate implements the PBKDF2 key derivation function as specified |
2 | | //! in [RFC 2898](https://tools.ietf.org/html/rfc2898). |
3 | | //! |
4 | | //! If you are only using the low-level [`pbkdf2`] function instead of the |
5 | | //! higher-level [`Pbkdf2`] struct to produce/verify hash strings, |
6 | | //! it's recommended to disable default features in your `Cargo.toml`: |
7 | | //! |
8 | | //! ```toml |
9 | | //! [dependencies] |
10 | | //! pbkdf2 = { version = "0.11", default-features = false } |
11 | | //! ``` |
12 | | //! |
13 | | //! # Usage (simple with default params) |
14 | | //! |
15 | | //! Note: this example requires the `rand_core` crate with the `std` feature |
16 | | //! enabled for `rand_core::OsRng` (embedded platforms can substitute their |
17 | | //! own RNG) |
18 | | //! |
19 | | //! Add the following to your crate's `Cargo.toml` to import it: |
20 | | //! |
21 | | //! ```toml |
22 | | //! [dependencies] |
23 | | //! pbkdf2 = "0.10" |
24 | | //! rand_core = { version = "0.6", features = ["std"] } |
25 | | //! ``` |
26 | | //! |
27 | | //! The following example demonstrates the high-level password hashing API: |
28 | | //! |
29 | | //! ``` |
30 | | //! # fn main() -> Result<(), Box<dyn std::error::Error>> { |
31 | | //! # #[cfg(all(feature = "simple", feature = "std"))] |
32 | | //! # { |
33 | | //! use pbkdf2::{ |
34 | | //! password_hash::{ |
35 | | //! rand_core::OsRng, |
36 | | //! PasswordHash, PasswordHasher, PasswordVerifier, SaltString |
37 | | //! }, |
38 | | //! Pbkdf2 |
39 | | //! }; |
40 | | //! |
41 | | //! let password = b"hunter42"; // Bad password; don't actually use! |
42 | | //! let salt = SaltString::generate(&mut OsRng); |
43 | | //! |
44 | | //! // Hash password to PHC string ($pbkdf2-sha256$...) |
45 | | //! let password_hash = Pbkdf2.hash_password(password, &salt)?.to_string(); |
46 | | //! |
47 | | //! // Verify password against PHC string |
48 | | //! let parsed_hash = PasswordHash::new(&password_hash)?; |
49 | | //! assert!(Pbkdf2.verify_password(password, &parsed_hash).is_ok()); |
50 | | //! # } |
51 | | //! # Ok(()) |
52 | | //! # } |
53 | | //! ``` |
54 | | |
55 | | #![no_std] |
56 | | #![cfg_attr(docsrs, feature(doc_cfg))] |
57 | | #![doc( |
58 | | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", |
59 | | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" |
60 | | )] |
61 | | |
62 | | #[cfg(feature = "std")] |
63 | | extern crate std; |
64 | | |
65 | | #[cfg(feature = "simple")] |
66 | | extern crate alloc; |
67 | | |
68 | | #[cfg(feature = "simple")] |
69 | | #[cfg_attr(docsrs, doc(cfg(feature = "simple")))] |
70 | | pub use password_hash; |
71 | | |
72 | | #[cfg(feature = "simple")] |
73 | | mod simple; |
74 | | |
75 | | #[cfg(feature = "simple")] |
76 | | pub use crate::simple::{Algorithm, Params, Pbkdf2}; |
77 | | |
78 | | #[cfg(feature = "parallel")] |
79 | | use rayon::prelude::*; |
80 | | |
81 | | use digest::{generic_array::typenum::Unsigned, FixedOutput, KeyInit, Update}; |
82 | | |
83 | | #[inline(always)] |
84 | 0 | fn xor(res: &mut [u8], salt: &[u8]) { |
85 | 0 | debug_assert!(salt.len() >= res.len(), "length mismatch in xor"); |
86 | 0 | res.iter_mut().zip(salt.iter()).for_each(|(a, b)| *a ^= b); |
87 | 0 | } |
88 | | |
89 | | #[inline(always)] |
90 | 0 | fn pbkdf2_body<PRF>(i: u32, chunk: &mut [u8], prf: &PRF, salt: &[u8], rounds: u32) |
91 | 0 | where |
92 | 0 | PRF: KeyInit + Update + FixedOutput + Clone, |
93 | | { |
94 | 0 | for v in chunk.iter_mut() { |
95 | 0 | *v = 0; |
96 | 0 | } |
97 | | |
98 | 0 | let mut salt = { |
99 | 0 | let mut prfc = prf.clone(); |
100 | 0 | prfc.update(salt); |
101 | 0 | prfc.update(&(i + 1).to_be_bytes()); |
102 | | |
103 | 0 | let salt = prfc.finalize_fixed(); |
104 | 0 | xor(chunk, &salt); |
105 | 0 | salt |
106 | | }; |
107 | | |
108 | 0 | for _ in 1..rounds { |
109 | 0 | let mut prfc = prf.clone(); |
110 | 0 | prfc.update(&salt); |
111 | 0 | salt = prfc.finalize_fixed(); |
112 | 0 |
|
113 | 0 | xor(chunk, &salt); |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | /// Generic implementation of PBKDF2 algorithm. |
118 | | #[cfg(not(feature = "parallel"))] |
119 | | #[inline] |
120 | 0 | pub fn pbkdf2<PRF>(password: &[u8], salt: &[u8], rounds: u32, res: &mut [u8]) |
121 | 0 | where |
122 | 0 | PRF: KeyInit + Update + FixedOutput + Clone + Sync, |
123 | | { |
124 | 0 | let n = PRF::OutputSize::to_usize(); |
125 | | // note: HMAC can be initialized with keys of any size, |
126 | | // so this panic never happens with it |
127 | 0 | let prf = PRF::new_from_slice(password).expect("PRF initialization failure"); |
128 | | |
129 | 0 | for (i, chunk) in res.chunks_mut(n).enumerate() { |
130 | 0 | pbkdf2_body(i as u32, chunk, &prf, salt, rounds); |
131 | 0 | } |
132 | 0 | } |
133 | | |
134 | | /// Generic implementation of PBKDF2 algorithm. |
135 | | #[cfg(feature = "parallel")] |
136 | | #[inline] |
137 | | pub fn pbkdf2<PRF>(password: &[u8], salt: &[u8], rounds: u32, res: &mut [u8]) |
138 | | where |
139 | | PRF: KeyInit + Update + FixedOutput + Clone + Sync, |
140 | | { |
141 | | let n = PRF::OutputSize::to_usize(); |
142 | | let prf = PRF::new_from_slice(password).expect("PRF initialization failure"); |
143 | | |
144 | | res.par_chunks_mut(n).enumerate().for_each(|(i, chunk)| { |
145 | | pbkdf2_body(i as u32, chunk, &prf, salt, rounds); |
146 | | }); |
147 | | } |