11//! This crate implements the PBKDF2 key derivation function as specified
22//! in [RFC 2898](https://tools.ietf.org/html/rfc2898).
33//!
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`:
4+ //! # Examples
75//!
8- //! ```toml
9- //! [dependencies]
10- //! pbkdf2 = { version = "0.11", default-features = false }
6+ //! PBKDF2 is defined in terms of a keyed pseudo-random function (PRF). Most
7+ //! commonly HMAC is used as this PRF. In such cases you can use [`pbkdf2_hmac`]
8+ //! and [`pbkdf2_hmac_array`] functions. The former accepts a byte slice which
9+ //! gets filled with generated key, while the former returns an array with
10+ //! generated key of requested length.
11+ //!
12+ //! ```
13+ //! # #[cfg(feature = "hmac")] {
14+ //! use hex_literal::hex;
15+ //! use pbkdf2::{pbkdf2_hmac, pbkdf2_hmac_array};
16+ //! use sha2::Sha256;
17+ //!
18+ //! let password = b"password";
19+ //! let salt = b"salt";
20+ //! // number of iterations
21+ //! let n = 4096;
22+ //! // Expected value of generated key
23+ //! let expected = hex!("c5e478d59288c841aa530db6845c4c8d962893a0");
24+ //!
25+ //! let mut key1 = [0u8; 20];
26+ //! pbkdf2_hmac::<Sha256>(password, salt, n, &mut key1);
27+ //! assert_eq!(key1, expected);
28+ //!
29+ //! let key2 = pbkdf2_hmac_array::<Sha256, 20>(password, salt, n);
30+ //! assert_eq!(key2, expected);
31+ //! # }
1132//! ```
1233//!
13- //! # Usage (simple with default params)
34+ //! If you want to use a different PRF, then you can use [`pbkdf2`][crate::pbkdf2]
35+ //! and [`pbkdf2_array`] functions.
1436//!
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)
37+ //! This crates also provides the high-level password-hashing API through
38+ //! the [`Pbkdf2`] struct and traits defined in the
39+ //! [`password-hash`][password_hash] crate.
1840//!
1941//! Add the following to your crate's `Cargo.toml` to import it:
2042//!
2143//! ```toml
2244//! [dependencies]
23- //! pbkdf2 = "0.10"
45+ //! pbkdf2 = { version = "0.12", features = ["simple"] }
2446//! rand_core = { version = "0.6", features = ["std"] }
2547//! ```
2648//!
@@ -78,7 +100,15 @@ pub use crate::simple::{Algorithm, Params, Pbkdf2};
78100#[ cfg( feature = "parallel" ) ]
79101use rayon:: prelude:: * ;
80102
81- use digest:: { generic_array:: typenum:: Unsigned , FixedOutput , KeyInit , Update } ;
103+ use digest:: { generic_array:: typenum:: Unsigned , FixedOutput , InvalidLength , KeyInit , Update } ;
104+
105+ #[ cfg( feature = "hmac" ) ]
106+ use digest:: {
107+ block_buffer:: Eager ,
108+ core_api:: { BlockSizeUser , BufferKindUser , CoreProxy , FixedOutputCore , UpdateCore } ,
109+ generic_array:: typenum:: { IsLess , Le , NonZero , U256 } ,
110+ HashMarker ,
111+ } ;
82112
83113#[ inline( always) ]
84114fn xor ( res : & mut [ u8 ] , salt : & [ u8 ] ) {
@@ -89,7 +119,7 @@ fn xor(res: &mut [u8], salt: &[u8]) {
89119#[ inline( always) ]
90120fn pbkdf2_body < PRF > ( i : u32 , chunk : & mut [ u8 ] , prf : & PRF , salt : & [ u8 ] , rounds : u32 )
91121where
92- PRF : KeyInit + Update + FixedOutput + Clone ,
122+ PRF : Update + FixedOutput + Clone ,
93123{
94124 for v in chunk. iter_mut ( ) {
95125 * v = 0 ;
@@ -114,34 +144,136 @@ where
114144 }
115145}
116146
117- /// Generic implementation of PBKDF2 algorithm.
118- #[ cfg( not( feature = "parallel" ) ) ]
147+ /// Generic implementation of PBKDF2 algorithm which accepts an arbitrary keyed PRF.
148+ ///
149+ /// ```
150+ /// use hex_literal::hex;
151+ /// use pbkdf2::pbkdf2;
152+ /// use hmac::Hmac;
153+ /// use sha2::Sha256;
154+ ///
155+ /// let mut buf = [0u8; 20];
156+ /// pbkdf2::<Hmac<Sha256>>(b"password", b"salt", 4096, &mut buf)
157+ /// .expect("HMAC can be initialized with any key length");
158+ /// assert_eq!(buf, hex!("c5e478d59288c841aa530db6845c4c8d962893a0"));
159+ /// ```
119160#[ inline]
120- pub fn pbkdf2 < PRF > ( password : & [ u8 ] , salt : & [ u8 ] , rounds : u32 , res : & mut [ u8 ] )
161+ pub fn pbkdf2 < PRF > (
162+ password : & [ u8 ] ,
163+ salt : & [ u8 ] ,
164+ rounds : u32 ,
165+ res : & mut [ u8 ] ,
166+ ) -> Result < ( ) , InvalidLength >
121167where
122168 PRF : KeyInit + Update + FixedOutput + Clone + Sync ,
123169{
124170 let n = PRF :: OutputSize :: to_usize ( ) ;
125171 // note: HMAC can be initialized with keys of any size,
126172 // so this panic never happens with it
127- let prf = PRF :: new_from_slice ( password) . expect ( "PRF initialization failure" ) ;
173+ let prf = PRF :: new_from_slice ( password) ? ;
128174
129- for ( i, chunk) in res. chunks_mut ( n) . enumerate ( ) {
130- pbkdf2_body ( i as u32 , chunk, & prf, salt, rounds) ;
175+ #[ cfg( not( feature = "parallel" ) ) ]
176+ {
177+ for ( i, chunk) in res. chunks_mut ( n) . enumerate ( ) {
178+ pbkdf2_body ( i as u32 , chunk, & prf, salt, rounds) ;
179+ }
180+ }
181+ #[ cfg( feature = "parallel" ) ]
182+ {
183+ res. par_chunks_mut ( n) . enumerate ( ) . for_each ( |( i, chunk) | {
184+ pbkdf2_body ( i as u32 , chunk, & prf, salt, rounds) ;
185+ } ) ;
131186 }
187+
188+ Ok ( ( ) )
132189}
133190
134- /// Generic implementation of PBKDF2 algorithm.
135- #[ cfg( feature = "parallel" ) ]
191+ /// A variant of the [`pbkdf2`][crate::pbkdf2] function which returns an array
192+ /// instead of filling an input slice.
193+ ///
194+ /// ```
195+ /// use hex_literal::hex;
196+ /// use pbkdf2::pbkdf2_array;
197+ /// use hmac::Hmac;
198+ /// use sha2::Sha256;
199+ ///
200+ /// let res = pbkdf2_array::<Hmac<Sha256>, 20>(b"password", b"salt", 4096)
201+ /// .expect("HMAC can be initialized with any key length");
202+ /// assert_eq!(res, hex!("c5e478d59288c841aa530db6845c4c8d962893a0"));
203+ /// ```
136204#[ inline]
137- pub fn pbkdf2 < PRF > ( password : & [ u8 ] , salt : & [ u8 ] , rounds : u32 , res : & mut [ u8 ] )
205+ pub fn pbkdf2_array < PRF , const N : usize > (
206+ password : & [ u8 ] ,
207+ salt : & [ u8 ] ,
208+ rounds : u32 ,
209+ ) -> Result < [ u8 ; N ] , InvalidLength >
138210where
139211 PRF : KeyInit + Update + FixedOutput + Clone + Sync ,
140212{
141- let n = PRF :: OutputSize :: to_usize ( ) ;
142- let prf = PRF :: new_from_slice ( password) . expect ( "PRF initialization failure" ) ;
213+ let mut buf = [ 0u8 ; N ] ;
214+ pbkdf2 :: < PRF > ( password, salt, rounds, & mut buf) . map ( |( ) | buf)
215+ }
216+
217+ /// A variant of the [`pbkdf2`][crate::pbkdf2] function which uses HMAC for PRF.
218+ /// It's generic over (eager) hash functions.
219+ ///
220+ /// ```
221+ /// use hex_literal::hex;
222+ /// use pbkdf2::pbkdf2_hmac;
223+ /// use sha2::Sha256;
224+ ///
225+ /// let mut buf = [0u8; 20];
226+ /// pbkdf2_hmac::<Sha256>(b"password", b"salt", 4096, &mut buf);
227+ /// assert_eq!(buf, hex!("c5e478d59288c841aa530db6845c4c8d962893a0"));
228+ /// ```
229+ #[ cfg( feature = "hmac" ) ]
230+ #[ cfg_attr( docsrs, doc( cfg( feature = "hmac" ) ) ) ]
231+ pub fn pbkdf2_hmac < D > ( password : & [ u8 ] , salt : & [ u8 ] , rounds : u32 , res : & mut [ u8 ] )
232+ where
233+ D : CoreProxy ,
234+ D :: Core : Sync
235+ + HashMarker
236+ + UpdateCore
237+ + FixedOutputCore
238+ + BufferKindUser < BufferKind = Eager >
239+ + Default
240+ + Clone ,
241+ <D :: Core as BlockSizeUser >:: BlockSize : IsLess < U256 > ,
242+ Le < <D :: Core as BlockSizeUser >:: BlockSize , U256 > : NonZero ,
243+ {
244+ crate :: pbkdf2 :: < hmac:: Hmac < D > > ( password, salt, rounds, res)
245+ . expect ( "HMAC can be initialized with any key length" ) ;
246+ }
143247
144- res. par_chunks_mut ( n) . enumerate ( ) . for_each ( |( i, chunk) | {
145- pbkdf2_body ( i as u32 , chunk, & prf, salt, rounds) ;
146- } ) ;
248+ /// A variant of the [`pbkdf2_hmac`] function which returns an array
249+ /// instead of filling an input slice.
250+ ///
251+ /// ```
252+ /// use hex_literal::hex;
253+ /// use pbkdf2::pbkdf2_hmac_array;
254+ /// use sha2::Sha256;
255+ ///
256+ /// assert_eq!(
257+ /// pbkdf2_hmac_array::<Sha256, 20>(b"password", b"salt", 4096),
258+ /// hex!("c5e478d59288c841aa530db6845c4c8d962893a0"),
259+ /// );
260+ /// ```
261+ #[ cfg( feature = "hmac" ) ]
262+ #[ cfg_attr( docsrs, doc( cfg( feature = "hmac" ) ) ) ]
263+ pub fn pbkdf2_hmac_array < D , const N : usize > ( password : & [ u8 ] , salt : & [ u8 ] , rounds : u32 ) -> [ u8 ; N ]
264+ where
265+ D : CoreProxy ,
266+ D :: Core : Sync
267+ + HashMarker
268+ + UpdateCore
269+ + FixedOutputCore
270+ + BufferKindUser < BufferKind = Eager >
271+ + Default
272+ + Clone ,
273+ <D :: Core as BlockSizeUser >:: BlockSize : IsLess < U256 > ,
274+ Le < <D :: Core as BlockSizeUser >:: BlockSize , U256 > : NonZero ,
275+ {
276+ let mut buf = [ 0u8 ; N ] ;
277+ pbkdf2_hmac :: < D > ( password, salt, rounds, & mut buf) ;
278+ buf
147279}
0 commit comments