Of course! Using Python for password-related tasks is a common and powerful use case. However, it's crucial to handle passwords with extreme care, especially when it comes to security.

Let's break this down into three main scenarios:
- Generating Strong Passwords: Creating secure, random passwords.
- Storing Passwords Securely: The absolute DO NOT and the correct way to do it.
- Checking Password Strength: Evaluating how strong a user-provided password is.
Generating Strong Passwords
This is a great use case for Python. We'll use Python's built-in secrets module, which is designed for generating cryptographically strong random numbers suitable for managing data like passwords, account authentication, and security tokens.
Why secrets and not random?
The random module is for modeling and simulation, not for security. The secrets module uses the best source of randomness your operating system can provide, making it unpredictable and secure.
Example: Generate a Password with Letters, Digits, and Symbols
import secrets
import string
import random
def generate_password(length=16):
"""
Generates a cryptographically secure password.
Args:
length (int): The desired length of the password. Defaults to 16.
Returns:
str: The generated password.
"""
# Define the character set
letters = string.ascii_letters # a-z, A-Z
digits = string.digits # 0-9
symbols = string.punctuation # !@#$%^&*()...
# Combine all characters
alphabet = letters + digits + symbols
# Generate a password
# We ensure at least one character from each category
password = [
secrets.choice(letters),
secrets.choice(digits),
secrets.choice(symbols)
]
# Fill the rest of the password with random choices from the full alphabet
for _ in range(length - 3):
password.append(secrets.choice(alphabet))
# Shuffle the list to ensure the first 3 characters aren't predictable
random.shuffle(password)
# Convert the list to a string
return "".join(password)
# --- Usage ---
if __name__ == "__main__":
new_password = generate_password(20)
print(f"Generated Password: {new_password}")
# Example of a shorter password
short_password = generate_password(12)
print(f"Generated Short Password: {short_password}")
Key Takeaways:

secrets.choice(): Picks a random, secure character from a sequence.stringmodule: Provides handy constants likeascii_letters,digits, andpunctuation.random.shuffle(): Used to mix up the characters so the password isn't predictable (e.g., doesn't always start with a letter).
Storing Passwords Securely (The Most Important Part)
This is a critical security rule.
🚫 NEVER DO THIS: Store Plain-Text Passwords
Storing passwords in plain text in a file or database is a massive security risk. If your database is ever compromised, all user passwords will be exposed.
# 🚫 AVOID THIS CODE AT ALL COSTS
import json
# DO NOT store passwords like this
user_credentials = {
"alice": "password123",
"bob": "super_secret_password"
}
with open("users.json", "w") as f:
json.dump(user_credentials, f)
✅ THE CORRECT WAY: Hashing with Salt
The standard and secure practice is to hash passwords. A hash is a one-way function: you can turn a password into a hash, but you can't turn the hash back into the password.
Even better, you should use a salt. A salt is a random piece of data that you add to each password before hashing. This ensures that even if two users have the same password (e.g., "password123"), their stored hashes will be completely different.

We'll use the bcrypt library, which is the gold standard for password hashing. It's slow and computationally expensive, which is a good thing because it makes brute-force attacks much harder.
First, install bcrypt:
pip install bcrypt
Example: Hashing and Verifying Passwords
import bcrypt
import os
def hash_password(password: str) -> str:
"""
Hashes a password using bcrypt with a salt.
Args:
password (str): The plain-text password to hash.
Returns:
str: The hashed password, including the salt.
"""
# Generate a salt. The 'gensalt' function creates a random salt.
# The 'rounds' parameter controls the computational cost (higher is more secure).
salt = bcrypt.gensalt(rounds=12)
# Hash the password
hashed_password = bcrypt.hashpw(password.encode('utf-8'), salt)
# The result is a bytes object, which we can decode to a string for storage
return hashed_password.decode('utf-8')
def check_password(plain_password: str, hashed_password_str: str) -> bool:
"""
Checks if a plain-text password matches a stored hash.
Args:
plain_password (str): The password provided by the user.
hashed_password_str (str): The stored, hashed password string.
Returns:
bool: True if the password matches, False otherwise.
"""
# bcrypt needs the hash to be in bytes for comparison
hashed_password_bytes = hashed_password_str.encode('utf-8')
# Hash the provided password with the salt from the stored hash
# bcrypt.checkpw handles the salt extraction and comparison
return bcrypt.checkpw(plain_password.encode('utf-8'), hashed_password_bytes)
# --- Usage ---
if __name__ == "__main__":
# 1. User registers with a new password
my_password = "a_very_strong_and_secret_password_123!"
hashed_pw = hash_password(my_password)
print(f"Original Password: {my_password}")
print(f"Hashed Password: {hashed_pw}")
# Store this hashed_pw in your database for the user
# 2. User tries to log in
login_attempt_1 = "a_very_strong_and_secret_password_123!"
login_attempt_2 = "wrong_password"
# Check the first attempt (should be True)
is_correct_1 = check_password(login_attempt_1, hashed_pw)
print(f"\nLogin attempt '{login_attempt_1}' is correct: {is_correct_1}")
# Check the second attempt (should be False)
is_correct_2 = check_password(login_attempt_2, hashed_pw)
print(f"Login attempt '{login_attempt_2}' is correct: {is_correct_2}")
Checking Password Strength
This is a different task from security. Here, we're not making the password secure, but we're giving the user feedback on how strong their chosen password is against common attacks (like dictionary attacks or guessing).
This is a heuristic-based approach, not a security measure. The goal is to encourage users to create better passwords.
import re
def check_password_strength(password: str) -> tuple[str, int]:
"""
Evaluates the strength of a password based on common criteria.
Args:
password (str): The password to check.
Returns:
tuple[str, int]: A tuple containing a feedback message and a score (0-5).
"""
score = 0
feedback = []
# Criteria
if len(password) >= 8:
score += 1
else:
feedback.append("Password should be at least 8 characters long.")
if re.search(r"[a-z]", password):
score += 1
else:
feedback.append("Include at least one lowercase letter.")
if re.search(r"[A-Z]", password):
score += 1
else:
feedback.append("Include at least one uppercase letter.")
if re.search(r"\d", password):
score += 1
else:
feedback.append("Include at least one number.")
if re.search(r"[!@#$%^&*(),.?\":{}|<>]", password):
score += 1
else:
feedback.append("Include at least one special character (!, @, #, etc.).")
# Final feedback message
if not feedback:
feedback_message = "Strong password!"
else:
feedback_message = "Weak password. Consider the following:\n" + "\n".join(feedback)
return feedback_message, score
# --- Usage ---
if __name__ == "__main__":
test_passwords = [
"short",
"password",
"Password123",
"P@ssw0rd!",
"ThisIsAVeryLongAndStrongPassword123!"
]
for pwd in test_passwords:
message, strength_score = check_password_strength(pwd)
print(f"\nPassword: '{pwd}'")
print(f"Score: {strength_score}/5")
print(f"Feedback: {message}")
Summary
| Task | Python Tool/Method | Security Level | Purpose |
|---|---|---|---|
| Generating | secrets module |
High | Create unpredictable passwords for users. |
| Storing | bcrypt library |
Critical | Securely store passwords in a database. |
| Checking Strength | re module, heuristics |
Low | Provide user feedback to encourage better passwords. |
