use entity::master_pass; use rand::{rngs::OsRng, RngCore}; use scrypt::{scrypt, Params}; use sea_orm::ActiveValue::Set; /// Hashes the password with Scrypt with the given salt #[inline] fn hash_password(password: &[u8], salt: &[u8]) -> [u8; 64] { let params = Params::new(14, Params::RECOMMENDED_R, Params::RECOMMENDED_P, 64).unwrap(); let mut password_hash = [0; 64]; scrypt(password, salt, ¶ms, &mut password_hash).unwrap(); password_hash } pub trait VerifyMasterPassExt { fn verify(&self, password: &str) -> bool; } impl VerifyMasterPassExt for master_pass::Model { /// Checks that the given password hash matches the one of the model #[inline] fn verify(&self, password: &str) -> bool { let hashed = hash_password(password.as_bytes(), &self.salt); hashed == self.password_hash.as_slice() } } pub trait MasterPassFromUnencryptedExt { fn from_unencrypted(user_id: u64, password: &str) -> master_pass::ActiveModel; } impl MasterPassFromUnencryptedExt for master_pass::ActiveModel { /// Hashes the password and creates an ActiveModel with all fields set to Set variant #[inline] fn from_unencrypted(user_id: u64, password: &str) -> Self { let mut salt = vec![0; 64]; OsRng.fill_bytes(&mut salt); let password_hash = Set(hash_password(password.as_bytes(), &salt).to_vec()); Self { user_id: Set(user_id), salt: Set(salt), password_hash, } } }