Skip to content

Commit

Permalink
password-hash: v0.2 breaking changes
Browse files Browse the repository at this point in the history
This commit contains a set of breaking changes intended to be released
as part of `password-hash` v0.2, addressing a number of currently open
issues about the crate discovered when integrating it into the crates in
the https://github.com/RustCrypto/password-hashes repo.

This includes:

- Allow specifying output length and version with params (#505)
- Allow passing `&str`, `&Salt`, or `&SaltString` as salt (#529)
- Simplify error handling (#547)
  • Loading branch information
tarcieri committed Apr 28, 2021
1 parent b96df69 commit c920298
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 406 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ cipher = { version = "=0.3.0-pre.4", optional = true, path = "../cipher" }
digest = { version = "0.10.0-pre", optional = true, path = "../digest" }
elliptic-curve = { version = "0.9", optional = true, path = "../elliptic-curve" }
mac = { version = "=0.11.0-pre", package = "crypto-mac", optional = true, path = "../crypto-mac" }
password-hash = { version = "0.1", optional = true, path = "../password-hash" }
password-hash = { version = "=0.2.0-pre", optional = true, path = "../password-hash" }
signature = { version = "1.3.0", optional = true, default-features = false, path = "../signature" }
universal-hash = { version = "0.4", optional = true, path = "../universal-hash" }

Expand Down
2 changes: 1 addition & 1 deletion password-hash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Traits which describe the functionality of password hashing algorithms,
as well as a `no_std`-friendly implementation of the PHC string format
(a well-defined subset of the Modular Crypt Format a.k.a. MCF)
"""
version = "0.1.4"
version = "0.2.0-pre"
authors = ["RustCrypto Developers"]
license = "MIT OR Apache-2.0"
readme = "README.md"
Expand Down
260 changes: 50 additions & 210 deletions password-hash/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,12 @@ pub use base64ct::Error as B64Error;

use core::fmt;

#[cfg(docsrs)]
use crate::PasswordHasher;
/// Result type.
pub type Result<T> = core::result::Result<T, Error>;

/// Password hash errors.
/// Password hashing errors.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum HashError {
/// Hash output error.
Hash(OutputError),

/// Params error.
Params(ParamsError),

/// Parse error.
Parse(ParseError),
}

impl fmt::Display for HashError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::Hash(err) => write!(f, "invalid password hash: {}", err),
Self::Params(err) => write!(f, "invalid params: {}", err),
Self::Parse(err) => write!(f, "parse error: {}", err),
}
}
}

impl From<OutputError> for HashError {
fn from(err: OutputError) -> HashError {
HashError::Hash(err)
}
}

impl From<ParamsError> for HashError {
fn from(err: ParamsError) -> HashError {
match err {
ParamsError::Parse(e) => e.into(),
_ => HashError::Params(err),
}
}
}

impl From<ParseError> for HashError {
fn from(err: ParseError) -> HashError {
HashError::Parse(err)
}
}

#[cfg(feature = "std")]
impl std::error::Error for HashError {}

/// Errors generating password hashes using a [`PasswordHasher`].
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum HasherError {
pub enum Error {
/// Unsupported algorithm.
Algorithm,

Expand All @@ -66,193 +19,80 @@ pub enum HasherError {
/// Cryptographic error.
Crypto,

/// Error generating output.
Output(OutputError),

/// Invalid parameter.
Params(ParamsError),

/// Parse error.
Parse(ParseError),

/// Invalid password.
Password,

/// Invalid algorithm version.
Version,
}

impl fmt::Display for HasherError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::Algorithm => write!(f, "unsupported algorithm"),
Self::B64(err) => write!(f, "{}", err),
Self::Crypto => write!(f, "cryptographic error"),
Self::Output(err) => write!(f, "PHF output error: {}", err),
Self::Params(err) => write!(f, "{}", err),
Self::Parse(err) => write!(f, "{}", err),
Self::Password => write!(f, "invalid password"),
Self::Version => write!(f, "invalid algorithm version"),
}
}
}

impl From<B64Error> for HasherError {
fn from(err: B64Error) -> HasherError {
HasherError::B64(err)
}
}

impl From<base64ct::InvalidLengthError> for HasherError {
fn from(_: base64ct::InvalidLengthError) -> HasherError {
HasherError::B64(B64Error::InvalidLength)
}
}

impl From<OutputError> for HasherError {
fn from(err: OutputError) -> HasherError {
HasherError::Output(err)
}
}

impl From<ParamsError> for HasherError {
fn from(err: ParamsError) -> HasherError {
HasherError::Params(err)
}
}

impl From<ParseError> for HasherError {
fn from(err: ParseError) -> HasherError {
HasherError::Parse(err)
}
}
/// Output too short (min 10-bytes).
OutputTooShort,

#[cfg(feature = "std")]
impl std::error::Error for HasherError {}
/// Output too long (max 64-bytes).
OutputTooLong,

/// Parameter-related errors.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ParamsError {
/// Duplicate parameter name encountered.
DuplicateName,
ParamNameDuplicated,

/// Invalid parameter name.
InvalidName,
ParamNameInvalid,

/// Invalid parameter value.
InvalidValue,
ParamValueInvalid,

/// Maximum number of parameters exceeded.
MaxExceeded,

/// Parse errors.
Parse(ParseError),
}

impl fmt::Display for ParamsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::DuplicateName => f.write_str("duplicate parameter"),
Self::InvalidName => f.write_str("invalid parameter name"),
Self::InvalidValue => f.write_str("invalid parameter value"),
Self::MaxExceeded => f.write_str("maximum number of parameters reached"),
Self::Parse(err) => write!(f, "{}", err),
}
}
}

impl From<ParseError> for ParamsError {
fn from(err: ParseError) -> ParamsError {
Self::Parse(err)
}
}

#[cfg(feature = "std")]
impl std::error::Error for ParamsError {}
ParamsMaxExceeded,

/// Parse errors.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ParseError {
/// Invalid empty input.
Empty,

/// Input contains invalid character.
InvalidChar(char),

/// Input too short.
TooShort,
/// Invalid password.
Password,

/// Input too long.
TooLong,
}
/// Password hash string contains invalid characters.
PhcStringInvalid,

impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::Empty => f.write_str("invalid empty input"),
Self::InvalidChar(char) => write!(f, "invalid character '{}'", char),
Self::TooShort => f.write_str("too short"),
Self::TooLong => f.write_str("too long"),
}
}
}
/// Password hash string too short.
PhcStringTooShort,

#[cfg(feature = "std")]
impl std::error::Error for ParseError {}
/// Password hash string too long.
PhcStringTooLong,

/// Password hash function output (i.e. hash/digest) errors.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum OutputError {
/// "B64" encoding error.
B64(B64Error),
/// Salt too short.
SaltTooShort,

/// Output too short (min 10-bytes).
TooShort,
/// Salt too long.
SaltTooLong,

/// Output too long (max 64-bytes).
TooLong,
/// Invalid algorithm version.
Version,
}

impl fmt::Display for OutputError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
match self {
Self::Algorithm => write!(f, "unsupported algorithm"),
Self::B64(err) => write!(f, "{}", err),
Self::TooShort => f.write_str("PHF output too short (min 10-bytes)"),
Self::TooLong => f.write_str("PHF output too long (max 64-bytes)"),
Self::Crypto => write!(f, "cryptographic error"),
Self::OutputTooShort => f.write_str("PHF output too short (min 10-bytes)"),
Self::OutputTooLong => f.write_str("PHF output too long (max 64-bytes)"),
Self::ParamNameDuplicated => f.write_str("duplicate parameter"),
Self::ParamNameInvalid => f.write_str("invalid parameter name"),
Self::ParamValueInvalid => f.write_str("invalid parameter value"),
Self::ParamsMaxExceeded => f.write_str("maximum number of parameters reached"),
Self::Password => write!(f, "invalid password"),
Self::PhcStringInvalid => write!(f, "password hash string invalid"),
Self::PhcStringTooShort => write!(f, "password hash string too short"),
Self::PhcStringTooLong => write!(f, "password hash string too long"),
Self::SaltTooShort => write!(f, "salt too short"),
Self::SaltTooLong => write!(f, "salt too long"),
Self::Version => write!(f, "invalid algorithm version"),
}
}
}

impl From<B64Error> for OutputError {
fn from(err: B64Error) -> OutputError {
OutputError::B64(err)
}
}

impl From<base64ct::InvalidLengthError> for OutputError {
fn from(_: base64ct::InvalidLengthError) -> OutputError {
OutputError::B64(B64Error::InvalidLength)
}
}

#[cfg(feature = "std")]
impl std::error::Error for OutputError {}

/// Password verification errors.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct VerifyError;
impl std::error::Error for Error {}

impl fmt::Display for VerifyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("password verification error")
impl From<B64Error> for Error {
fn from(err: B64Error) -> Error {
Error::B64(err)
}
}

impl From<HasherError> for VerifyError {
fn from(_: HasherError) -> VerifyError {
VerifyError
impl From<base64ct::InvalidLengthError> for Error {
fn from(_: base64ct::InvalidLengthError) -> Error {
Error::B64(B64Error::InvalidLength)
}
}

#[cfg(feature = "std")]
impl std::error::Error for VerifyError {}
Loading

0 comments on commit c920298

Please sign in to comment.