Skip to content

Commit 9c5a7f6

Browse files
authored
password-hash: add generic H param to traits (#2110)
Adds a generic `H` parameter to the `(Customized)PasswordHasher` and `PasswordVerifier` traits which specifies the return type and the hash type respectively. A generic parameter is used instead of an associated constant in order to support overlapping impls. Notably multiple commonly used password hashing algorithms (e.g. PBKDF2, scrypt) support encoding in either the Modular Crypt Format (MCF) or Password Hashing Competition (PHC) string format, which are implemented as the `mcf::PasswordHash` and `phc::PasswordHash` types respectively. We already have open issues to add MCF support where we currently don't support it (RustCrypto/password-hashes#727, RustCrypto/password-hashes#747). The blanket impl of `PasswordVerifier` for `CustomizedPasswordHasher` is retained, but only for `phc::PasswordHash`, as supporting it for MCF requires algorithmic-specific interpretation of the hash. However, algorithms can provide their own impls of `PasswordVerifier<mcf::PasswordHash>`.
1 parent cc1362e commit 9c5a7f6

File tree

3 files changed

+26
-21
lines changed

3 files changed

+26
-21
lines changed

password-hash/src/lib.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,20 @@ use core::{
4949
pub type Version = u32;
5050

5151
/// Trait for password hashing functions.
52-
pub trait PasswordHasher {
52+
///
53+
/// Generic around a password hash to be returned (typically [`PasswordHash`])
54+
pub trait PasswordHasher<H> {
5355
/// Simple API for computing a [`PasswordHash`] from a password and
5456
/// salt value.
5557
///
5658
/// Uses the default recommended parameters for a given algorithm.
57-
fn hash_password(&self, password: &[u8], salt: &[u8]) -> Result<PasswordHash>;
59+
fn hash_password(&self, password: &[u8], salt: &[u8]) -> Result<H>;
5860
}
5961

6062
/// Trait for password hashing functions which support customization.
61-
pub trait CustomizedPasswordHasher {
63+
///
64+
/// Generic around a password hash to be returned (typically [`PasswordHash`])
65+
pub trait CustomizedPasswordHasher<H> {
6266
/// Algorithm-specific parameters.
6367
type Params: Clone + Debug + Default + Display + FromStr<Err = Error>;
6468

@@ -74,24 +78,26 @@ pub trait CustomizedPasswordHasher {
7478
algorithm: Option<&str>,
7579
version: Option<Version>,
7680
params: Self::Params,
77-
) -> Result<PasswordHash>;
81+
) -> Result<H>;
7882
}
7983

8084
/// Trait for password verification.
8185
///
82-
/// Automatically impl'd for any type that impls [`PasswordHasher`].
86+
/// Generic around a password hash to be returned (typically [`PasswordHash`])
87+
///
88+
/// Automatically impl'd for any type that impls [`PasswordHasher`] with [`PasswordHash`] as `H`.
8389
///
8490
/// This trait is object safe and can be used to implement abstractions over
8591
/// multiple password hashing algorithms. One such abstraction is provided by
8692
/// the [`PasswordHash::verify_password`] method.
87-
pub trait PasswordVerifier {
93+
pub trait PasswordVerifier<H> {
8894
/// Compute this password hashing function against the provided password
8995
/// using the parameters from the provided password hash and see if the
9096
/// computed output matches.
91-
fn verify_password(&self, password: &[u8], hash: &PasswordHash) -> Result<()>;
97+
fn verify_password(&self, password: &[u8], hash: &H) -> Result<()>;
9298
}
9399

94-
impl<T: CustomizedPasswordHasher> PasswordVerifier for T {
100+
impl<T: CustomizedPasswordHasher<PasswordHash>> PasswordVerifier<PasswordHash> for T {
95101
fn verify_password(&self, password: &[u8], hash: &PasswordHash) -> Result<()> {
96102
#[allow(clippy::single_match)]
97103
match (&hash.salt, &hash.hash) {
@@ -136,7 +142,7 @@ pub trait McfHasher {
136142
/// Verify a password hash in MCF format against the provided password.
137143
fn verify_mcf_hash(&self, password: &[u8], mcf_hash: &str) -> Result<()>
138144
where
139-
Self: PasswordVerifier,
145+
Self: PasswordVerifier<PasswordHash>,
140146
{
141147
self.verify_password(password, &self.upgrade_mcf_hash(mcf_hash)?)
142148
}

password-hash/src/phc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ impl PasswordHash {
158158

159159
/// Generate a password hash using the supplied algorithm.
160160
pub fn generate(
161-
phf: impl PasswordHasher,
161+
phf: impl PasswordHasher<Self>,
162162
password: impl AsRef<[u8]>,
163163
salt: &[u8],
164164
) -> crate::Result<Self> {
@@ -169,7 +169,7 @@ impl PasswordHash {
169169
/// [`PasswordHasher`] trait objects.
170170
pub fn verify_password(
171171
&self,
172-
phfs: &[&dyn PasswordVerifier],
172+
phfs: &[&dyn PasswordVerifier<Self>],
173173
password: impl AsRef<[u8]>,
174174
) -> crate::Result<()> {
175175
for &phf in phfs {

password-hash/tests/hashing.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
//! Password hashing tests
22
33
use core::{fmt::Display, str::FromStr};
4-
use password_hash::PasswordHasher;
5-
pub use password_hash::{
6-
CustomizedPasswordHasher,
4+
use password_hash::{
5+
CustomizedPasswordHasher, PasswordHasher,
76
errors::{Error, Result},
87
phc::{Decimal, Ident, Output, ParamsString, PasswordHash, Salt},
98
};
@@ -13,13 +12,7 @@ const ALG: Ident = Ident::new_unwrap("example");
1312
/// Stub password hashing function for testing.
1413
pub struct StubPasswordHasher;
1514

16-
impl PasswordHasher for StubPasswordHasher {
17-
fn hash_password(&self, password: &[u8], salt: &[u8]) -> Result<PasswordHash> {
18-
self.hash_password_customized(password, salt, None, None, StubParams)
19-
}
20-
}
21-
22-
impl CustomizedPasswordHasher for StubPasswordHasher {
15+
impl CustomizedPasswordHasher<PasswordHash> for StubPasswordHasher {
2316
type Params = StubParams;
2417

2518
fn hash_password_customized(
@@ -55,6 +48,12 @@ impl CustomizedPasswordHasher for StubPasswordHasher {
5548
}
5649
}
5750

51+
impl PasswordHasher<PasswordHash> for StubPasswordHasher {
52+
fn hash_password(&self, password: &[u8], salt: &[u8]) -> Result<PasswordHash> {
53+
self.hash_password_customized(password, salt, None, None, StubParams)
54+
}
55+
}
56+
5857
/// Stub parameters
5958
#[derive(Clone, Debug, Default)]
6059
pub struct StubParams;

0 commit comments

Comments
 (0)