openserve 2.0.3

A modern, high-performance, AI-enhanced file server built in Rust
Documentation
//! Cryptography Utilities
//!
//! This module provides utility functions for cryptographic operations,
//! such as password hashing and verification. It uses the `argon2`
//! crate for secure password hashing and `rand` for generating salts.

use anyhow::Result;
use argon2::{
    password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
    Argon2,
};
use sha2::{Sha256, Digest};

/// Hashes a password using the Argon2id algorithm.
///
/// This function takes a plain-text password, generates a random salt,
/// and computes the password hash. The resulting hash is suitable for
/// secure storage.
///
/// # Arguments
///
/// * `password` - The plain-text password to hash.
///
/// # Returns
///
/// A `Result` containing the hashed password as a `String`, or an error
/// if hashing fails.
pub fn hash_password(password: &str) -> Result<String> {
    let salt = SaltString::generate(&mut OsRng);
    let argon2 = Argon2::default();
    let password_hash = argon2
        .hash_password(password.as_bytes(), &salt)
        .map_err(|e| anyhow::anyhow!("Password hashing failed: {}", e))?
        .to_string();
    Ok(password_hash)
}

/// Verifies a plain-text password against a stored Argon2 hash.
///
/// # Arguments
///
/// * `password` - The plain-text password to verify.
/// * `hash` - The stored password hash to verify against.
///
/// # Returns
///
/// A `Result` containing `true` if the password matches the hash,
/// and `false` otherwise. An error is returned if the hash is invalid.
pub fn verify_password(password: &str, hash: &str) -> Result<bool> {
    let parsed_hash = PasswordHash::new(hash)
        .map_err(|e| anyhow::anyhow!("Invalid password hash: {}", e))?;
    let argon2 = Argon2::default();
    Ok(argon2
        .verify_password(password.as_bytes(), &parsed_hash)
        .is_ok())
}

/// Computes the SHA-256 hash of a byte slice.
///
/// This is a general-purpose hashing function suitable for checksums or
/// data integrity checks, but not for password hashing.
///
/// # Arguments
///
/// * `data` - The byte slice to hash.
///
/// # Returns
///
/// A `String` representing the hexadecimal SHA-256 hash.
pub fn sha256_hash(data: &[u8]) -> String {
    let mut hasher = Sha256::new();
    hasher.update(data);
    format!("{:x}", hasher.finalize())
}

/// Generates a secure, random, alphanumeric token of a specified length.
///
/// This function is useful for creating session tokens, API keys, or other
/// sensitive, temporary credentials.
///
/// # Arguments
///
/// * `length` - The desired length of the token.
///
/// # Returns
///
/// A randomly generated `String`.
pub fn generate_token(length: usize) -> String {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    (0..length)
        .map(|_| rng.sample(rand::distributions::Alphanumeric) as char)
        .collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_password_hashing() {
        let password = "test_password";
        let hash = hash_password(password).unwrap();
        
        assert!(verify_password(password, &hash).unwrap());
        assert!(!verify_password("wrong_password", &hash).unwrap());
    }

    #[test]
    fn test_sha256_hash() {
        let data = b"hello world";
        let hash = sha256_hash(data);
        assert_eq!(hash, "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
    }
}