Cybersecurity Knowledge Hub

Expert articles, practical guides, and threat analysis — written for professionals and enthusiasts who want to stay secure online.

← All stories
Cyber Security

cracking passwords

In the digital age, password security is the first line of defense against cyber threats. While we all know we should use strong passwords, the definition of "strong" has evolved significantly over the years. Many users still rely on the outdated "Password1!" style complexity rules, which offer surprisingly little protection against modern cracking tools.

We have all been there: creating a new account, only to be stopped by a red bar telling us our password isn't strong enough. We then proceed to add an exclamation point and a number to the end of our dog's name, and suddenly, we are "secure." But are we?
The traditional advice of using uppercase letters, numbers, and symbols (often called "complexity rules") was designed to increase the mathematical possibilities. However, human nature is predictable. When forced to add complexity, we typically use the same patterns: Password123! or Admin2024#. Hackers know these patterns.
Modern cybersecurity experts, including the National Institute of Standards and Technology (NIST), have shifted their stance. They now argue that length and uniqueness matter far more than arbitrary complexity rules. A 20-character passphrase like correct-horse-battery-staple is infinitely harder for a computer to crack than P@ssw0rd, yet it is easier for a human to remember.
In this blog, we will build a Python tool that checks a password's length, character variety, and prevalence in known data breaches. We will also write a function to estimate how long a brute-force attack would take. Let's dive into the code.

The Logic Behind the Code

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:

1.    Length: The most critical factor.

2.    Character Variety: Does it use lowercase, uppercase, digits, and symbols?

3.    Blacklist Check: Is it a commonly used password?

4.    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.


Conclusion

Building your own tools is one of the best ways to understand the technology that governs our digital lives. By creating this Password Strength Checker in Python, we have peeled back the curtain on how security systems evaluate our credentials.
The key takeaway from this project is a shift in mindset. We need to move away from the "complexity theater" of the early 2000s. A password like P@ssw0rd! is technically complex but practically useless against a dictionary attack. Conversely, a long, unique passphrase offers superior protection.
Actionable Takeaways:
1. Prioritize Length: Aim for 16+ characters. A long password is exponentially harder to crack than a short, complex one.
2. Uniqueness Matters: Never reuse passwords. If one site is breached, your other accounts are vulnerable. Use a password manager to generate and store unique, random strings.
3. Use Passphrases: For passwords you must remember, use a string of random words (e.g., BlueCarpetRunningFast). It is easy for you to remember but hard for a computer to guess.
You can extend the code we wrote today by adding a GUI using Tkinter, or by integrating a larger database of compromised passwords via an API like "Have I Been Pwned." The possibilities are endless, and the knowledge you gain is invaluable. Stay secure