From ccbf11ea108164fe8016bc04b32e6198c9f883cf Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 17 May 2024 10:21:18 +0200 Subject: [PATCH] sha-crypt: Make hashing infallible The rounds were already checked to be sane in `Sha{256,512}Parameters::new`. Fixes #499. --- sha-crypt/src/lib.rs | 70 ++++++++++++++++-------------------------- sha-crypt/tests/lib.rs | 12 +++----- 2 files changed, 30 insertions(+), 52 deletions(-) diff --git a/sha-crypt/src/lib.rs b/sha-crypt/src/lib.rs index 8ec3d83c..266c3d5e 100644 --- a/sha-crypt/src/lib.rs +++ b/sha-crypt/src/lib.rs @@ -96,7 +96,7 @@ pub fn sha512_crypt( password: &[u8], salt: &[u8], params: &Sha512Params, -) -> Result<[u8; BLOCK_SIZE_SHA512], CryptError> { +) -> [u8; BLOCK_SIZE_SHA512] { let pw_len = password.len(); let salt_len = salt.len(); @@ -106,10 +106,6 @@ pub fn sha512_crypt( }; let salt_len = salt.len(); - if params.rounds < ROUNDS_MIN || params.rounds > ROUNDS_MAX { - return Err(CryptError::RoundsError); - } - let digest_a = sha512crypt_intermediate(password, salt); // 13. @@ -178,7 +174,7 @@ pub fn sha512_crypt( digest_c.clone_from_slice(&hasher.finalize()); } - Ok(digest_c) + digest_c } /// The SHA256 crypt function returned as byte vector @@ -199,7 +195,7 @@ pub fn sha256_crypt( password: &[u8], salt: &[u8], params: &Sha256Params, -) -> Result<[u8; BLOCK_SIZE_SHA256], CryptError> { +) -> [u8; BLOCK_SIZE_SHA256] { let pw_len = password.len(); let salt_len = salt.len(); @@ -209,10 +205,6 @@ pub fn sha256_crypt( }; let salt_len = salt.len(); - if params.rounds < ROUNDS_MIN || params.rounds > ROUNDS_MAX { - return Err(CryptError::RoundsError); - } - let digest_a = sha256crypt_intermediate(password, salt); // 13. @@ -281,7 +273,7 @@ pub fn sha256_crypt( digest_c.clone_from_slice(&hasher.finalize()); } - Ok(digest_c) + digest_c } /// Same as sha512_crypt except base64 representation will be returned. @@ -295,14 +287,9 @@ pub fn sha256_crypt( /// # Returns /// - `Ok(())` if calculation was successful /// - `Err(errors::CryptError)` otherwise -pub fn sha512_crypt_b64( - password: &[u8], - salt: &[u8], - params: &Sha512Params, -) -> Result { - let output = sha512_crypt(password, salt, params)?; - let r = String::from_utf8(b64::encode_sha512(&output).to_vec())?; - Ok(r) +pub fn sha512_crypt_b64(password: &[u8], salt: &[u8], params: &Sha512Params) -> String { + let output = sha512_crypt(password, salt, params); + String::from_utf8(b64::encode_sha512(&output).to_vec()).unwrap() } /// Same as sha256_crypt except base64 representation will be returned. @@ -316,14 +303,9 @@ pub fn sha512_crypt_b64( /// # Returns /// - `Ok(())` if calculation was successful /// - `Err(errors::CryptError)` otherwise -pub fn sha256_crypt_b64( - password: &[u8], - salt: &[u8], - params: &Sha256Params, -) -> Result { - let output = sha256_crypt(password, salt, params)?; - let r = String::from_utf8(b64::encode_sha256(&output).to_vec())?; - Ok(r) +pub fn sha256_crypt_b64(password: &[u8], salt: &[u8], params: &Sha256Params) -> String { + let output = sha256_crypt(password, salt, params); + String::from_utf8(b64::encode_sha256(&output).to_vec()).unwrap() } /// Simple interface for generating a SHA512 password hash. @@ -339,7 +321,7 @@ pub fn sha256_crypt_b64( /// [1]: https://www.akkadia.org/drepper/SHA-crypt.txt #[cfg(feature = "simple")] #[cfg_attr(docsrs, doc(cfg(feature = "simple")))] -pub fn sha512_simple(password: &str, params: &Sha512Params) -> Result { +pub fn sha512_simple(password: &str, params: &Sha512Params) -> String { let rng = thread_rng(); let salt: String = rng @@ -347,7 +329,7 @@ pub fn sha512_simple(password: &str, params: &Sha512Params) -> Result Result Result Result { +pub fn sha256_simple(password: &str, params: &Sha256Params) -> String { let rng = thread_rng(); let salt: String = rng @@ -383,7 +365,7 @@ pub fn sha256_simple(password: &str, params: &Sha256Params) -> Result Result Result<(), CheckError )); } - let params = Sha512Params { rounds }; - - let output = match sha512_crypt(password.as_bytes(), salt.as_bytes(), ¶ms) { - Ok(v) => v, + let params = match Sha512Params::new(rounds) { + Ok(p) => p, Err(e) => return Err(CheckError::Crypt(e)), }; + let output = sha512_crypt(password.as_bytes(), salt.as_bytes(), ¶ms); + let hash = b64::decode_sha512(hash.as_bytes())?; use subtle::ConstantTimeEq; @@ -537,13 +519,13 @@ pub fn sha256_check(password: &str, hashed_value: &str) -> Result<(), CheckError )); } - let params = Sha256Params { rounds }; - - let output = match sha256_crypt(password.as_bytes(), salt.as_bytes(), ¶ms) { - Ok(v) => v, + let params = match Sha256Params::new(rounds) { + Ok(p) => p, Err(e) => return Err(CheckError::Crypt(e)), }; + let output = sha256_crypt(password.as_bytes(), salt.as_bytes(), ¶ms); + let hash = b64::decode_sha256(hash.as_bytes())?; use subtle::ConstantTimeEq; diff --git a/sha-crypt/tests/lib.rs b/sha-crypt/tests/lib.rs index 428eb660..62a046db 100644 --- a/sha-crypt/tests/lib.rs +++ b/sha-crypt/tests/lib.rs @@ -100,7 +100,7 @@ const TEST_VECTORS: &[TestVector] = &[ fn test_sha512_crypt() { for t in TEST_VECTORS { let params = Sha512Params::new(t.rounds).expect("Rounds error"); - let result = sha512_crypt_b64(t.input.as_bytes(), t.salt.as_bytes(), ¶ms).unwrap(); + let result = sha512_crypt_b64(t.input.as_bytes(), t.salt.as_bytes(), ¶ms); assert!(result == t.result_sha512); } } @@ -109,7 +109,7 @@ fn test_sha512_crypt() { fn test_sha256_crypt() { for t in TEST_VECTORS { let params = Sha256Params::new(t.rounds).expect("Rounds error"); - let result = sha256_crypt_b64(t.input.as_bytes(), t.salt.as_bytes(), ¶ms).unwrap(); + let result = sha256_crypt_b64(t.input.as_bytes(), t.salt.as_bytes(), ¶ms); println!("result {:?}", result); println!("correct {:?}", t.result_sha256); assert!(result == t.result_sha256); @@ -172,9 +172,7 @@ fn test_sha512_simple_check_roundtrip() { let pw = "this is my password"; let params = Sha512Params::new(5_000).expect("Rounds error"); - let r = sha512_simple(pw, ¶ms); - assert!(r.is_ok()); - let hash = r.unwrap(); + let hash = sha512_simple(pw, ¶ms); let c_r = sha512_check(pw, &hash); assert!(c_r.is_ok()); @@ -186,9 +184,7 @@ fn test_sha256_simple_check_roundtrip() { let pw = "this is my password"; let params = Sha256Params::new(5_000).expect("Rounds error"); - let r = sha256_simple(pw, ¶ms); - assert!(r.is_ok()); - let hash = r.unwrap(); + let hash = sha256_simple(pw, ¶ms); let c_r = sha256_check(pw, &hash); assert!(c_r.is_ok());