Skip to content

Commit

Permalink
sha-crypt: Make hashing infallible
Browse files Browse the repository at this point in the history
The rounds were already checked to be sane in
`Sha{256,512}Parameters::new`.

Fixes #499.
  • Loading branch information
tbu- committed May 17, 2024
1 parent 30196fb commit ccbf11e
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 52 deletions.
70 changes: 26 additions & 44 deletions sha-crypt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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<String, CryptError> {
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.
Expand All @@ -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<String, CryptError> {
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.
Expand All @@ -339,15 +321,15 @@ 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<String, CryptError> {
pub fn sha512_simple(password: &str, params: &Sha512Params) -> String {
let rng = thread_rng();

let salt: String = rng
.sample_iter(&ShaCryptDistribution)
.take(SALT_MAX_LEN)
.collect();

let out = sha512_crypt(password.as_bytes(), salt.as_bytes(), params)?;
let out = sha512_crypt(password.as_bytes(), salt.as_bytes(), params);

let mut result = String::new();
result.push_str(SHA512_SALT_PREFIX);
Expand All @@ -357,9 +339,9 @@ pub fn sha512_simple(password: &str, params: &Sha512Params) -> Result<String, Cr
}
result.push_str(&salt);
result.push('$');
let s = String::from_utf8(b64::encode_sha512(&out).to_vec())?;
let s = String::from_utf8(b64::encode_sha512(&out).to_vec()).unwrap();
result.push_str(&s);
Ok(result)
result
}

/// Simple interface for generating a SHA256 password hash.
Expand All @@ -375,15 +357,15 @@ pub fn sha512_simple(password: &str, params: &Sha512Params) -> Result<String, Cr
/// [1]: https://www.akkadia.org/drepper/SHA-crypt.txt
#[cfg(feature = "simple")]
#[cfg_attr(docsrs, doc(cfg(feature = "simple")))]
pub fn sha256_simple(password: &str, params: &Sha256Params) -> Result<String, CryptError> {
pub fn sha256_simple(password: &str, params: &Sha256Params) -> String {
let rng = thread_rng();

let salt: String = rng
.sample_iter(&ShaCryptDistribution)
.take(SALT_MAX_LEN)
.collect();

let out = sha256_crypt(password.as_bytes(), salt.as_bytes(), params)?;
let out = sha256_crypt(password.as_bytes(), salt.as_bytes(), params);

let mut result = String::new();
result.push_str(SHA256_SALT_PREFIX);
Expand All @@ -393,9 +375,9 @@ pub fn sha256_simple(password: &str, params: &Sha256Params) -> Result<String, Cr
}
result.push_str(&salt);
result.push('$');
let s = String::from_utf8(b64::encode_sha256(&out).to_vec())?;
let s = String::from_utf8(b64::encode_sha256(&out).to_vec()).unwrap();
result.push_str(&s);
Ok(result)
result
}

/// Checks that given password matches provided hash.
Expand Down Expand Up @@ -459,13 +441,13 @@ pub fn sha512_check(password: &str, hashed_value: &str) -> Result<(), CheckError
));
}

let params = Sha512Params { rounds };

let output = match sha512_crypt(password.as_bytes(), salt.as_bytes(), &params) {
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(), &params);

let hash = b64::decode_sha512(hash.as_bytes())?;

use subtle::ConstantTimeEq;
Expand Down Expand Up @@ -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(), &params) {
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(), &params);

let hash = b64::decode_sha256(hash.as_bytes())?;

use subtle::ConstantTimeEq;
Expand Down
12 changes: 4 additions & 8 deletions sha-crypt/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(), &params).unwrap();
let result = sha512_crypt_b64(t.input.as_bytes(), t.salt.as_bytes(), &params);
assert!(result == t.result_sha512);
}
}
Expand All @@ -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(), &params).unwrap();
let result = sha256_crypt_b64(t.input.as_bytes(), t.salt.as_bytes(), &params);
println!("result {:?}", result);
println!("correct {:?}", t.result_sha256);
assert!(result == t.result_sha256);
Expand Down Expand Up @@ -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, &params);
assert!(r.is_ok());
let hash = r.unwrap();
let hash = sha512_simple(pw, &params);

let c_r = sha512_check(pw, &hash);
assert!(c_r.is_ok());
Expand All @@ -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, &params);
assert!(r.is_ok());
let hash = r.unwrap();
let hash = sha256_simple(pw, &params);

let c_r = sha256_check(pw, &hash);
assert!(c_r.is_ok());
Expand Down

0 comments on commit ccbf11e

Please sign in to comment.