bit-twiddler 0.2.0

Cross-platform developer toolbox: bit manipulation, hashing, YAML/JSON/SQL, QR, Markdown, cron, and 40+ more tools — Tauri v2, no Node.js
use argon2::{
    password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
    Algorithm, Argon2, Params, Version,
};

#[tauri::command]
pub fn hash_password(
    password: String,
    algorithm: String,
    cost: u32,
    memory_kib: u32,
    parallelism: u32,
) -> Result<String, String> {
    match algorithm.as_str() {
        "bcrypt" => bcrypt::hash(&password, cost).map_err(|e| e.to_string()),
        "argon2id" => {
            let params =
                Params::new(memory_kib, cost, parallelism, None).map_err(|e| e.to_string())?;
            let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
            let salt = SaltString::generate(&mut OsRng);
            argon2
                .hash_password(password.as_bytes(), &salt)
                .map(|h| h.to_string())
                .map_err(|e| e.to_string())
        }
        other => Err(format!("Unsupported algorithm: {other}")),
    }
}

#[tauri::command]
pub fn verify_password(password: String, hash: String) -> Result<bool, String> {
    if hash.starts_with("$2") {
        bcrypt::verify(&password, &hash).map_err(|e| e.to_string())
    } else if hash.starts_with("$argon2") {
        let parsed = PasswordHash::new(&hash).map_err(|e| e.to_string())?;
        Ok(Argon2::default()
            .verify_password(password.as_bytes(), &parsed)
            .is_ok())
    } else {
        Err("Unrecognized hash format (expected bcrypt $2*$ or Argon2 $argon2*$)".to_string())
    }
}