import tkinter as tk
from tkinter import ttk
import math
import re
# ---------------------------
# Heuristics & helpers
# ---------------------------
COMMON_PASSWORDS = {
"password", "123456", "123456789", "qwerty", "abc123",
"letmein", "welcome", "admin", "iloveyou", "monkey"
}
SEQUENCES = [
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"qwertyuiop", "asdfghjkl", "zxcvbnm"
]
def shannon_entropy(password: str) -> float:
"""Approximate entropy based on character sets used."""
pool = 0
if re.search(r"[a-z]", password): pool += 26
if re.search(r"[A-Z]", password): pool += 26
if re.search(r"\d", password): pool += 10
if re.search(r"[^\w\s]", password): pool += 32 # symbols
if pool == 0:
return 0.0
return len(password) * math.log2(pool)
def has_repeats(password: str) -> bool:
return bool(re.search(r"(.)\1{2,}", password)) # aaa, 111
def has_sequence(password: str) -> bool:
p = password
for seq in SEQUENCES:
for i in range(len(seq) - 3):
if seq[i:i+4] in p:
return True
return False
def keyboard_walk(password: str) -> bool:
walks = ["qwerty", "asdf", "zxcv", "poiuy", "lkjhg", "mnbv"]
p = password.lower()
return any(w in p for w in walks)
def analyze_password(password: str):
issues = []
score = 0
# Length
if len(password) < 8:
issues.append("Too short (minimum 8 characters).")
else:
score += min(20, (len(password) - 7) * 3)
# Character classes
classes = 0
classes += bool(re.search(r"[a-z]", password))
classes += bool(re.search(r"[A-Z]", password))
classes += bool(re.search(r"\d", password))
classes += bool(re.search(r"[^\w\s]", password))
score += classes * 10
if classes < 3:
issues.append("Use at least 3 character types (upper/lower/digits/symbols).")
# Entropy
ent = shannon_entropy(password)
score += min(30, int(ent / 3)) # cap contribution
if ent < 40:
issues.append("Low entropy. Add length and variety.")
# Patterns
if password.lower() in COMMON_PASSWORDS:
issues.append("Common password detected.")
score -= 30
if has_repeats(password):
issues.append("Repeated characters detected (e.g., 'aaa').")
score -= 10
if has_sequence(password):
issues.append("Sequential pattern detected (e.g., 'abcd', '1234').")
score -= 10
if keyboard_walk(password):
issues.append("Keyboard pattern detected (e.g., 'qwerty').")
score -= 10
score = max(0, min(100, score))
if score >= 80:
verdict = "Strong"
elif score >= 60:
verdict = "Good"
elif score >= 40:
verdict = "Weak"
else:
verdict = "Very Weak"
return {
"score": score,
"verdict": verdict,
"entropy": round(ent, 1),
"issues": issues
}
# ---------------------------
# GUI
# ---------------------------
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Local Password Strength Analyzer")
self.geometry("520x420")
self.resizable(False, False)
ttk.Label(self, text="Enter Password:", font=("Arial", 12)).pack(pady=10)
self.pw = ttk.Entry(self, show="*", width=40)
self.pw.pack()
self.show_var = tk.BooleanVar(value=False)
ttk.Checkbutton(self, text="Show password", variable=self.show_var,
command=self.toggle_show).pack(pady=5)
ttk.Button(self, text="Analyze", command=self.run).pack(pady=10)
self.score_lbl = ttk.Label(self, text="Score: —", font=("Arial", 12, "bold"))
self.score_lbl.pack()
self.ent_lbl = ttk.Label(self, text="Entropy: — bits")
self.ent_lbl.pack(pady=5)
self.verdict_lbl = ttk.Label(self, text="Verdict: —", font=("Arial", 12))
self.verdict_lbl.pack(pady=5)
ttk.Label(self, text="Feedback:", font=("Arial", 11, "bold")).pack(pady=8)
self.feedback = tk.Text(self, height=8, width=60, wrap="word")
self.feedback.pack(padx=10)
def toggle_show(self):
self.pw.config(show="" if self.show_var.get() else "*")
def run(self):
pwd = self.pw.get()
res = analyze_password(pwd)
self.score_lbl.config(text=f"Score: {res['score']}/100")
self.ent_lbl.config(text=f"Entropy: {res['entropy']} bits")
self.verdict_lbl.config(text=f"Verdict: {res['verdict']}")
self.feedback.delete("1.0", "end")
if res["issues"]:
for i in res["issues"]:
self.feedback.insert("end", f"• {i}\n")
else:
self.feedback.insert("end", "No issues found. Great password!")
if __name__ == "__main__":
App().mainloop()