Content
To build a robust checker, we need to evaluate several factors. We will use Python’s built-in re (regular expression) module for pattern matching and math for calculating entropy.
Our checker will perform four distinct checks:
Length: The most critical factor.
Character Variety: Does it use lowercase, uppercase, digits, and symbols?
Blacklist Check: Is it a commonly used password?
Entropy Estimation: How long would a computer take to guess it?
Step 1: Importing Libraries
We need a few standard libraries. We will also create a small list of common passwords for demonstration purposes (in a real-world scenario, you would use a file containing millions of entries like rockyou.txt).
python
import re
import math
import time
# A small sample of common passwords for demonstration
COMMON_PASSWORDS = {
"password", "123456", "123456789", "qwerty", "password123",
"admin", "letmein", "welcome", "monkey", "dragon", "master"
}
Step 2: Defining the Checker Class
We will create a class to keep our logic organized. This class will hold the password and perform the checks.
python
class PasswordStrengthChecker:
def __init__(self, password):
self.password = password
self.length = len(password)
self.score = 0
self.feedback = []
def check_common(self):
if self.password.lower() in COMMON_PASSWORDS:
self.feedback.append("❌ This is a very common password. It will be cracked instantly.")
return False
return True
def check_variety(self):
# Check for lowercase, uppercase, digits, and symbols
criteria = {
"lowercase": bool(re.search(r"[a-z]", self.password)),
"uppercase": bool(re.search(r"[A-Z]", self.password)),
"digits": bool(re.search(r"\d", self.password)),
"symbols": bool(re.search(r"[!@#$%^&*(),.?\":{}|<>]", self.password))
}
variety_count = sum(criteria.values())
if variety_count < 3:
self.feedback.append("⚠️ Try adding more variety (uppercase, numbers, or symbols).")
elif variety_count == 4:
self.feedback.append("✅ Great character variety.")
return variety_count
def calculate_entropy(self):
# Estimate pool size based on character types used
pool = 0
if re.search(r"[a-z]", self.password): pool += 26
if re.search(r"[A-Z]", self.password): pool += 26
if re.search(r"\d", self.password): pool += 10
if re.search(r"[!@#$%^&*(),.?\":{}|<>]", self.password): pool += 32
if pool == 0: return 0
# Entropy formula: E = L * log2(R)
entropy = self.length * math.log2(pool)
return entropy
def estimate_crack_time(self):
# Assumes 1 billion guesses per second (modern GPU speed)
entropy = self.calculate_entropy()
if entropy == 0: return "Instant"
combinations = 2 ** entropy
seconds = combinations / 1_000_000_000
# Convert seconds to a readable format
if seconds < 1:
return "Instant"
elif seconds < 60:
return f"{seconds:.2f} seconds"
elif seconds < 3600:
return f"{seconds/60:.2f} minutes"
elif seconds < 86400:
return f"{seconds/3600:.2f} hours"
elif seconds < 31536000:
return f"{seconds/86400:.2f} days"
else:
return f"{seconds/31536000:.2f} years"
def get_strength(self):
# Reset score and feedback
self.score = 0
self.feedback = []
# Check 1: Common Password (Immediate fail)
if not self.check_common():
return "Very Weak", self.feedback
# Check 2: Length (The most important factor)
if self.length < 8:
self.feedback.append("❌ Too short. Aim for at least 12-16 characters.")
return "Weak", self.feedback
elif self.length < 12:
self.score += 1
self.feedback.append("⚠️ Length is okay, but longer is better.")
else:
self.score += 2
self.feedback.append("✅ Good length.")
# Check 3: Variety
variety_score = self.check_variety()
if variety_score >= 3:
self.score += 1
# Final Evaluation
crack_time = self.estimate_crack_time()
self.feedback.append(f"🕒 Estimated crack time: {crack_time}")
if self.score >= 3:
return "Strong", self.feedback
elif self.score == 2:
return "Moderate", self.feedback
else:
return "Weak", self.feedback
Step 3: Running the Checker
Let's test our checker with a few different passwords to see how it performs.
python
def test_password(password):
checker = PasswordStrengthChecker(password)
strength, feedback = checker.get_strength()
print(f"\nPassword: '{password}'")
print(f"Strength: {strength}")
for comment in feedback:
print(f" - {comment}")
# Test cases
test_password("123456")
test_password("Password123!")
test_password("correct-horse-battery-staple-2024")
Analyzing the Results
When you run the code above, you will notice something interesting. The password Password123! might get a "Moderate" rating because it has variety, but it is actually quite weak because it follows a predictable pattern. Our estimate_crack_time function will likely show that a computer could guess it relatively quickly.
On the other hand, correct-horse-battery-staple-2024 is long. Even though it has no uppercase letters and only a few symbols, the sheer length (33 characters) makes the entropy massive. The estimated crack time would be millions of years.
This demonstrates the core lesson: Length is the heavy lifter of password security. Complexity rules (adding a ! or a 1) only marginally increase the search space compared to adding a few more words to your password.