Coverage Report

Created: 2026-02-26 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/password-hash-0.4.2/src/traits.rs
Line
Count
Source
1
//! Trait definitions.
2
3
use crate::{Decimal, Error, Ident, ParamsString, PasswordHash, Result, Salt};
4
use core::fmt::Debug;
5
6
/// Trait for password hashing functions.
7
pub trait PasswordHasher {
8
    /// Algorithm-specific parameters.
9
    type Params: Clone
10
        + Debug
11
        + Default
12
        + for<'a> TryFrom<&'a PasswordHash<'a>, Error = Error>
13
        + TryInto<ParamsString, Error = Error>;
14
15
    /// Compute a [`PasswordHash`] from the provided password using an
16
    /// explicit set of customized algorithm parameters as opposed to the
17
    /// defaults.
18
    ///
19
    /// When in doubt, use [`PasswordHasher::hash_password`] instead.
20
    fn hash_password_customized<'a>(
21
        &self,
22
        password: &[u8],
23
        algorithm: Option<Ident<'a>>,
24
        version: Option<Decimal>,
25
        params: Self::Params,
26
        salt: impl Into<Salt<'a>>,
27
    ) -> Result<PasswordHash<'a>>;
28
29
    /// Simple API for computing a [`PasswordHash`] from a password and
30
    /// salt value.
31
    ///
32
    /// Uses the default recommended parameters for a given algorithm.
33
0
    fn hash_password<'a, S>(&self, password: &[u8], salt: &'a S) -> Result<PasswordHash<'a>>
34
0
    where
35
0
        S: AsRef<str> + ?Sized,
36
    {
37
0
        self.hash_password_customized(
38
0
            password,
39
0
            None,
40
0
            None,
41
0
            Self::Params::default(),
42
0
            Salt::try_from(salt.as_ref())?,
43
        )
44
0
    }
45
}
46
47
/// Trait for password verification.
48
///
49
/// Automatically impl'd for any type that impls [`PasswordHasher`].
50
///
51
/// This trait is object safe and can be used to implement abstractions over
52
/// multiple password hashing algorithms. One such abstraction is provided by
53
/// the [`PasswordHash::verify_password`] method.
54
pub trait PasswordVerifier {
55
    /// Compute this password hashing function against the provided password
56
    /// using the parameters from the provided password hash and see if the
57
    /// computed output matches.
58
    fn verify_password(&self, password: &[u8], hash: &PasswordHash<'_>) -> Result<()>;
59
}
60
61
impl<T: PasswordHasher> PasswordVerifier for T {
62
0
    fn verify_password(&self, password: &[u8], hash: &PasswordHash<'_>) -> Result<()> {
63
0
        if let (Some(salt), Some(expected_output)) = (&hash.salt, &hash.hash) {
64
0
            let computed_hash = self.hash_password_customized(
65
0
                password,
66
0
                Some(hash.algorithm),
67
0
                hash.version,
68
0
                T::Params::try_from(hash)?,
69
0
                *salt,
70
0
            )?;
71
72
0
            if let Some(computed_output) = &computed_hash.hash {
73
                // See notes on `Output` about the use of a constant-time comparison
74
0
                if expected_output == computed_output {
75
0
                    return Ok(());
76
0
                }
77
0
            }
78
0
        }
79
80
0
        Err(Error::Password)
81
0
    }
82
}
83
84
/// Trait for password hashing algorithms which support the legacy
85
/// [Modular Crypt Format (MCF)][MCF].
86
///
87
/// [MCF]: https://passlib.readthedocs.io/en/stable/modular_crypt_format.html
88
pub trait McfHasher {
89
    /// Upgrade an MCF hash to a PHC hash. MCF follow this rough format:
90
    ///
91
    /// ```text
92
    /// $<id>$<content>
93
    /// ```
94
    ///
95
    /// MCF hashes are otherwise largely unstructured and parsed according to
96
    /// algorithm-specific rules so hashers must parse a raw string themselves.
97
    fn upgrade_mcf_hash<'a>(&self, hash: &'a str) -> Result<PasswordHash<'a>>;
98
99
    /// Verify a password hash in MCF format against the provided password.
100
0
    fn verify_mcf_hash(&self, password: &[u8], mcf_hash: &str) -> Result<()>
101
0
    where
102
0
        Self: PasswordVerifier,
103
    {
104
0
        self.verify_password(password, &self.upgrade_mcf_hash(mcf_hash)?)
105
0
    }
106
}