1use crate::error::{CryptoError, CryptoResult};
4use zeroize::Zeroize;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum PasswordAlgorithm {
9 Bcrypt,
11 Argon2,
13}
14
15#[derive(Debug, Clone)]
17pub struct PasswordHasherConfig {
18 pub algorithm: PasswordAlgorithm,
20 pub bcrypt_cost: u32,
22}
23
24impl Default for PasswordHasherConfig {
25 fn default() -> Self {
26 Self { algorithm: PasswordAlgorithm::Bcrypt, bcrypt_cost: 12 }
27 }
28}
29
30#[derive(Debug, Clone)]
32pub struct PasswordHasher {
33 config: PasswordHasherConfig,
34}
35
36impl PasswordHasher {
37 pub fn new(config: PasswordHasherConfig) -> Self {
39 Self { config }
40 }
41
42 pub fn default() -> Self {
44 Self::new(PasswordHasherConfig::default())
45 }
46
47 pub fn hash_password(&self, password: &str) -> CryptoResult<String> {
49 let mut password_bytes = password.as_bytes().to_vec();
50 let result = match self.config.algorithm {
51 PasswordAlgorithm::Bcrypt => self.hash_bcrypt(&password_bytes),
52 PasswordAlgorithm::Argon2 => self.hash_argon2(&password_bytes),
53 };
54 password_bytes.zeroize();
55 result
56 }
57
58 pub fn verify_password(&self, password: &str, hash: &str) -> CryptoResult<bool> {
60 let mut password_bytes = password.as_bytes().to_vec();
61 let result = match self.config.algorithm {
62 PasswordAlgorithm::Bcrypt => self.verify_bcrypt(&password_bytes, hash),
63 PasswordAlgorithm::Argon2 => self.verify_argon2(&password_bytes, hash),
64 };
65 password_bytes.zeroize();
66 result
67 }
68
69 fn hash_bcrypt(&self, password: &[u8]) -> CryptoResult<String> {
71 bcrypt::hash(password, self.config.bcrypt_cost).map_err(|_| CryptoError::PasswordHashError)
72 }
73
74 fn verify_bcrypt(&self, password: &[u8], hash: &str) -> CryptoResult<bool> {
76 bcrypt::verify(password, hash).map_err(|_| CryptoError::PasswordVerifyError)
77 }
78
79 fn hash_argon2(&self, _password: &[u8]) -> CryptoResult<String> {
81 Err(CryptoError::InvalidAlgorithm)
82 }
83
84 fn verify_argon2(&self, _password: &[u8], _hash: &str) -> CryptoResult<bool> {
86 Err(CryptoError::InvalidAlgorithm)
87 }
88}
89
90impl Default for PasswordHasher {
91 fn default() -> Self {
92 Self::new(PasswordHasherConfig::default())
93 }
94}