Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Snippet 4: Create User Locked Vault

#![allow(unused)]
fn main() {
pub fn initialize_for_user(&mut self, user_id: &str, password: &str) -> Result<()> {
    println!("Starting crypto initialization for user: {}", user_id);
    let start_time = std::time::Instant::now();

    // Create user-specific config directory
    let mut user_config_path = self.config_path.clone();
    user_config_path.push("users");
    user_config_path.push(user_id);

    if !user_config_path.exists() {
        fs::create_dir_all(&user_config_path)?;
    }

    let key_file = user_config_path.join("auth.hash");
    let metadata_file = user_config_path.join("security.meta");

    let key = if key_file.exists() && metadata_file.exists() {
        println!("Loading existing user configuration...");

        // Load existing setup
        let stored_hash = fs::read_to_string(&key_file)?;
        let parsed_hash = PasswordHash::new(&stored_hash)
            .map_err(|e| anyhow!("Failed to parse password hash: {}", e))?;

        println!("Verifying password...");
        // Verify password (this should be fast with default Argon2)
        Argon2::default()
            .verify_password(password.as_bytes(), &parsed_hash)
            .map_err(|e| anyhow!("Password verification failed: {}", e))?;

        println!("Loading metadata...");
        // Load metadata
        let metadata_content = fs::read_to_string(&metadata_file)?;
        let mut metadata: SecurityMetadata = serde_json::from_str(&metadata_content)
            .map_err(|e| anyhow!("Failed to parse security metadata: {}", e))?;

        // Handle backward compatibility - if hardware_components is empty, regenerate it
        if metadata.hardware_components.is_empty() {
            println!("Upgrading old metadata format...");
            let (current_hash, current_components) =
                self.generate_stable_hardware_fingerprint()?;

            // Update the metadata with current components
            metadata.hardware_components = current_components;
            metadata.hardware_fingerprint_hash = current_hash;

            // Save updated metadata
            fs::write(&metadata_file, serde_json::to_string_pretty(&metadata)?)?;
            println!("Metadata upgraded successfully");
        } else {
            println!("Checking hardware fingerprint...");
            // Get current hardware components
            let (current_hash, current_components) =
                self.generate_stable_hardware_fingerprint()?;

            // Check if hardware fingerprint matches
            if metadata.hardware_fingerprint_hash != current_hash {
                // Try to identify what changed
                let mut changed_components = Vec::new();
                for (i, (stored, current)) in metadata
                    .hardware_components
                    .iter()
                    .zip(current_components.iter())
                    .enumerate()
                {
                    if stored != current {
                        changed_components
                            .push(format!("Component {}: '{}' -> '{}'", i, stored, current));
                    }
                }

                if !changed_components.is_empty() {
                    println!("Hardware changes detected:");
                    for change in &changed_components {
                        println!("  {}", change);
                    }

                    // For now, let's be more lenient and only fail if critical components changed
                    if self.is_critical_hardware_change(
                        &metadata.hardware_components,
                        &current_components,
                    ) {
                        return Err(anyhow!(
                            "Critical hardware components changed: {}",
                            changed_components.join(", ")
                        ));
                    } else {
                        println!("Non-critical hardware changes detected, allowing access...");
                        // Update the stored fingerprint
                        metadata.hardware_fingerprint_hash = current_hash;
                        metadata.hardware_components = current_components;

                        // Save updated metadata
                        fs::write(&metadata_file, serde_json::to_string_pretty(&metadata)?)?;
                    }
                }
            } else {
                println!("Hardware fingerprint matches!");
            }
        }

        self.security_metadata = Some(metadata);

        println!("Deriving encryption key...");
        // Use standard security key derivation
        self.derive_secure_key(password)
    } else {
        println!("First time setup for user...");

        let current_time = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_secs();

        let (hardware_hash, hardware_components) =
            self.generate_stable_hardware_fingerprint()?;

        println!("Initial hardware components: {:?}", hardware_components);
        println!("Initial hardware hash: {}", hardware_hash);

        let metadata = SecurityMetadata {
            version: 1,
            created_timestamp: current_time,
            hardware_fingerprint_hash: hardware_hash,
            hardware_components,
        };

        let key = self.derive_secure_key(password);

        println!("Storing password hash...");
        // Store password hash
        let verification_salt = SaltString::generate(&mut OsRng);
        let argon2 = Argon2::default();
        let password_hash = argon2
            .hash_password(password.as_bytes(), &verification_salt)
            .map_err(|e| anyhow!("Failed to hash password: {}", e))?;

        fs::write(&key_file, password_hash.to_string())?;
        fs::write(&metadata_file, serde_json::to_string_pretty(&metadata)?)?;

        self.secure_file_permissions(&key_file)?;
        self.secure_file_permissions(&metadata_file)?;

        self.security_metadata = Some(metadata);
        key
    };

    self.cipher = Some(ChaCha20Poly1305::new(&key));

    let elapsed = start_time.elapsed();
    println!(
        "Crypto initialization completed in {:.2}s",
        elapsed.as_secs_f64()
    );

    Ok(())
}
}

