password_hash/
errors.rs

1//! Error types.
2
3pub use base64ct::Error as B64Error;
4
5use core::cmp::Ordering;
6use core::fmt;
7
8/// Result type.
9pub type Result<T> = core::result::Result<T, Error>;
10
11/// Password hashing errors.
12#[derive(Copy, Clone, Debug, Eq, PartialEq)]
13#[non_exhaustive]
14pub enum Error {
15    /// Unsupported algorithm.
16    Algorithm,
17
18    /// "B64" encoding error.
19    B64Encoding(B64Error),
20
21    /// Cryptographic error.
22    Crypto,
23
24    /// Output size unexpected.
25    OutputSize {
26        /// Indicates why the output size is unexpected.
27        ///
28        /// - [`Ordering::Less`]: Size is too small.
29        /// - [`Ordering::Equal`]: Size is not exactly as `expected`.
30        /// - [`Ordering::Greater`]: Size is too long.
31        provided: Ordering,
32        /// Expected output size in relation to `provided`.
33        ///
34        /// - [`Ordering::Less`]: Minimum size.
35        /// - [`Ordering::Equal`]: Expecrted size.
36        /// - [`Ordering::Greater`]: Maximum size.
37        expected: usize,
38    },
39
40    /// Duplicate parameter name encountered.
41    ParamNameDuplicated,
42
43    /// Invalid parameter name.
44    ParamNameInvalid,
45
46    /// Invalid parameter value.
47    ParamValueInvalid(InvalidValue),
48
49    /// Maximum number of parameters exceeded.
50    ParamsMaxExceeded,
51
52    /// Invalid password.
53    Password,
54
55    /// Password hash string invalid.
56    PhcStringField,
57
58    /// Password hash string contains trailing data.
59    PhcStringTrailingData,
60
61    /// Salt invalid.
62    SaltInvalid(InvalidValue),
63
64    /// Invalid algorithm version.
65    Version,
66}
67
68impl fmt::Display for Error {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
70        match self {
71            Self::Algorithm => write!(f, "unsupported algorithm"),
72            Self::B64Encoding(err) => write!(f, "{}", err),
73            Self::Crypto => write!(f, "cryptographic error"),
74            Self::OutputSize { provided, expected } => match provided {
75                Ordering::Less => write!(
76                    f,
77                    "output size too short, expected at least {} bytes",
78                    expected
79                ),
80                Ordering::Equal => write!(f, "output size unexpected, expected {} bytes", expected),
81                Ordering::Greater => write!(
82                    f,
83                    "output size too long, expected at most {} bytes",
84                    expected
85                ),
86            },
87            Self::ParamNameDuplicated => f.write_str("duplicate parameter"),
88            Self::ParamNameInvalid => f.write_str("invalid parameter name"),
89            Self::ParamValueInvalid(val_err) => write!(f, "invalid parameter value: {}", val_err),
90            Self::ParamsMaxExceeded => f.write_str("maximum number of parameters reached"),
91            Self::Password => write!(f, "invalid password"),
92            Self::PhcStringField => write!(f, "password hash string missing field"),
93            Self::PhcStringTrailingData => {
94                write!(f, "password hash string contains trailing characters")
95            }
96            Self::SaltInvalid(val_err) => write!(f, "salt invalid: {}", val_err),
97            Self::Version => write!(f, "invalid algorithm version"),
98        }
99    }
100}
101
102#[cfg(feature = "std")]
103impl std::error::Error for Error {
104    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
105        match self {
106            Self::B64Encoding(err) => Some(err),
107            Self::ParamValueInvalid(err) => Some(err),
108            Self::SaltInvalid(err) => Some(err),
109            _ => None,
110        }
111    }
112}
113
114impl From<B64Error> for Error {
115    fn from(err: B64Error) -> Error {
116        Error::B64Encoding(err)
117    }
118}
119
120impl From<base64ct::InvalidLengthError> for Error {
121    fn from(_: base64ct::InvalidLengthError) -> Error {
122        Error::B64Encoding(B64Error::InvalidLength)
123    }
124}
125
126/// Parse errors relating to invalid parameter values or salts.
127#[derive(Copy, Clone, Debug, Eq, PartialEq)]
128#[non_exhaustive]
129pub enum InvalidValue {
130    /// Character is not in the allowed set.
131    InvalidChar(char),
132
133    /// Format is invalid.
134    InvalidFormat,
135
136    /// Value is malformed.
137    Malformed,
138
139    /// Value exceeds the maximum allowed length.
140    TooLong,
141
142    /// Value does not satisfy the minimum length.
143    TooShort,
144}
145
146impl InvalidValue {
147    /// Create an [`Error::ParamValueInvalid`] which warps this error.
148    pub fn param_error(self) -> Error {
149        Error::ParamValueInvalid(self)
150    }
151
152    /// Create an [`Error::SaltInvalid`] which wraps this error.
153    pub fn salt_error(self) -> Error {
154        Error::SaltInvalid(self)
155    }
156}
157
158impl fmt::Display for InvalidValue {
159    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
160        match self {
161            Self::InvalidChar(c) => write!(f, "contains invalid character: '{}'", c),
162            Self::InvalidFormat => f.write_str("value format is invalid"),
163            Self::Malformed => f.write_str("value malformed"),
164            Self::TooLong => f.write_str("value to long"),
165            Self::TooShort => f.write_str("value to short"),
166        }
167    }
168}
169
170#[cfg(feature = "std")]
171impl std::error::Error for InvalidValue {}