split hash utils into directory
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
df0328f43f
commit
52d470058a
4 changed files with 88 additions and 65 deletions
|
@ -1,62 +1,15 @@
|
|||
use std::sync::OnceLock;
|
||||
mod argon;
|
||||
mod sha256;
|
||||
|
||||
use argon2::{
|
||||
password_hash, password_hash::SaltString, Algorithm, Argon2, Params, PasswordHash, PasswordHasher,
|
||||
PasswordVerifier, Version,
|
||||
};
|
||||
use crate::Result;
|
||||
|
||||
const M_COST: u32 = Params::DEFAULT_M_COST; // memory size in 1 KiB blocks
|
||||
const T_COST: u32 = Params::DEFAULT_T_COST; // nr of iterations
|
||||
const P_COST: u32 = Params::DEFAULT_P_COST; // parallelism
|
||||
#[inline]
|
||||
pub fn password(password: &str) -> Result<String> { argon::password(password) }
|
||||
|
||||
static ARGON: OnceLock<Argon2<'static>> = OnceLock::new();
|
||||
|
||||
pub fn password(password: &str) -> Result<String, password_hash::Error> {
|
||||
let salt = SaltString::generate(rand::thread_rng());
|
||||
ARGON
|
||||
.get_or_init(init_argon)
|
||||
.hash_password(password.as_bytes(), &salt)
|
||||
.map(|it| it.to_string())
|
||||
#[inline]
|
||||
pub fn verify_password(password: &str, password_hash: &str) -> Result<()> {
|
||||
argon::verify_password(password, password_hash)
|
||||
}
|
||||
|
||||
pub fn verify_password(password: &str, password_hash: &str) -> Result<(), password_hash::Error> {
|
||||
let password_hash = PasswordHash::new(password_hash)?;
|
||||
ARGON
|
||||
.get_or_init(init_argon)
|
||||
.verify_password(password.as_bytes(), &password_hash)
|
||||
}
|
||||
|
||||
fn init_argon() -> Argon2<'static> {
|
||||
// 19456 Kib blocks, iterations = 2, parallelism = 1
|
||||
// * <https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id>
|
||||
debug_assert!(M_COST == 19_456, "M_COST default changed");
|
||||
debug_assert!(T_COST == 2, "T_COST default changed");
|
||||
debug_assert!(P_COST == 1, "P_COST default changed");
|
||||
|
||||
let algorithm = Algorithm::Argon2id;
|
||||
let version = Version::default();
|
||||
let out_len: Option<usize> = None;
|
||||
let params = Params::new(M_COST, T_COST, P_COST, out_len).expect("valid parameters");
|
||||
Argon2::new(algorithm, version, params)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn password_hash_and_verify() {
|
||||
use crate::utils::hash;
|
||||
let preimage = "temp123";
|
||||
let digest = hash::password(preimage).expect("digest");
|
||||
hash::verify_password(preimage, &digest).expect("verified");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "unverified")]
|
||||
fn password_hash_and_verify_fail() {
|
||||
use crate::utils::hash;
|
||||
let preimage = "temp123";
|
||||
let fakeimage = "temp321";
|
||||
let digest = hash::password(preimage).expect("digest");
|
||||
hash::verify_password(fakeimage, &digest).expect("unverified");
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn calculate_hash(keys: &[&[u8]]) -> Vec<u8> { sha256::hash(keys) }
|
||||
|
|
68
src/core/utils/hash/argon.rs
Normal file
68
src/core/utils/hash/argon.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use std::sync::OnceLock;
|
||||
|
||||
use argon2::{
|
||||
password_hash, password_hash::SaltString, Algorithm, Argon2, Params, PasswordHash, PasswordHasher,
|
||||
PasswordVerifier, Version,
|
||||
};
|
||||
|
||||
use crate::{Error, Result};
|
||||
|
||||
const M_COST: u32 = Params::DEFAULT_M_COST; // memory size in 1 KiB blocks
|
||||
const T_COST: u32 = Params::DEFAULT_T_COST; // nr of iterations
|
||||
const P_COST: u32 = Params::DEFAULT_P_COST; // parallelism
|
||||
|
||||
static ARGON: OnceLock<Argon2<'static>> = OnceLock::new();
|
||||
|
||||
fn init_argon() -> Argon2<'static> {
|
||||
// 19456 Kib blocks, iterations = 2, parallelism = 1
|
||||
// * <https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id>
|
||||
debug_assert!(M_COST == 19_456, "M_COST default changed");
|
||||
debug_assert!(T_COST == 2, "T_COST default changed");
|
||||
debug_assert!(P_COST == 1, "P_COST default changed");
|
||||
|
||||
let algorithm = Algorithm::Argon2id;
|
||||
let version = Version::default();
|
||||
let out_len: Option<usize> = None;
|
||||
let params = Params::new(M_COST, T_COST, P_COST, out_len).expect("valid parameters");
|
||||
Argon2::new(algorithm, version, params)
|
||||
}
|
||||
|
||||
pub(super) fn password(password: &str) -> Result<String> {
|
||||
let salt = SaltString::generate(rand::thread_rng());
|
||||
ARGON
|
||||
.get_or_init(init_argon)
|
||||
.hash_password(password.as_bytes(), &salt)
|
||||
.map(|it| it.to_string())
|
||||
.map_err(map_err)
|
||||
}
|
||||
|
||||
pub(super) fn verify_password(password: &str, password_hash: &str) -> Result<()> {
|
||||
let password_hash = PasswordHash::new(password_hash).map_err(map_err)?;
|
||||
ARGON
|
||||
.get_or_init(init_argon)
|
||||
.verify_password(password.as_bytes(), &password_hash)
|
||||
.map_err(map_err)
|
||||
}
|
||||
|
||||
fn map_err(e: password_hash::Error) -> Error { Error::Err(e.to_string()) }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn password_hash_and_verify() {
|
||||
use crate::utils::hash;
|
||||
let preimage = "temp123";
|
||||
let digest = hash::password(preimage).expect("digest");
|
||||
hash::verify_password(preimage, &digest).expect("verified");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "unverified")]
|
||||
fn password_hash_and_verify_fail() {
|
||||
use crate::utils::hash;
|
||||
let preimage = "temp123";
|
||||
let fakeimage = "temp321";
|
||||
let digest = hash::password(preimage).expect("digest");
|
||||
hash::verify_password(fakeimage, &digest).expect("unverified");
|
||||
}
|
||||
}
|
9
src/core/utils/hash/sha256.rs
Normal file
9
src/core/utils/hash/sha256.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
use ring::{digest, digest::SHA256};
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(super) fn hash(keys: &[&[u8]]) -> Vec<u8> {
|
||||
// We only hash the pdu's event ids, not the whole pdu
|
||||
let bytes = keys.join(&0xFF);
|
||||
let hash = digest::digest(&SHA256, &bytes);
|
||||
hash.as_ref().to_owned()
|
||||
}
|
|
@ -14,11 +14,11 @@ use std::{
|
|||
};
|
||||
|
||||
pub use debug::slice_truncated as debug_slice_truncated;
|
||||
pub use hash::calculate_hash;
|
||||
pub use html::Escape as HtmlEscape;
|
||||
pub use json::{deserialize_from_str, to_canonical_object};
|
||||
pub use mutex_map::MutexMap;
|
||||
use rand::prelude::*;
|
||||
use ring::digest;
|
||||
use ruma::UserId;
|
||||
pub use sys::available_parallelism;
|
||||
|
||||
|
@ -84,13 +84,6 @@ pub fn random_string(length: usize) -> String {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(keys))]
|
||||
pub fn calculate_hash(keys: &[&[u8]]) -> Vec<u8> {
|
||||
// We only hash the pdu's event ids, not the whole pdu
|
||||
let bytes = keys.join(&0xFF);
|
||||
let hash = digest::digest(&digest::SHA256, &bytes);
|
||||
hash.as_ref().to_owned()
|
||||
}
|
||||
|
||||
#[allow(clippy::impl_trait_in_params)]
|
||||
pub fn common_elements(
|
||||
|
|
Loading…
Add table
Reference in a new issue