-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpassword_strength.py
More file actions
99 lines (96 loc) · 3.59 KB
/
password_strength.py
File metadata and controls
99 lines (96 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import re
import math
class PasswordStrengthChecker:
def __init__(self, min_length=10):
self.min_length = min_length
def estimate_crack_time(self, password: str) -> str:
# Estimate entropy
charset = 0
if re.search(r'[a-z]', password):
charset += 26
if re.search(r'[A-Z]', password):
charset += 26
if re.search(r'\d', password):
charset += 10
if re.search(r'[^A-Za-z0-9]', password):
charset += 32 # Approximate for special chars
if charset == 0:
charset = 1
entropy = len(password) * math.log2(charset)
# Estimate guesses per second (offline fast attack)
guesses_per_second = 1e10
guesses = 2 ** entropy
seconds = guesses / guesses_per_second
# Convert seconds to human readable
def human_time(seconds):
intervals = [
('years', 60*60*24*365),
('days', 60*60*24),
('hours', 60*60),
('minutes', 60),
('seconds', 1)
]
result = []
for name, count in intervals:
value = int(seconds // count)
if value:
seconds -= value * count
result.append(f"{value} {name}")
if not result:
return "less than a second"
return ', '.join(result[:2])
return human_time(seconds)
def check(self, password: str) -> dict:
feedback = []
score = 0
# Length check
if len(password) >= self.min_length:
score += 1
if len(password) >= 14:
feedback.append("Good password length (14+ characters)")
else:
feedback.append(f"Minimum length met ({self.min_length}+ characters)")
else:
feedback.append(f"Password should be at least {self.min_length} characters long (current: {len(password)})")
# Character diversity checks
checks = [
(r'[A-Z]', "uppercase letter", "Add uppercase letters (A-Z)"),
(r'[a-z]', "lowercase letter", "Add lowercase letters (a-z)"),
(r'\d', "digit", "Include numbers (0-9)"),
(r'[^A-Za-z0-9]', "special character", "Add special characters (!@#$%^&*)"),
(r'.{3,}', "repeating patterns", "Avoid repeated patterns")
]
for pattern, positive_fb, negative_fb in checks[:-1]:
if re.search(pattern, password):
score += 1
else:
feedback.append(negative_fb)
# Check for repeating patterns
if not re.search(r'(.)\1{2,}', password):
score += 0.5
else:
feedback.append("Avoid repeating characters (e.g. 'aaa')")
# Final scoring
score = min(int(score), 5) # Cap at 5
strength_levels = {
5: "Very Strong",
4: "Strong",
3: "Medium",
2: "Weak",
1: "Very Weak",
0: "Insecure"
}
strength = strength_levels.get(score, "Insecure")
# Positive feedback for strong passwords
if score >= 4:
feedback.insert(0, "Good job! Your password is secure")
elif score == 0:
feedback.insert(0, "Immediately change this password - it's extremely vulnerable")
# Crack time estimate
crack_time = self.estimate_crack_time(password)
return {
"score": score,
"strength": strength,
"feedback": feedback,
"crack_time": crack_time
}