Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions password-hash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@ alloc = ["phc?/alloc"]
getrandom = ["dep:getrandom", "phc?/getrandom"]
rand_core = ["dep:rand_core", "phc?/rand_core"]

[lints]
workspace = true

[package.metadata.docs.rs]
all-features = true
53 changes: 47 additions & 6 deletions password-hash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,23 @@ pub trait PasswordHasher<H> {
///
/// The salt should be unique per password. When in doubt, use [`PasswordHasher::hash_password`]
/// which will choose the salt for you.
///
/// # Errors
/// These will vary by algorithm/implementation of this trait, but may be due to:
/// - length restrictions on the password and/or salt
/// - algorithm-specific internal error
fn hash_password_with_salt(&self, password: &[u8], salt: &[u8]) -> Result<H>;

/// Compute the hash `H` from the given password, potentially using configuration stored in
/// `&self` for the parameters, or otherwise the recommended defaults.
///
/// A large random salt will be generated automatically.
///
/// # Errors
/// These will vary by algorithm/implementation of this trait, but may be due to:
/// - length restrictions on the password
/// - algorithm-specific internal error
/// - RNG internal error
#[cfg(feature = "getrandom")]
fn hash_password(&self, password: &[u8]) -> Result<H> {
let salt = try_generate_salt()?;
Expand All @@ -102,6 +113,12 @@ pub trait PasswordHasher<H> {
/// `&self` for the parameters, or otherwise the recommended defaults.
///
/// A large random salt will be generated automatically from the provided RNG.
///
/// # Errors
/// These will vary by algorithm/implementation of this trait, but may be due to:
/// - length restrictions on the password
/// - algorithm-specific internal error
/// - RNG internal error
#[cfg(feature = "rand_core")]
fn hash_password_with_rng<R: TryCryptoRng + ?Sized>(
&self,
Expand All @@ -121,11 +138,15 @@ pub trait CustomizedPasswordHasher<H> {
/// Algorithm-specific parameters.
type Params: Clone + Debug + Default;

/// Compute a [`PasswordHash`] from the provided password using an
/// explicit set of customized algorithm parameters as opposed to the
/// defaults.
/// Compute a [`PasswordHash`] from the provided password using an explicit set of customized
/// algorithm parameters as opposed to the defaults.
///
/// When in doubt, use [`PasswordHasher::hash_password`] instead.
///
/// # Errors
/// These will vary by algorithm/implementation of this trait, but may be due to:
/// - length restrictions on the password and/or salt
/// - algorithm-specific params or internal error
fn hash_password_customized(
&self,
password: &[u8],
Expand All @@ -137,6 +158,11 @@ pub trait CustomizedPasswordHasher<H> {

/// Compute a [`PasswordHash`] using customized parameters only, using the default
/// algorithm and version.
///
/// # Errors
/// These will vary by algorithm/implementation of this trait, but may be due to:
/// - length restrictions on the password and/or salt
/// - algorithm-specific params or internal error
fn hash_password_with_params(
&self,
password: &[u8],
Expand All @@ -156,9 +182,14 @@ pub trait CustomizedPasswordHasher<H> {
/// This trait is object safe and can be used to implement abstractions over
/// multiple password hashing algorithms.
pub trait PasswordVerifier<H: ?Sized> {
/// Compute this password hashing function against the provided password
/// using the parameters from the provided password hash and see if the
/// computed output matches.
/// Compute this password hashing function against the provided password using the parameters
/// from the provided password hash and see if the computed output matches.
///
/// # Errors
/// - Returns `Error::Algorithm` if the algorithm being requested by the hash `H` is unsupported
/// - Returns `Error::PasswordInvalid` if the hash for the supplied password does not match
/// the provided hash
/// - May return other algorithm-specific errors
fn verify_password(&self, password: &[u8], hash: &H) -> Result<()>;
}

Expand Down Expand Up @@ -207,17 +238,27 @@ pub trait McfHasher {
///
/// MCF hashes are otherwise largely unstructured and parsed according to
/// algorithm-specific rules so hashers must parse a raw string themselves.
///
/// # Errors
/// Returns errors if the the hash couldn't be converted
fn upgrade_mcf_hash(&self, hash: &str) -> Result<phc::PasswordHash>;
}

/// Generate a random salt value of the recommended length using the system's secure RNG.
///
/// # Panics
/// If the system's secure RNG experiences an internal failure.
#[cfg(feature = "getrandom")]
#[must_use]
pub fn generate_salt() -> [u8; RECOMMENDED_SALT_LEN] {
try_generate_salt().expect("RNG failure")
}

/// Try generating a random salt value of the recommended length using the system's secure RNG,
/// returning errors if they occur.
///
/// # Errors
/// If the system's secure RNG experiences an internal failure.
#[cfg(feature = "getrandom")]
pub fn try_generate_salt() -> core::result::Result<[u8; RECOMMENDED_SALT_LEN], getrandom::Error> {
let mut salt = [0u8; RECOMMENDED_SALT_LEN];
Expand Down
3 changes: 2 additions & 1 deletion password-hash/tests/traits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Password hashing tests

#![cfg(feature = "phc")]
#![allow(missing_copy_implementations, missing_debug_implementations)]

use core::{fmt::Display, str::FromStr};
use password_hash::{CustomizedPasswordHasher, Error, PasswordHasher, Result};
Expand Down Expand Up @@ -58,7 +59,7 @@ impl PasswordHasher<PasswordHash> for StubPasswordHasher {
pub struct StubParams;

impl Display for StubParams {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Ok(())
}
}
Expand Down