use super::PasswordHasher;
use sha2::{Digest, Sha256};
use subtle::ConstantTimeEq;
#[derive(Debug, Copy, Clone, Default)]
pub struct Sha256Hasher;
impl Sha256Hasher {
pub const fn new() -> Self {
Self
}
}
impl PasswordHasher for Sha256Hasher {
fn hash(&self, password: &str, salt: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(salt);
hasher.update(password.as_bytes());
let result = hasher.finalize();
let mut hash = [0u8; 32];
hash.copy_from_slice(&result);
hash
}
fn verify(&self, password: &str, salt: &[u8], hash: &[u8; 32]) -> bool {
let computed_hash = self.hash(password, salt);
computed_hash.ct_eq(hash).into()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_same_password_same_hash() {
let hasher = Sha256Hasher::new();
let salt = [1u8; 16];
let hash1 = hasher.hash("password123", &salt);
let hash2 = hasher.hash("password123", &salt);
assert_eq!(hash1, hash2);
}
#[test]
fn test_different_passwords_different_hashes() {
let hasher = Sha256Hasher::new();
let salt = [1u8; 16];
let hash1 = hasher.hash("password123", &salt);
let hash2 = hasher.hash("password456", &salt);
assert_ne!(hash1, hash2);
}
#[test]
fn test_different_salts_different_hashes() {
let hasher = Sha256Hasher::new();
let salt1 = [1u8; 16];
let salt2 = [2u8; 16];
let hash1 = hasher.hash("password123", &salt1);
let hash2 = hasher.hash("password123", &salt2);
assert_ne!(hash1, hash2);
}
#[test]
fn test_verify_correct_password() {
let hasher = Sha256Hasher::new();
let salt = [1u8; 16];
let hash = hasher.hash("password123", &salt);
assert!(hasher.verify("password123", &salt, &hash));
}
#[test]
fn test_verify_incorrect_password() {
let hasher = Sha256Hasher::new();
let salt = [1u8; 16];
let hash = hasher.hash("password123", &salt);
assert!(!hasher.verify("wrongpassword", &salt, &hash));
}
#[test]
fn test_verify_wrong_salt() {
let hasher = Sha256Hasher::new();
let salt1 = [1u8; 16];
let salt2 = [2u8; 16];
let hash = hasher.hash("password123", &salt1);
assert!(!hasher.verify("password123", &salt2, &hash));
}
#[test]
fn test_empty_password() {
let hasher = Sha256Hasher::new();
let salt = [1u8; 16];
let hash = hasher.hash("", &salt);
assert_eq!(hash.len(), 32);
assert!(hasher.verify("", &salt, &hash));
assert!(!hasher.verify("nonempty", &salt, &hash));
}
#[test]
fn test_unicode_password() {
let hasher = Sha256Hasher::new();
let salt = [1u8; 16];
let password = "пароль🔒";
let hash = hasher.hash(password, &salt);
assert!(hasher.verify(password, &salt, &hash));
assert!(!hasher.verify("different", &salt, &hash));
}
}