Python Snippets

Password Strength Validator with Feedback

import re
import math
from typing import Tuple, List

def validate_password_strength(password: str) -> Tuple[bool, int, List[str]]:
    """
    Validates password strength and provides feedback.
    
    Args:
        password (str): Password to validate
        
    Returns:
        Tuple[bool, int, List[str]]: (is_valid, score, feedback)
        - is_valid: True if password meets minimum requirements
        - score: Password strength score (0-100)
        - feedback: List of feedback messages
    """
    feedback = []
    score = 0
    
    # Length checks
    length = len(password)
    if length < 8:
        feedback.append("Password must be at least 8 characters long")
    else:
        score += min(25, length * 2)  # Reward longer passwords up to 25 points
    
    # Character variety checks
    has_lower = bool(re.search(r'[a-z]', password))
    has_upper = bool(re.search(r'[A-Z]', password))
    has_digit = bool(re.search(r'[0-9]', password))
    has_special = bool(re.search(r'[^a-zA-Z0-9]', password))
    
    # Award points for character variety
    variety_score = sum([has_lower, has_upper, has_digit, has_special]) * 10
    score += variety_score
    
    # Provide feedback for missing character types
    if not has_lower:
        feedback.append("Add lowercase letters")
    if not has_upper:
        feedback.append("Add uppercase letters")
    if not has_digit:
        feedback.append("Add numbers")
    if not has_special:
        feedback.append("Add special characters (!@#$%^&* etc.)")
    
    # Check for common patterns (deduct points)
    if re.search(r'(.)\1{2,}', password):  # Repeated characters
        score -= 15
        feedback.append("Avoid repeated characters")
    
    if re.search(r'(012|123|234|345|456|567|678|789|890|abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz)', password.lower()):
        score -= 10
        feedback.append("Avoid sequential characters")
    
    # Check for common passwords (simplified)
    common_passwords = ['password', '12345678', 'qwertyui', 'admin123']
    if password.lower() in common_passwords:
        score -= 30
        feedback.append("Do not use common passwords")
    
    # Normalize score
    score = max(0, min(100, score))
    
    # Determine validity (minimum requirements)
    is_valid = (length >= 8 and has_lower and has_upper and has_digit)
    
    # Additional feedback based on score
    if score < 30:
        strength = "Very Weak"
    elif score < 50:
        strength = "Weak"
    elif score < 70:
        strength = "Fair"
    elif score < 90:
        strength = "Good"
    else:
        strength = "Strong"
    
    feedback.insert(0, f"Password strength: {strength} ({score}/100)")
    
    return (is_valid, score, feedback)

def estimate_crack_time(password: str) -> str:
    """
    Estimates how long it would take to crack a password.
    
    Args:
        password (str): Password to analyze
        
    Returns:
        str: Human-readable time estimate
    """
    # Simplified entropy calculation
    charset_size = 0
    if re.search(r'[a-z]', password):
        charset_size += 26
    if re.search(r'[A-Z]', password):
        charset_size += 26
    if re.search(r'[0-9]', password):
        charset_size += 10
    if re.search(r'[^a-zA-Z0-9]', password):
        charset_size += 32  # Rough estimate for special chars
    
    entropy = len(password) * math.log2(charset_size) if charset_size > 0 else 0
    
    # Assume 10 billion attempts per second (modern GPU)
    attempts_per_second = 10**10
    total_combinations = 2**entropy
    seconds_to_crack = total_combinations / (2 * attempts_per_second)  # Average time
    
    # Convert to human-readable format
    if seconds_to_crack < 60:
        return f"{seconds_to_crack:.2f} seconds"
    elif seconds_to_crack < 3600:
        return f"{seconds_to_crack/60:.2f} minutes"
    elif seconds_to_crack < 86400:
        return f"{seconds_to_crack/3600:.2f} hours"
    elif seconds_to_crack < 31536000:
        return f"{seconds_to_crack/86400:.2f} days"
    else:
        years = seconds_to_crack / 31536000
        if years > 1000000:
            return "millions of years"
        return f"{years:.2f} years"

# Example usage
if __name__ == "__main__":
    test_passwords = [
        "password",
        "Password123",
        "MyP@ssw0rd123!",
        "Tr0ub4dor&3",
        "correcthorsebatterystaple",
        "123456789",
        "Qwerty123!"
    ]
    
    for pwd in test_passwords:
        print(f"\nAnalyzing: {pwd}")
        is_valid, score, feedback = validate_password_strength(pwd)
        crack_time = estimate_crack_time(pwd)
        
        print(f"Valid: {is_valid}")
        print(f"Crack time estimate: {crack_time}")
        for item in feedback:
            print(f"  - {item}")

This password strength validator solves the common problem of helping users create secure passwords by providing real-time feedback on password quality. The code evaluates passwords based on multiple criteria:

  1. Length Requirements: Checks if the password meets minimum length requirements (8+ characters)
  2. Character Variety: Analyzes the presence of lowercase, uppercase, digits, and special characters
  3. Pattern Detection: Identifies common weak patterns like repeated characters or sequences
  4. Common Password Detection: Warns against using easily guessable passwords
  5. Strength Scoring: Assigns a numeric score (0-100) and categorical rating (Very Weak to Strong)
  6. Crack Time Estimation: Calculates approximately how long it would take to crack the password with modern hardware

The validator returns three key pieces of information:

To use this snippet, simply call validate_password_strength(password) with any password string. The function returns a tuple containing validation status, a score out of 100, and a list of feedback messages. For even more insight, use estimate_crack_time(password) to see how secure the password is against brute force attacks.

The code is designed to be integrated into signup forms, password change interfaces, or security auditing tools where providing immediate feedback on password strength is essential.