Skip to content

Instantly share code, notes, and snippets.

@Gabriel-Paulucci
Created December 15, 2021 16:43
Show Gist options
  • Save Gabriel-Paulucci/47d4b5b1ff8f3975939fb91f1acc3c3c to your computer and use it in GitHub Desktop.
Save Gabriel-Paulucci/47d4b5b1ff8f3975939fb91f1acc3c3c to your computer and use it in GitHub Desktop.
Hash Password and Salt in Rust
use std::fmt::Display;
use chrono::Utc;
use sha3::Sha3_512;
use uuid::Uuid;
use crate::errors::HashError;
struct HashedElement(Box<[u8]>);
impl HashedElement {
fn hash(element: &str) -> Self {
let element_to_bytes = element.as_bytes();
Self::hash_raw(element_to_bytes)
}
fn hash_raw(element: &[u8]) -> Self {
let mut hasher = Sha3_512::new();
hasher.update(element);
let hashed_content = hasher.finalize()[..].into();
Self(hashed_content)
}
fn hash_from_base(base64: &str) -> Result<Self, HashError> {
let data = base64::decode(base64).map_err(|_| HashError::InvalidBase64)?;
Ok(Self(data.into()))
}
fn append_hash(&self, more_hash: &Self) -> Self {
let arrs = [&*self.0, &*more_hash.0].concat();
Self::hash_raw(&*arrs)
}
}
impl Display for HashedElement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", base64::encode(&*self.0))
}
}
#[derive(PartialEq, Eq, Debug)]
pub struct PasswordHasher {
salt: String,
password: String,
}
impl PasswordHasher {
pub fn new(extra_data: &str, password: &str) -> Self {
let extra_data_hash = HashedElement::hash(extra_data);
let password_hash = HashedElement::hash(password);
let content_hash = extra_data_hash.append_hash(&password_hash);
let uuid = HashedElement::hash(&Uuid::new_v4().to_string());
let now = HashedElement::hash(&Utc::now().timestamp().to_string());
let salt_hash = content_hash.append_hash(&uuid).append_hash(&now);
let password_hash = content_hash.append_hash(&salt_hash);
Self {
salt: salt_hash.to_string(),
password: password_hash.to_string(),
}
}
pub fn new_from_created_salt(
password: &str,
extra_data: &str,
salt: &str,
) -> Result<Self, HashError> {
let salt = HashedElement::hash_from_base(salt)?;
let password = HashedElement::hash(password);
let extra_data = HashedElement::hash(extra_data);
let password = extra_data.append_hash(&password);
let password = password.append_hash(&salt);
Ok(Self {
salt: salt.to_string(),
password: password.to_string(),
})
}
pub fn load_password_hasher_info(pass_hashed: String, salt: String) -> Self {
Self {
password: pass_hashed,
salt,
}
}
pub fn get_password_hash(&self) -> &str {
&self.password
}
pub fn get_salt(&self) -> &str {
&self.salt
}
}
#[test]
fn check_password_creator_and_login() {
let username = "username";
let password = "superpassword";
let password_generated = PasswordHasher::new(username, password);
let generated_salt = password_generated.get_salt();
let login_password_generated =
PasswordHasher::new_from_created_salt(password, username, generated_salt).unwrap();
assert_eq!(password_generated, login_password_generated);
}
#[test]
fn check_wrong_password_creator_and_login() {
let username = "username";
let password = "superpassword";
let wrong_password = "notsuperpassword";
let sing_up_password = PasswordHasher::new(username, password);
let pass_salt = sing_up_password.get_salt();
let sing_in_password =
PasswordHasher::new_from_created_salt(wrong_password, username, pass_salt).unwrap();
assert!(sing_up_password != sing_in_password);
}
#[test]
fn check_from_load() {
let username = "username";
let password = "superpassword";
let sing_up = PasswordHasher::new(username, password);
let hash_pass = sing_up.get_password_hash();
let salt = sing_up.get_salt();
let reconstructed = PasswordHasher::load_password_hasher_info(hash_pass.into(), salt.into());
assert_eq!(sing_up, reconstructed);
}
@kakarot-dev
Copy link

Really helped me :3
Thanks!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment