diff --git a/Cargo.lock b/Cargo.lock index 80f100a3..0c493bc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -324,6 +324,7 @@ dependencies = [ name = "password-hash" version = "0.6.0-rc.4" dependencies = [ + "getrandom", "phc", ] @@ -343,6 +344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61f960577aaac5c259bc0866d685ba315c0ed30793c602d7287f54980913863" dependencies = [ "base64ct", + "getrandom", "subtle", ] diff --git a/password-hash/Cargo.toml b/password-hash/Cargo.toml index df40710e..ec302dd1 100644 --- a/password-hash/Cargo.toml +++ b/password-hash/Cargo.toml @@ -17,10 +17,12 @@ as well as a `no_std`-friendly implementation of the PHC string format """ [dependencies] +getrandom = { version = "0.3", optional = true, default-features = false } phc = { version = "0.6.0-rc.0", optional = true, default-features = false } [features] alloc = ["phc?/alloc"] +getrandom = ["dep:getrandom", "phc?/getrandom"] [package.metadata.docs.rs] all-features = true diff --git a/password-hash/src/lib.rs b/password-hash/src/lib.rs index fc71c3f9..292c8b04 100644 --- a/password-hash/src/lib.rs +++ b/password-hash/src/lib.rs @@ -61,15 +61,40 @@ use core::{ /// Numeric version identifier for password hashing algorithms. pub type Version = u32; -/// Trait for password hashing functions. +/// Recommended length of a salt: 16-bytes. /// -/// Generic around a password hash to be returned (typically [`PasswordHash`]) +/// This recommendation comes from the [PHC string format specification]: +/// +/// > The role of salts is to achieve uniqueness. A *random* salt is fine +/// > for that as long as its length is sufficient; a 16-byte salt would +/// > work well (by definition, UUID are very good salts, and they encode +/// > over exactly 16 bytes). 16 bytes encode as 22 characters in B64. +/// +/// [PHC string format specification]: https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md#function-duties +#[cfg(feature = "getrandom")] +const RECOMMENDED_SALT_LEN: usize = 16; + +/// High-level trait for password hashing functions. +/// +/// Generic around a password hash to be returned (typically [`phc::PasswordHash`]) pub trait PasswordHasher { - /// Simple API for computing a [`PasswordHash`] from a password and - /// salt value. + /// Compute the hash `H` from the given password and salt, potentially using configuration + /// stored in `&self` for the parameters, or otherwise the recommended defaults. + /// + /// The salt should be unique per password. When in doubt, use [`PasswordHasher::hash_password`] + /// which will choose the salt for you. + fn hash_password_with_salt(&self, password: &[u8], salt: &[u8]) -> Result; + + /// Compute the hash `H` from the given password, potentially using configuration stored in + /// `&self` for the parameters, or otherwise the recommended defaults. /// - /// Uses the default recommended parameters for a given algorithm. - fn hash_password(&self, password: &[u8], salt: &[u8]) -> Result; + /// A large random salt will be generated automatically. + #[cfg(feature = "getrandom")] + fn hash_password(&self, password: &[u8]) -> Result { + let mut salt = [0u8; RECOMMENDED_SALT_LEN]; + getrandom::fill(&mut salt).map_err(|_| Error::Crypto)?; + self.hash_password_with_salt(password, &salt) + } } /// Trait for password hashing functions which support customization. diff --git a/password-hash/tests/traits.rs b/password-hash/tests/traits.rs index de63e7cd..dd5e2406 100644 --- a/password-hash/tests/traits.rs +++ b/password-hash/tests/traits.rs @@ -48,7 +48,7 @@ impl CustomizedPasswordHasher for StubPasswordHasher { } impl PasswordHasher for StubPasswordHasher { - fn hash_password(&self, password: &[u8], salt: &[u8]) -> Result { + fn hash_password_with_salt(&self, password: &[u8], salt: &[u8]) -> Result { self.hash_password_customized(password, salt, None, None, StubParams) } } @@ -84,7 +84,7 @@ fn verify_password_hash() { let valid_password = b"test password"; let salt = Salt::from_b64("testsalt000").unwrap(); let hash = StubPasswordHasher - .hash_password(valid_password, &salt) + .hash_password_with_salt(valid_password, &salt) .unwrap(); // Sanity tests for StubFunction impl above