Coverage Report

Created: 2025-11-16 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}