diff --git a/password-hash/src/encoding.rs b/password-hash/src/encoding.rs deleted file mode 100644 index 41473092b..000000000 --- a/password-hash/src/encoding.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Base64 encoding variants. - -use base64ct::{ - Base64Bcrypt, Base64Crypt, Base64ShaCrypt, Base64Unpadded as B64, Encoding as _, - Error as B64Error, -}; - -/// Base64 encoding variants. -#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, PartialOrd, Ord)] -#[non_exhaustive] -pub enum Encoding { - /// "B64" encoding: standard Base64 without padding. - /// - /// ```text - /// [A-Z] [a-z] [0-9] + / - /// 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f - /// ``` - /// - #[default] - B64, - - /// bcrypt encoding. - /// - /// ```text - /// ./ [A-Z] [a-z] [0-9] - /// 0x2e-0x2f, 0x41-0x5a, 0x61-0x7a, 0x30-0x39 - /// ``` - Bcrypt, - - /// `crypt(3)` encoding. - /// - /// ```text - /// [.-9] [A-Z] [a-z] - /// 0x2e-0x39, 0x41-0x5a, 0x61-0x7a - /// ``` - Crypt, - - /// `crypt(3)` Base64 encoding for the following schemes. - /// - sha1_crypt, - /// - sha256_crypt, - /// - sha512_crypt, - /// - md5_crypt - /// - /// ```text - /// [.-9] [A-Z] [a-z] - /// 0x2e-0x39, 0x41-0x5a, 0x61-0x7a - /// ``` - ShaCrypt, -} - -impl Encoding { - /// Decode a Base64 string into the provided destination buffer. - pub fn decode(self, src: impl AsRef<[u8]>, dst: &mut [u8]) -> Result<&[u8], B64Error> { - match self { - Self::B64 => B64::decode(src, dst), - Self::Bcrypt => Base64Bcrypt::decode(src, dst), - Self::Crypt => Base64Crypt::decode(src, dst), - Self::ShaCrypt => Base64ShaCrypt::decode(src, dst), - } - } - - /// Encode the input byte slice as Base64. - /// - /// Writes the result into the provided destination slice, returning an - /// ASCII-encoded Base64 string value. - pub fn encode<'a>(self, src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, B64Error> { - match self { - Self::B64 => B64::encode(src, dst), - Self::Bcrypt => Base64Bcrypt::encode(src, dst), - Self::Crypt => Base64Crypt::encode(src, dst), - Self::ShaCrypt => Base64ShaCrypt::encode(src, dst), - } - .map_err(Into::into) - } - - /// Get the length of Base64 produced by encoding the given bytes. - pub fn encoded_len(self, bytes: &[u8]) -> usize { - match self { - Self::B64 => B64::encoded_len(bytes), - Self::Bcrypt => Base64Bcrypt::encoded_len(bytes), - Self::Crypt => Base64Crypt::encoded_len(bytes), - Self::ShaCrypt => Base64ShaCrypt::encoded_len(bytes), - } - } -} diff --git a/password-hash/src/lib.rs b/password-hash/src/lib.rs index 31a62a0de..50dc85020 100644 --- a/password-hash/src/lib.rs +++ b/password-hash/src/lib.rs @@ -33,7 +33,6 @@ pub use rand_core; pub mod errors; -mod encoding; mod ident; mod output; mod params; @@ -42,7 +41,6 @@ mod traits; mod value; pub use crate::{ - encoding::Encoding, errors::{Error, Result}, ident::Ident, output::Output, @@ -128,11 +126,6 @@ pub struct PasswordHash<'a> { impl<'a> PasswordHash<'a> { /// Parse a password hash from a string in the PHC string format. pub fn new(s: &'a str) -> Result { - Self::parse(s, Encoding::default()) - } - - /// Parse a password hash from the given [`Encoding`]. - pub fn parse(s: &'a str, encoding: Encoding) -> Result { if s.is_empty() { return Err(Error::PhcStringField); } @@ -185,7 +178,7 @@ impl<'a> PasswordHash<'a> { } if let Some(field) = fields.next() { - hash = Some(Output::decode(field, encoding)?); + hash = Some(Output::decode(field)?); } if fields.next().is_some() { @@ -226,11 +219,6 @@ impl<'a> PasswordHash<'a> { Err(Error::Password) } - /// Get the [`Encoding`] that this [`PasswordHash`] is serialized with. - pub fn encoding(&self) -> Encoding { - self.hash.map(|h| h.encoding()).unwrap_or_default() - } - /// Serialize this [`PasswordHash`] as a [`PasswordHashString`]. #[cfg(feature = "alloc")] pub fn serialize(&self) -> PasswordHashString { @@ -282,9 +270,6 @@ impl fmt::Display for PasswordHash<'_> { pub struct PasswordHashString { /// String value string: String, - - /// String encoding - encoding: Encoding, } #[cfg(feature = "alloc")] @@ -292,22 +277,12 @@ pub struct PasswordHashString { impl PasswordHashString { /// Parse a password hash from a string in the PHC string format. pub fn new(s: &str) -> Result { - Self::parse(s, Encoding::default()) - } - - /// Parse a password hash from the given [`Encoding`]. - pub fn parse(s: &str, encoding: Encoding) -> Result { - Ok(PasswordHash::parse(s, encoding)?.into()) + PasswordHash::new(s).map(Into::into) } /// Parse this owned string as a [`PasswordHash`]. pub fn password_hash(&self) -> PasswordHash<'_> { - PasswordHash::parse(&self.string, self.encoding).expect("malformed password hash") - } - - /// Get the [`Encoding`] that this [`PasswordHashString`] is serialized with. - pub fn encoding(&self) -> Encoding { - self.encoding + PasswordHash::new(&self.string).expect("malformed password hash") } /// Borrow this value as a `str`. @@ -370,7 +345,6 @@ impl From<&PasswordHash<'_>> for PasswordHashString { fn from(hash: &PasswordHash<'_>) -> PasswordHashString { PasswordHashString { string: hash.to_string(), - encoding: hash.encoding(), } } } diff --git a/password-hash/src/output.rs b/password-hash/src/output.rs index 48592315c..63fba7e2e 100644 --- a/password-hash/src/output.rs +++ b/password-hash/src/output.rs @@ -1,6 +1,7 @@ //! Outputs from password hashing functions. -use crate::{Encoding, Error, Result}; +use crate::{Error, Result}; +use base64ct::{Base64Unpadded as B64, Encoding}; use core::{cmp::Ordering, fmt, str::FromStr}; use subtle::{Choice, ConstantTimeEq}; @@ -102,9 +103,6 @@ pub struct Output { /// Length of the password hashing function output in bytes. length: u8, - - /// Encoding which output should be serialized with. - encoding: Encoding, } #[allow(clippy::len_without_is_empty)] @@ -130,15 +128,6 @@ impl Output { }) } - /// Create a [`Output`] from the given byte slice and [`Encoding`], - /// validating it according to [`Output::MIN_LENGTH`] and - /// [`Output::MAX_LENGTH`] restrictions. - pub fn new_with_encoding(input: &[u8], encoding: Encoding) -> Result { - let mut result = Self::new(input)?; - result.encoding = encoding; - Ok(result) - } - /// Initialize an [`Output`] using the provided method, which is given /// a mutable byte slice into which it should write the output. /// @@ -169,7 +158,6 @@ impl Output { Ok(Self { bytes, length: output_size as u8, - encoding: Encoding::default(), }) } @@ -178,52 +166,53 @@ impl Output { &self.bytes[..self.len()] } - /// Get the [`Encoding`] that this [`Output`] is serialized with. - pub fn encoding(&self) -> Encoding { - self.encoding - } - - /// Creates a copy of this [`Output`] with the specified [`Encoding`]. - pub fn with_encoding(&self, encoding: Encoding) -> Self { - Self { encoding, ..*self } - } - /// Get the length of the output value as a byte slice. pub fn len(&self) -> usize { usize::from(self.length) } - /// Parse B64-encoded [`Output`], i.e. using the PHC string - /// specification's restricted interpretation of Base64. - pub fn b64_decode(input: &str) -> Result { - Self::decode(input, Encoding::B64) + /// Parse "B64"-encoded [`Output`], i.e. using the PHC string specification's restricted + /// interpretation of Base64. + pub fn decode(input: &str) -> Result { + let mut bytes = [0u8; Self::MAX_LENGTH]; + B64::decode(input, &mut bytes) + .map_err(Into::into) + .and_then(Self::new) } - /// Write B64-encoded [`Output`] to the provided buffer, returning - /// a sub-slice containing the encoded data. + /// Write "B64"-encoded [`Output`] to the provided buffer, returning a sub-slice containing the + /// encoded data. /// /// Returns an error if the buffer is too short to contain the output. - pub fn b64_encode<'a>(&self, out: &'a mut [u8]) -> Result<&'a str> { - self.encode(out, Encoding::B64) + pub fn encode<'a>(&self, out: &'a mut [u8]) -> Result<&'a str> { + Ok(B64::encode(self.as_ref(), out)?) } - /// Decode the given input string using the specified [`Encoding`]. - pub fn decode(input: &str, encoding: Encoding) -> Result { - let mut bytes = [0u8; Self::MAX_LENGTH]; - encoding - .decode(input, &mut bytes) - .map_err(Into::into) - .and_then(|decoded| Self::new_with_encoding(decoded, encoding)) + /// Get the length of this [`Output`] when encoded as "B64". + pub fn encoded_len(&self) -> usize { + B64::encoded_len(self.as_ref()) } - /// Encode this [`Output`] using the specified [`Encoding`]. - pub fn encode<'a>(&self, out: &'a mut [u8], encoding: Encoding) -> Result<&'a str> { - Ok(encoding.encode(self.as_ref(), out)?) + /// DEPRECATED: parse B64-encoded [`Output`], i.e. using the PHC string specification's + /// restricted interpretation of Base64. + #[deprecated(since = "0.6.0", note = "Use `Output::decode` instead")] + pub fn b64_decode(input: &str) -> Result { + Self::decode(input) + } + + /// DEPRECATED: write B64-encoded [`Output`] to the provided buffer, returning a sub-slice + /// containing the encoded data. + /// + /// Returns an error if the buffer is too short to contain the output. + #[deprecated(since = "0.6.0", note = "Use `Output::encode` instead")] + pub fn b64_encode<'a>(&self, out: &'a mut [u8]) -> Result<&'a str> { + self.encode(out) } /// Get the length of this [`Output`] when encoded as B64. + #[deprecated(since = "0.6.0", note = "Use `Output::encoded_len` instead")] pub fn b64_len(&self) -> usize { - Encoding::B64.encoded_len(self.as_ref()) + self.encoded_len() } } @@ -243,7 +232,7 @@ impl FromStr for Output { type Err = Error; fn from_str(s: &str) -> Result { - Self::b64_decode(s) + Self::decode(s) } } @@ -264,7 +253,7 @@ impl TryFrom<&[u8]> for Output { impl fmt::Display for Output { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut buffer = [0u8; Self::B64_MAX_LENGTH]; - self.encode(&mut buffer, self.encoding) + self.encode(&mut buffer) .map_err(|_| fmt::Error) .and_then(|encoded| f.write_str(encoded)) } diff --git a/password-hash/src/params.rs b/password-hash/src/params.rs index 7fdb3baed..70b3ca2c3 100644 --- a/password-hash/src/params.rs +++ b/password-hash/src/params.rs @@ -1,10 +1,11 @@ //! Algorithm parameters. -use crate::errors::InvalidValue; use crate::{ - Encoding, Error, Ident, Result, + Error, Ident, Result, + errors::InvalidValue, value::{Decimal, Value}, }; +use base64ct::{Base64Unpadded as B64, Encoding}; use core::{ fmt::{self, Debug, Write}, str::{self, FromStr}, @@ -67,9 +68,7 @@ impl ParamsString { // Encode B64 value let offset = self.0.length as usize; - let written = Encoding::B64 - .encode(bytes, &mut self.0.bytes[offset..])? - .len(); + let written = B64::encode(bytes, &mut self.0.bytes[offset..])?.len(); self.0.length += written as u8; Ok(()) diff --git a/password-hash/src/salt.rs b/password-hash/src/salt.rs index b789181bf..7896a5716 100644 --- a/password-hash/src/salt.rs +++ b/password-hash/src/salt.rs @@ -1,9 +1,9 @@ //! Salt string support. -use crate::{Encoding, Error, Result, Value}; +use crate::{Error, Result, Value, errors::InvalidValue}; +use base64ct::{Base64Unpadded as B64, Encoding}; use core::{fmt, str}; -use crate::errors::InvalidValue; #[cfg(feature = "rand_core")] use rand_core::{CryptoRng, TryCryptoRng}; @@ -239,7 +239,7 @@ impl SaltString { /// Returns `Error` if the slice is too long. pub fn encode_b64(input: &[u8]) -> Result { let mut bytes = [0u8; Salt::MAX_LENGTH]; - let length = Encoding::B64.encode(input, &mut bytes)?.len() as u8; + let length = B64::encode(input, &mut bytes)?.len() as u8; Ok(Self { chars: bytes, length, diff --git a/password-hash/src/value.rs b/password-hash/src/value.rs index f60a75590..46a3365a6 100644 --- a/password-hash/src/value.rs +++ b/password-hash/src/value.rs @@ -13,8 +13,8 @@ //! //! [1]: https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md -use crate::errors::InvalidValue; -use crate::{Encoding, Error, Result}; +use crate::{Error, Result, errors::InvalidValue}; +use base64ct::{Base64Unpadded as B64, Encoding}; use core::{fmt, str}; /// Type used to represent decimal (i.e. integer) values. @@ -69,7 +69,7 @@ impl<'a> Value<'a> { /// /// [1]: https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md#argon2-encoding pub fn b64_decode<'b>(&self, buf: &'b mut [u8]) -> Result<&'b [u8]> { - Ok(Encoding::B64.decode(self.as_str(), buf)?) + Ok(B64::decode(self.as_str(), buf)?) } /// Borrow this value as a `str`.