diff --git a/sha-crypt/Cargo.toml b/sha-crypt/Cargo.toml index 5f1fd019..527bc0f1 100644 --- a/sha-crypt/Cargo.toml +++ b/sha-crypt/Cargo.toml @@ -2,8 +2,9 @@ name = "sha-crypt" version = "0.6.0-rc.1" description = """ -Pure Rust implementation of the SHA-crypt password hash based on SHA-512 -as implemented by the POSIX crypt C library +Pure Rust implementation of the SHA-crypt password hashing algorithm based on SHA-256/SHA-512 +as implemented by the POSIX crypt C library, including support for generating and verifying password +hash strings in the Modular Crypt Format """ authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" diff --git a/sha-crypt/README.md b/sha-crypt/README.md index 19d8ea6e..f6440114 100644 --- a/sha-crypt/README.md +++ b/sha-crypt/README.md @@ -2,16 +2,16 @@ [![crate][crate-image]][crate-link] [![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] ![Apache2/MIT licensed][license-image] ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] -[![Build Status][build-image]][build-link] -Pure Rust implementation of the [SHA-crypt password hash based on SHA-512][1], +Pure Rust implementation of the [SHA-crypt password hash based on SHA-256/SHA-512][1], a legacy password hashing scheme supported by the [POSIX crypt C library][2]. -Password hashes using this algorithm start with `$6$` when encoded using the -[PHC string format][3]. +Password hashes using this algorithm start with `$5$` or `$6$` when encoded +using the [Modular Crypt Format][3]. ## License @@ -34,15 +34,15 @@ dual licensed as above, without any additional terms or conditions. [crate-link]: https://crates.io/crates/sha-crypt [docs-image]: https://docs.rs/sha-crypt/badge.svg [docs-link]: https://docs.rs/sha-crypt/ +[build-image]: https://github.com/RustCrypto/password-hashes/actions/workflows/sha-crypt.yml/badge.svg +[build-link]: https://github.com/RustCrypto/password-hashes/actions/workflows/sha-crypt.yml [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg [rustc-image]: https://img.shields.io/badge/rustc-1.81+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260046-password-hashes -[build-image]: https://github.com/RustCrypto/password-hashes/workflows/sha-crypt/badge.svg?branch=master&event=push -[build-link]: https://github.com/RustCrypto/password-hashes/actions?query=workflow%3Asha-crypt [//]: # (general links) [1]: https://www.akkadia.org/drepper/SHA-crypt.txt [2]: https://en.wikipedia.org/wiki/Crypt_(C) -[3]: https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md +[3]: https://passlib.readthedocs.io/en/stable/modular_crypt_format.html diff --git a/sha-crypt/src/algorithm.rs b/sha-crypt/src/algorithm.rs new file mode 100644 index 00000000..c2a5f6aa --- /dev/null +++ b/sha-crypt/src/algorithm.rs @@ -0,0 +1,81 @@ +use core::{fmt, str::FromStr}; +use password_hash::Error; + +/// SHA-crypt algorithm variants: SHA-256 or SHA-512. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +#[non_exhaustive] +pub enum Algorithm { + /// SHA-256-crypt: SHA-crypt instantiated with SHA-256. + Sha256Crypt, + + /// SHA-512-crypt: SHA-crypt instantiated with SHA-512. + Sha512Crypt, +} + +impl Default for Algorithm { + /// Recommended default algorithm: SHA-512. + fn default() -> Self { + Self::RECOMMENDED + } +} + +impl Algorithm { + /// SHA-256-crypt Modular Crypt Format algorithm identifier + pub const SHA256_CRYPT_IDENT: &str = "5"; + + /// SHA-512-crypt Modular Crypt Format algorithm identifier + pub const SHA512_CRYPT_IDENT: &str = "6"; + + /// Recommended default algorithm: SHA-512. + const RECOMMENDED: Self = Self::Sha512Crypt; + + /// Parse an [`Algorithm`] from the provided string. + pub fn new(id: impl AsRef) -> password_hash::Result { + id.as_ref().parse() + } + + /// Get the Modular Crypt Format algorithm identifier for this algorithm. + pub const fn ident(&self) -> &'static str { + match self { + Algorithm::Sha256Crypt => Self::SHA256_CRYPT_IDENT, + Algorithm::Sha512Crypt => Self::SHA512_CRYPT_IDENT, + } + } + + /// Get the identifier string for this PBKDF2 [`Algorithm`]. + pub fn as_str(&self) -> &'static str { + self.ident() + } +} + +impl AsRef for Algorithm { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl fmt::Display for Algorithm { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl FromStr for Algorithm { + type Err = Error; + + fn from_str(s: &str) -> password_hash::Result { + s.try_into() + } +} + +impl<'a> TryFrom<&'a str> for Algorithm { + type Error = Error; + + fn try_from(name: &'a str) -> password_hash::Result { + match name { + Self::SHA256_CRYPT_IDENT => Ok(Algorithm::Sha256Crypt), + Self::SHA512_CRYPT_IDENT => Ok(Algorithm::Sha512Crypt), + _ => Err(Error::Algorithm), + } + } +} diff --git a/sha-crypt/src/lib.rs b/sha-crypt/src/lib.rs index aef7a028..28d3748c 100644 --- a/sha-crypt/src/lib.rs +++ b/sha-crypt/src/lib.rs @@ -15,14 +15,15 @@ //! # fn main() -> password_hash::Result<()> { //! // NOTE: example requires `getrandom` feature is enabled //! -//! use sha_crypt::{SHA512_CRYPT, PasswordHasher, PasswordVerifier}; +//! use sha_crypt::{PasswordHasher, PasswordVerifier, ShaCrypt}; //! +//! let sha_crypt = ShaCrypt::default(); // default is SHA-512-crypt //! let password = b"pleaseletmein"; // don't actually use this as a password! -//! let password_hash = SHA512_CRYPT.hash_password(password)?; +//! let password_hash = sha_crypt.hash_password(password)?; //! assert!(password_hash.as_str().starts_with("$6$")); //! //! // verify password is correct for the given hash -//! SHA512_CRYPT.verify_password(password, &password_hash)?; +//! sha_crypt.verify_password(password, &password_hash)?; //! # Ok(()) //! # } //! ``` @@ -34,6 +35,8 @@ extern crate alloc; mod errors; mod params; +#[cfg(feature = "password-hash")] +mod algorithm; #[cfg(feature = "password-hash")] mod mcf; @@ -44,8 +47,9 @@ pub use crate::{ #[cfg(feature = "password-hash")] pub use { - crate::mcf::{ - PasswordHash, PasswordHashRef, SHA256_CRYPT, SHA512_CRYPT, ShaCrypt, ShaCryptCore, + crate::{ + algorithm::Algorithm, + mcf::{PasswordHash, PasswordHashRef, ShaCrypt}, }, password_hash::{self, CustomizedPasswordHasher, PasswordHasher, PasswordVerifier}, }; @@ -53,21 +57,19 @@ pub use { use alloc::vec::Vec; use sha2::{Digest, Sha256, Sha512}; -/// Block size for SHA256 +/// Block size for SHA-256-crypt. pub const BLOCK_SIZE_SHA256: usize = 32; -/// Block size for SHA512 +/// Block size for SHA-512-crypt. pub const BLOCK_SIZE_SHA512: usize = 64; -/// The SHA-256 crypt function returned as byte vector -/// -/// If the provided hash is longer than defs::SALT_MAX_LEN character, it will -/// be stripped down to defs::SALT_MAX_LEN characters. +/// The SHA-256-crypt function which outputs a uniformly random byte array. /// /// # Arguments /// - `password`: the password to process as a byte vector /// - `salt`: the salt value to use as a byte vector /// - `params`: the parameters to use +/// /// **WARNING: Make sure to compare this value in constant time!** pub fn sha256_crypt(password: &[u8], salt: &[u8], params: &Params) -> [u8; BLOCK_SIZE_SHA256] { let pw_len = password.len(); @@ -79,7 +81,7 @@ pub fn sha256_crypt(password: &[u8], salt: &[u8], params: &Params) -> [u8; BLOCK }; let salt_len = salt.len(); - let digest_a = sha256crypt_intermediate(password, salt); + let digest_a = sha256_crypt_intermediate(password, salt); // 13. let mut hasher_alt = Sha256::default(); @@ -150,15 +152,13 @@ pub fn sha256_crypt(password: &[u8], salt: &[u8], params: &Params) -> [u8; BLOCK digest_c } -/// The SHA-512 crypt function returned as byte vector -/// -/// If the provided hash is longer than defs::SALT_MAX_LEN character, it will -/// be stripped down to defs::SALT_MAX_LEN characters. +/// The SHA-512-crypt function which outputs a uniformly random byte array. /// /// # Arguments /// - `password`The password to process as a byte vector /// - `salt` - The salt value to use as a byte vector /// - `params` - The parameters to use +/// /// **WARNING: Make sure to compare this value in constant time!** pub fn sha512_crypt(password: &[u8], salt: &[u8], params: &Params) -> [u8; BLOCK_SIZE_SHA512] { let pw_len = password.len(); @@ -170,7 +170,7 @@ pub fn sha512_crypt(password: &[u8], salt: &[u8], params: &Params) -> [u8; BLOCK }; let salt_len = salt.len(); - let digest_a = sha512crypt_intermediate(password, salt); + let digest_a = sha512_crypt_intermediate(password, salt); // 13. let mut hasher_alt = Sha512::default(); @@ -241,7 +241,7 @@ pub fn sha512_crypt(password: &[u8], salt: &[u8], params: &Params) -> [u8; BLOCK digest_c } -fn sha256crypt_intermediate(password: &[u8], salt: &[u8]) -> [u8; BLOCK_SIZE_SHA256] { +fn sha256_crypt_intermediate(password: &[u8], salt: &[u8]) -> [u8; BLOCK_SIZE_SHA256] { let pw_len = password.len(); let mut hasher = Sha256::default(); @@ -284,7 +284,7 @@ fn sha256crypt_intermediate(password: &[u8], salt: &[u8]) -> [u8; BLOCK_SIZE_SHA hasher.finalize().as_slice().try_into().unwrap() } -fn sha512crypt_intermediate(password: &[u8], salt: &[u8]) -> [u8; BLOCK_SIZE_SHA512] { +fn sha512_crypt_intermediate(password: &[u8], salt: &[u8]) -> [u8; BLOCK_SIZE_SHA512] { let pw_len = password.len(); let mut hasher = Sha512::default(); diff --git a/sha-crypt/src/mcf.rs b/sha-crypt/src/mcf.rs index 5742de78..7263968f 100644 --- a/sha-crypt/src/mcf.rs +++ b/sha-crypt/src/mcf.rs @@ -2,47 +2,24 @@ pub use mcf::{PasswordHash, PasswordHashRef}; -use crate::{BLOCK_SIZE_SHA256, BLOCK_SIZE_SHA512, Params, sha256_crypt, sha512_crypt}; +use crate::{BLOCK_SIZE_SHA256, BLOCK_SIZE_SHA512, Params, algorithm::Algorithm}; use base64ct::{Base64ShaCrypt, Encoding}; -use core::{marker::PhantomData, str::FromStr}; +use core::str::FromStr; use mcf::Base64; use password_hash::{ CustomizedPasswordHasher, Error, PasswordHasher, PasswordVerifier, Result, Version, }; -use sha2::{Sha256, Sha512}; - -/// SHA-crypt uses digest-specific parameters. -pub trait ShaCryptCore { - /// Modular Crypt Format ID. - const MCF_ID: &'static str; - - /// Output data - type Output: AsRef<[u8]>; - - /// Core function - fn sha_crypt_core(password: &[u8], salt: &[u8], params: &Params) -> Self::Output; +use subtle::ConstantTimeEq; + +/// SHA-crypt type for use with the [`PasswordHasher`] and [`PasswordVerifier`] traits, which can +/// produce and verify password hashes in [`Modular Crypt Format`][`mcf`]. +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +pub struct ShaCrypt { + /// Default algorithm to use when generating password hashes. + algorithm: Algorithm, } -/// sha-crypt type for use with [`PasswordHasher`]. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct ShaCrypt { - phantom: PhantomData, -} - -/// SHA-crypt initialized using SHA-256 -pub const SHA256_CRYPT: ShaCrypt = ShaCrypt { - phantom: PhantomData, -}; - -/// SHA-crypt initialized using SHA-512 -pub const SHA512_CRYPT: ShaCrypt = ShaCrypt { - phantom: PhantomData, -}; - -impl CustomizedPasswordHasher for ShaCrypt -where - Self: ShaCryptCore, -{ +impl CustomizedPasswordHasher for ShaCrypt { type Params = Params; fn hash_password_customized( @@ -53,9 +30,10 @@ where version: Option, params: Params, ) -> Result { - if alg_id.is_some() && alg_id != Some(Self::MCF_ID) { - return Err(Error::Algorithm); - } + let alg = alg_id + .map(|id| id.parse::()) + .transpose()? + .unwrap_or(self.algorithm); if version.is_some() { return Err(Error::Version); @@ -63,9 +41,7 @@ where // We compute the function over the Base64-encoded salt let salt = Base64ShaCrypt::encode_string(salt); - let out = Self::sha_crypt_core(password, salt.as_bytes(), ¶ms); - - let mut mcf_hash = PasswordHash::from_id(Self::MCF_ID).expect("should have valid ID"); + let mut mcf_hash = PasswordHash::from_id(alg.ident()).expect("should have valid ID"); mcf_hash .push_displayable(¶ms) @@ -75,39 +51,36 @@ where .push_str(&salt) .map_err(|_| Error::EncodingInvalid)?; - mcf_hash.push_base64(out.as_ref(), Base64::Crypt); + match alg { + Algorithm::Sha256Crypt => { + let out = sha256_crypt_core(password, salt.as_bytes(), ¶ms); + mcf_hash.push_base64(&out, Base64::Crypt); + } + Algorithm::Sha512Crypt => { + let out = sha512_crypt_core(password, salt.as_bytes(), ¶ms); + mcf_hash.push_base64(&out, Base64::Crypt); + } + } Ok(mcf_hash) } } -impl PasswordHasher for ShaCrypt -where - Self: ShaCryptCore, -{ +impl PasswordHasher for ShaCrypt { fn hash_password_with_salt(&self, password: &[u8], salt: &[u8]) -> Result { self.hash_password_customized(password, salt, None, None, Params::default()) } } -impl PasswordVerifier for ShaCrypt -where - Self: ShaCryptCore, -{ +impl PasswordVerifier for ShaCrypt { fn verify_password(&self, password: &[u8], hash: &PasswordHash) -> Result<()> { self.verify_password(password, hash.as_password_hash_ref()) } } -impl PasswordVerifier for ShaCrypt -where - Self: ShaCryptCore, -{ +impl PasswordVerifier for ShaCrypt { fn verify_password(&self, password: &[u8], hash: &PasswordHashRef) -> Result<()> { - if hash.id() != Self::MCF_ID { - return Err(Error::Algorithm); - } - + let alg = hash.id().parse::()?; let mut fields = hash.fields(); let mut next = fields.next().ok_or(Error::EncodingInvalid)?; @@ -134,9 +107,16 @@ where return Err(Error::EncodingInvalid); } - let actual = Self::sha_crypt_core(password, salt, ¶ms); + let is_valid = match alg { + Algorithm::Sha256Crypt => sha256_crypt_core(password, salt, ¶ms) + .as_ref() + .ct_eq(&expected), + Algorithm::Sha512Crypt => sha512_crypt_core(password, salt, ¶ms) + .as_ref() + .ct_eq(&expected), + }; - if subtle::ConstantTimeEq::ct_ne(actual.as_ref(), &expected).into() { + if (!is_valid).into() { return Err(Error::PasswordInvalid); } @@ -144,10 +124,7 @@ where } } -impl PasswordVerifier for ShaCrypt -where - Self: ShaCryptCore, -{ +impl PasswordVerifier for ShaCrypt { fn verify_password(&self, password: &[u8], hash: &str) -> password_hash::Result<()> { // TODO(tarcieri): better mapping from `mcf::Error` and `password_hash::Error`? let hash = PasswordHashRef::new(hash).map_err(|_| Error::EncodingInvalid)?; @@ -155,45 +132,41 @@ where } } -impl ShaCryptCore for ShaCrypt { - const MCF_ID: &'static str = "5"; - type Output = [u8; BLOCK_SIZE_SHA256]; - - /// Core function - fn sha_crypt_core(password: &[u8], salt: &[u8], params: &Params) -> Self::Output { - let output = sha256_crypt(password, salt, params); - let transposition_table = [ - 20, 10, 0, 11, 1, 21, 2, 22, 12, 23, 13, 3, 14, 4, 24, 5, 25, 15, 26, 16, 6, 17, 7, 27, - 8, 28, 18, 29, 19, 9, 30, 31, - ]; - - let mut transposed = [0u8; BLOCK_SIZE_SHA256]; - for (i, &ti) in transposition_table.iter().enumerate() { - transposed[i] = output[ti as usize]; - } - - transposed +impl From for ShaCrypt { + fn from(algorithm: Algorithm) -> Self { + Self { algorithm } } } -impl ShaCryptCore for ShaCrypt { - const MCF_ID: &'static str = "6"; - type Output = [u8; BLOCK_SIZE_SHA512]; - - /// Core function - fn sha_crypt_core(password: &[u8], salt: &[u8], params: &Params) -> Self::Output { - let output = sha512_crypt(password, salt, params); - let transposition_table = [ - 42, 21, 0, 1, 43, 22, 23, 2, 44, 45, 24, 3, 4, 46, 25, 26, 5, 47, 48, 27, 6, 7, 49, 28, - 29, 8, 50, 51, 30, 9, 10, 52, 31, 32, 11, 53, 54, 33, 12, 13, 55, 34, 35, 14, 56, 57, - 36, 15, 16, 58, 37, 38, 17, 59, 60, 39, 18, 19, 61, 40, 41, 20, 62, 63, - ]; - - let mut transposed = [0u8; BLOCK_SIZE_SHA512]; - for (i, &ti) in transposition_table.iter().enumerate() { - transposed[i] = output[ti as usize]; - } +/// SHA-256-crypt core function: uses an algorithm-specific transposition table. +fn sha256_crypt_core(password: &[u8], salt: &[u8], params: &Params) -> [u8; BLOCK_SIZE_SHA256] { + let output = super::sha256_crypt(password, salt, params); + let transposition_table = [ + 20, 10, 0, 11, 1, 21, 2, 22, 12, 23, 13, 3, 14, 4, 24, 5, 25, 15, 26, 16, 6, 17, 7, 27, 8, + 28, 18, 29, 19, 9, 30, 31, + ]; + + let mut transposed = [0u8; BLOCK_SIZE_SHA256]; + for (i, &ti) in transposition_table.iter().enumerate() { + transposed[i] = output[ti as usize]; + } - transposed + transposed +} + +/// SHA-512-crypt core function: uses an algorithm-specific transposition table. +fn sha512_crypt_core(password: &[u8], salt: &[u8], params: &Params) -> [u8; BLOCK_SIZE_SHA512] { + let output = super::sha512_crypt(password, salt, params); + let transposition_table = [ + 42, 21, 0, 1, 43, 22, 23, 2, 44, 45, 24, 3, 4, 46, 25, 26, 5, 47, 48, 27, 6, 7, 49, 28, 29, + 8, 50, 51, 30, 9, 10, 52, 31, 32, 11, 53, 54, 33, 12, 13, 55, 34, 35, 14, 56, 57, 36, 15, + 16, 58, 37, 38, 17, 59, 60, 39, 18, 19, 61, 40, 41, 20, 62, 63, + ]; + + let mut transposed = [0u8; BLOCK_SIZE_SHA512]; + for (i, &ti) in transposition_table.iter().enumerate() { + transposed[i] = output[ti as usize]; } + + transposed } diff --git a/sha-crypt/tests/mcf.rs b/sha-crypt/tests/mcf.rs index ef6a89ed..30524609 100644 --- a/sha-crypt/tests/mcf.rs +++ b/sha-crypt/tests/mcf.rs @@ -3,7 +3,7 @@ use base64ct::{Base64ShaCrypt, Encoding}; use mcf::PasswordHash; use sha_crypt::{ - Params, SHA256_CRYPT, SHA512_CRYPT, + Algorithm, Params, ShaCrypt, password_hash::{CustomizedPasswordHasher, Error, PasswordVerifier}, }; @@ -89,12 +89,13 @@ const TEST_VECTORS: &[TestVector] = &[ #[test] fn hash_sha256_crypt() { + let sha_crypt = ShaCrypt::from(Algorithm::Sha256Crypt); let mut any = false; for t in TEST_VECTORS { if let Ok(salt) = Base64ShaCrypt::decode_vec(&t.salt) { let params = Params::new(t.rounds).unwrap(); - let result = SHA256_CRYPT + let result = sha_crypt .hash_password_with_params(t.input.as_bytes(), &salt, params) .unwrap(); @@ -108,12 +109,13 @@ fn hash_sha256_crypt() { #[test] fn hash_sha512_crypt() { + let sha_crypt = ShaCrypt::default(); // default should be SHA-512 let mut any = false; for t in TEST_VECTORS { if let Ok(salt) = Base64ShaCrypt::decode_vec(&t.salt) { let params = Params::new(t.rounds).unwrap(); - let result = SHA512_CRYPT + let result = sha_crypt .hash_password_with_params(t.input.as_bytes(), &salt, params) .unwrap(); @@ -127,20 +129,19 @@ fn hash_sha512_crypt() { #[test] fn verify_sha256_crypt() { + let sha_crypt = ShaCrypt::from(Algorithm::Sha256Crypt); + for t in TEST_VECTORS { let mut hash = PasswordHash::from_id("6").unwrap(); hash.push_str(&format!("rounds={}", t.rounds)).unwrap(); hash.push_str(t.salt).unwrap(); hash.push_str(t.result_sha512).unwrap(); - assert_eq!( - SHA512_CRYPT.verify_password(t.input.as_bytes(), &hash), - Ok(()) - ); + assert_eq!(sha_crypt.verify_password(t.input.as_bytes(), &hash), Ok(())); } assert_eq!( - SHA256_CRYPT.verify_password( + sha_crypt.verify_password( b"foobar", &PasswordHash::new("$5$9aEeVXnCiCNHUjO/$FrVBcjyJukRaE6inMYazyQv1DBnwaKfom.71ebgQR/0") .unwrap() @@ -149,7 +150,7 @@ fn verify_sha256_crypt() { ); assert_eq!( - SHA256_CRYPT.verify_password( + sha_crypt.verify_password( b"foobar", &PasswordHash::new( "$5$rounds=100000$PhW/wpSsmgIMKsTW$d9kDD8dQNu3r0Ky.xcOEhdin6EQRebrHfNKDRwWP/pB" @@ -162,20 +163,19 @@ fn verify_sha256_crypt() { #[test] fn verify_sha512_crypt() { + let sha_crypt = ShaCrypt::default(); // default should be SHA-512 + for t in TEST_VECTORS { let mut hash = PasswordHash::from_id("6").unwrap(); hash.push_str(&format!("rounds={}", t.rounds)).unwrap(); hash.push_str(t.salt).unwrap(); hash.push_str(t.result_sha512).unwrap(); - assert_eq!( - SHA512_CRYPT.verify_password(t.input.as_bytes(), &hash), - Ok(()) - ); + assert_eq!(sha_crypt.verify_password(t.input.as_bytes(), &hash), Ok(())); } assert_eq!( - SHA512_CRYPT.verify_password( + sha_crypt.verify_password( b"foobar", &PasswordHash::new( "$6$bbe605c2cce4c642$BiBOywFAm9kdv6ZPpj2GaKVqeh/.c21pf1uFBaq.e59KEE2Ej74iJleXaLXURYV6uh5LF4K7dDc4vtRtPiiKB/" @@ -185,7 +185,7 @@ fn verify_sha512_crypt() { ); assert_eq!( - SHA512_CRYPT.verify_password( + sha_crypt.verify_password( b"foobar", &PasswordHash::new( "$6$rounds=100000$exn6tVc2j/MZD8uG$BI1Xh8qQSK9J4m14uwy7abn.ctj/TIAzlaVCto0MQrOFIeTXsc1iwzH16XEWo/a7c7Y9eVJvufVzYAs4EsPOy0" @@ -197,22 +197,12 @@ fn verify_sha512_crypt() { #[cfg(feature = "password-hash")] #[test] -fn test_sha256_wrong_id() { - let passwd = b"foobar"; - - // wrong id '7' - let hash = PasswordHash::new("$7$rounds=100000$exn6tVc2j/MZD8uG$BI1Xh8qQSK9J4m14uwy7abn.ctj/TIAzlaVCto0MQrOFIeTXsc1iwzH16XEWo/a7c7Y9eVJvufVzYAs4EsPOy0").unwrap(); - let res = SHA256_CRYPT.verify_password(passwd, &hash); - assert_eq!(res, Err(Error::Algorithm)); -} - -#[cfg(feature = "password-hash")] -#[test] -fn test_sha512_wrong_id() { +fn test_wrong_id() { + let sha_crypt = ShaCrypt::default(); let passwd = b"foobar"; // wrong id '7' let hash = PasswordHash::new("$7$rounds=100000$exn6tVc2j/MZD8uG$BI1Xh8qQSK9J4m14uwy7abn.ctj/TIAzlaVCto0MQrOFIeTXsc1iwzH16XEWo/a7c7Y9eVJvufVzYAs4EsPOy0").unwrap(); - let res = SHA512_CRYPT.verify_password(passwd, &hash); + let res = sha_crypt.verify_password(passwd, &hash); assert_eq!(res, Err(Error::Algorithm)); } diff --git a/yescrypt/README.md b/yescrypt/README.md index e0151d46..61fb571e 100644 --- a/yescrypt/README.md +++ b/yescrypt/README.md @@ -54,12 +54,12 @@ dual licensed as above, without any additional terms or conditions. [crate-link]: https://crates.io/crates/yescrypt [docs-image]: https://docs.rs/yescrypt/badge.svg [docs-link]: https://docs.rs/yescrypt/ +[build-image]: https://github.com/RustCrypto/password-hashes/actions/workflows/yescrypt.yml/badge.svg +[build-link]: https://github.com/RustCrypto/password-hashes/actions/workflows/yescrypt.yml [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260046-password-hashes -[build-image]: https://github.com/RustCrypto/password-hashes/actions/workflows/yescrypt.yml/badge.svg -[build-link]: https://github.com/RustCrypto/password-hashes/actions/workflows/yescrypt.yml [//]: # (links)