Allow applying unicode normalisation to passwords before hashing

This commit is contained in:
Quentin Gliech
2025-05-30 15:33:34 +02:00
parent b229cb8018
commit 40cb052d1f
18 changed files with 128 additions and 56 deletions

View File

@@ -31,6 +31,7 @@ use mas_storage_pg::{DatabaseError, PgRepository};
use rand::{RngCore, SeedableRng};
use sqlx::{Acquire, types::Uuid};
use tracing::{error, info, info_span, warn};
use zeroize::Zeroizing;
use crate::util::{
database_connection_from_config, homeserver_connection_from_config,
@@ -210,7 +211,7 @@ impl Options {
return Ok(ExitCode::from(1));
}
let password = password.into_bytes().into();
let password = Zeroizing::new(password);
let (version, hashed_password) = password_manager.hash(&mut rng, password).await?;
@@ -566,7 +567,7 @@ impl Options {
// Hash the password if it's provided
let hashed_password = if let Some(password) = password {
let password = password.into_bytes().into();
let password = Zeroizing::new(password);
Some(password_manager.hash(&mut rng, password).await?)
} else {
None
@@ -641,7 +642,7 @@ impl Options {
.interact()
})
.await??;
let password = password.into_bytes().into();
let password = Zeroizing::new(password);
req.hashed_password =
Some(password_manager.hash(&mut rng, password).await?);
}

View File

@@ -36,20 +36,24 @@ pub async fn password_manager_from_config(
return Ok(PasswordManager::disabled());
}
let schemes = config
.load()
.await?
.into_iter()
.map(|(version, algorithm, cost, secret)| {
let schemes = config.load().await?.into_iter().map(
|(version, algorithm, cost, secret, unicode_normalization)| {
use mas_handlers::passwords::Hasher;
let hasher = match algorithm {
mas_config::PasswordAlgorithm::Pbkdf2 => Hasher::pbkdf2(secret),
mas_config::PasswordAlgorithm::Bcrypt => Hasher::bcrypt(cost, secret),
mas_config::PasswordAlgorithm::Argon2id => Hasher::argon2id(secret),
mas_config::PasswordAlgorithm::Pbkdf2 => {
Hasher::pbkdf2(secret, unicode_normalization)
}
mas_config::PasswordAlgorithm::Bcrypt => {
Hasher::bcrypt(cost, secret, unicode_normalization)
}
mas_config::PasswordAlgorithm::Argon2id => {
Hasher::argon2id(secret, unicode_normalization)
}
};
(version, hasher)
});
},
);
PasswordManager::new(config.minimum_complexity(), schemes)
}
@@ -492,7 +496,7 @@ mod tests {
#[tokio::test]
async fn test_password_manager_from_config() {
let mut rng = rand_chacha::ChaChaRng::seed_from_u64(42);
let password = Zeroizing::new(b"hunter2".to_vec());
let password = Zeroizing::new("hunter2".to_owned());
// Test a valid, enabled config
let config = serde_json::from_value(serde_json::json!({