Add argon2 to core Rust lib (#1404)

This commit is contained in:
Leendert de Borst
2026-01-14 11:41:05 +01:00
parent d3a785b227
commit 2899855962
4 changed files with 103 additions and 0 deletions
+40
View File
@@ -6,6 +6,7 @@ version = 4
name = "aliasvault-core"
version = "0.1.0"
dependencies = [
"argon2",
"chrono",
"console_error_panic_hook",
"digest",
@@ -79,6 +80,18 @@ version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "argon2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
dependencies = [
"base64ct",
"blake2",
"cpufeatures",
"password-hash",
]
[[package]]
name = "askama"
version = "0.12.1"
@@ -126,6 +139,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "base64ct"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]]
name = "basic-toml"
version = "0.1.10"
@@ -144,6 +163,15 @@ dependencies = [
"serde",
]
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -296,6 +324,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
@@ -471,6 +500,17 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "paste"
version = "1.0.15"
+3
View File
@@ -45,6 +45,9 @@ digest = "0.10"
subtle = "2.5"
getrandom = { version = "0.2", features = ["js"] }
# Argon2 password hashing
argon2 = "0.5"
# UniFFI for Swift/Kotlin bindings (optional)
# Note: Don't add "cli" feature here - it pulls in heavy bindgen dependencies
# The uniffi-cli feature enables CLI separately for the uniffi-bindgen binary only
+41
View File
@@ -118,6 +118,47 @@ fn pad_to_length(bytes: Vec<u8>, target_len: usize) -> Vec<u8> {
}
}
// ═══════════════════════════════════════════════════════════════════════════════
// Argon2 Password Hashing
// ═══════════════════════════════════════════════════════════════════════════════
/// Derive a key from a password using Argon2Id.
///
/// Uses the AliasVault default parameters:
/// - Iterations: 2
/// - Memory: 19456 KiB
/// - Parallelism: 1
/// - Output length: 32 bytes
///
/// # Arguments
/// * `password` - The password to hash
/// * `salt` - Salt as a string (will be UTF-8 encoded)
///
/// # Returns
/// Derived key as uppercase hex string (64 characters = 32 bytes)
pub fn argon2_hash_password(password: &str, salt: &str) -> Result<String, SrpError> {
use argon2::{Argon2, Algorithm, Version, Params};
// AliasVault default parameters
let params = Params::new(
19456, // m_cost (memory in KiB)
2, // t_cost (iterations)
1, // p_cost (parallelism)
Some(32) // output length
).map_err(|e| SrpError::InvalidParameter(format!("Invalid Argon2 params: {}", e)))?;
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
let mut output = [0u8; 32];
argon2.hash_password_into(
password.as_bytes(),
salt.as_bytes(),
&mut output
).map_err(|e| SrpError::InvalidParameter(format!("Argon2 hash failed: {}", e)))?;
Ok(bytes_to_hex(&output))
}
// ═══════════════════════════════════════════════════════════════════════════════
// Client Operations
// ═══════════════════════════════════════════════════════════════════════════════
+19
View File
@@ -114,6 +114,25 @@ pub fn extract_root_domain(domain: String) -> String {
pub use crate::srp::{SrpEphemeral, SrpSession, SrpError};
/// Derive a key from a password using Argon2Id.
///
/// Uses the AliasVault default parameters:
/// - Iterations: 2
/// - Memory: 19456 KiB
/// - Parallelism: 1
/// - Output length: 32 bytes
///
/// # Arguments
/// * `password` - The password to hash
/// * `salt` - Salt as a string (will be UTF-8 encoded)
///
/// # Returns
/// Derived key as uppercase hex string (64 characters = 32 bytes)
#[uniffi::export]
pub fn argon2_hash_password(password: String, salt: String) -> Result<String, SrpError> {
crate::srp::argon2_hash_password(&password, &salt)
}
/// Generate a cryptographic salt for SRP.
/// Returns a 32-byte random salt as an uppercase hex string.
#[uniffi::export]