Advanced Cryptographic User Vault System with Hardware Binding

This sophisticated function represents the heart of the application's security architecture, implementing a comprehensive user-specific cryptographic vault system. It combines multiple layers of security including password-based authentication, hardware fingerprinting, and modern encryption algorithms to create a robust, tamper-resistant storage system.

Comprehensive Security Architecture Analysis

Function Signature and Purpose:

#![allow(unused)]
fn main() {
pub fn initialize_for_user(&mut self, user_id: &str, password: &str) -> Result<()>
}

This function serves as the central security initialization point, responsible for establishing or restoring a user's complete cryptographic environment. It handles both first-time user setup and subsequent authentication sessions with equal security rigor.

Performance Monitoring and Logging: The function begins with comprehensive logging and performance tracking:

  • Detailed Logging: Provides extensive debug information for security auditing and troubleshooting
  • Performance Timing: Tracks initialization duration to identify potential performance issues or security attacks
  • User Context: Logs the specific user ID for audit trail purposes

User-Specific Directory Architecture:

#![allow(unused)]
fn main() {
let mut user_config_path = self.config_path.clone();
user_config_path.push("users");
user_config_path.push(user_id);
}

The system creates a hierarchical directory structure that provides:

  • User Isolation: Each user has completely separate storage, preventing data leakage between accounts
  • Organized Storage: Clear directory structure makes system administration and backup easier
  • Scalability: Can handle unlimited users without naming conflicts or performance degradation
  • Security Boundaries: File system permissions can be applied at the user level

Critical Security Files Management: Two essential files store the user's security credentials:

  • auth.hash: Contains the Argon2 password hash for authentication
  • security.meta: Stores hardware fingerprinting data and security metadata

Existing User Authentication Flow: For returning users, the system performs a multi-step verification process:

Password Hash Verification:

#![allow(unused)]
fn main() {
let stored_hash = fs::read_to_string(&key_file)?;
let parsed_hash = PasswordHash::new(&stored_hash)?;
Argon2::default().verify_password(password.as_bytes(), &parsed_hash)?;
}

This implements industry-standard password verification:

  • Argon2 Algorithm: Uses the winner of the Password Hashing Competition, resistant to both GPU and ASIC attacks
  • Salt Integration: Each password hash includes a unique salt to prevent rainbow table attacks
  • Constant-Time Verification: Prevents timing attacks that could leak password information
  • Memory-Hard Function: Requires significant memory allocation, making brute force attacks expensive

Hardware Fingerprinting System: The system implements sophisticated hardware binding to prevent credential theft:

Backward Compatibility Handling:

#![allow(unused)]
fn main() {
if metadata.hardware_components.is_empty() {
    println!("Upgrading old metadata format...");
    let (current_hash, current_components) = self.generate_stable_hardware_fingerprint()?;
    metadata.hardware_components = current_components;
    metadata.hardware_fingerprint_hash = current_hash;
}
}

This graceful upgrade system:

  • Seamless Migration: Automatically upgrades older installations without user intervention
  • Data Preservation: Maintains existing user data while adding new security features
  • Future-Proofing: Establishes a pattern for future security enhancements

Hardware Change Detection:

#![allow(unused)]
fn main() {
if metadata.hardware_fingerprint_hash != current_hash {
    let mut changed_components = Vec::new();
    for (i, (stored, current)) in metadata.hardware_components.iter().zip(current_components.iter()).enumerate() {
        if stored != current {
            changed_components.push(format!("Component {}: '{}' -> '{}'", i, stored, current));
        }
    }
}
}

The system provides intelligent hardware change handling:

  • Component-Level Analysis: Identifies exactly which hardware components have changed
  • Detailed Logging: Records specific changes for security auditing
  • Flexible Response: Distinguishes between critical and non-critical hardware changes
  • User Transparency: Provides clear information about detected changes

Critical vs Non-Critical Hardware Changes: The system implements a nuanced approach to hardware changes:

  • Critical Changes: Major components like CPU or motherboard that indicate potential system compromise
  • Non-Critical Changes: Minor changes like RAM upgrades or peripheral additions
  • Adaptive Security: Updates fingerprints for non-critical changes while blocking critical ones

First-Time User Setup: For new users, the system performs comprehensive initialization:

Security Metadata Creation:

#![allow(unused)]
fn main() {
let metadata = SecurityMetadata {
    version: 1,
    created_timestamp: current_time,
    hardware_fingerprint_hash: hardware_hash,
    hardware_components,
};
}

This metadata provides:

  • Version Tracking: Enables future security upgrades and compatibility handling
  • Timestamp Recording: Creates audit trail for account creation
  • Hardware Binding: Establishes the baseline hardware configuration
  • Component Inventory: Detailed record of hardware components for change detection

Secure Key Derivation: The system uses the derive_secure_key() method to generate encryption keys:

  • Password-Based Key Derivation: Uses the user's password as the primary key material
  • Cryptographically Secure: Employs proven key derivation functions
  • Unique Per User: Each user gets completely unique encryption keys
  • Memory Protection: Keys are handled securely in memory

Password Hash Storage:

#![allow(unused)]
fn main() {
let verification_salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
let password_hash = argon2.hash_password(password.as_bytes(), &verification_salt)?;
}

The password storage system implements best practices:

  • Cryptographically Secure Random Salt: Uses OS-provided randomness for salt generation
  • Argon2 Default Parameters: Uses recommended parameters for security vs performance balance
  • Secure Storage: Hash is immediately written to disk with secure permissions

File System Security:

#![allow(unused)]
fn main() {
self.secure_file_permissions(&key_file)?;
self.secure_file_permissions(&metadata_file)?;
}

The system applies strict file permissions:

  • Owner-Only Access: Files are readable and writable only by the file owner
  • No Group/Other Access: Prevents other users on the system from accessing sensitive data
  • Cross-Platform Implementation: Handles permission setting across different operating systems

Cipher Initialization:

#![allow(unused)]
fn main() {
self.cipher = Some(ChaCha20Poly1305::new(&key));
}

The final step establishes the encryption system:

  • ChaCha20Poly1305: Modern authenticated encryption algorithm
  • Key Binding: Cipher is initialized with the user-specific derived key
  • Ready State: System is now ready for encrypt/decrypt operations

Performance Optimization: The function concludes with performance reporting:

  • Timing Analysis: Measures and reports total initialization time
  • Performance Monitoring: Helps identify potential security attacks or system issues
  • User Feedback: Provides transparency about system operations

Error Handling and Security: Throughout the function, comprehensive error handling ensures:

  • Graceful Failure: All errors are properly propagated with descriptive messages
  • Security Logging: Failed operations are logged for security monitoring
  • State Consistency: Partial failures don't leave the system in an inconsistent state
  • Attack Resistance: Error messages don't leak sensitive information

This snippet implements the core cryptographic initialization system for user-specific encrypted storage. The initialize_for_user() function:

Security Setup:

  • Creates user-specific directories: Establishes isolated storage for each user
  • Manages encryption keys: Derives secure keys from user passwords using Argon2
  • Hardware fingerprinting: Binds encryption to specific hardware to prevent unauthorized access

Key Operations:

  • First-time setup: Generates new encryption keys and stores security metadata
  • Existing user login: Verifies password and loads existing encryption configuration
  • Hardware change detection: Identifies and handles hardware modifications gracefully
  • Backward compatibility: Upgrades old metadata formats automatically

Security Features:

  • Password verification: Uses cryptographically secure Argon2 hashing
  • File permissions: Sets restrictive permissions on sensitive files (Unix systems)
  • ChaCha20Poly1305 encryption: Initializes modern, secure cipher for data protection

This is the foundation of the application's security model, ensuring each user's data remains encrypted and tied to their specific device.