Crpyto-HW7/part2.py
2025-11-25 16:01:49 -06:00

175 lines
5.8 KiB
Python

import hashlib
import itertools
import time
import string
# Define character set: 0-9, a-z, A-Z, and special symbols
CHARACTERS = string.digits + string.ascii_lowercase + string.ascii_uppercase + '#$%^&*'
def generate_salted_sha256_hash(password, salt_bytes):
"""
Generate SHA256 hash of a password concatenated with salt.
Args:
password: The password string
salt_bytes: The salt as bytes
Returns:
SHA256 hash as hexadecimal string
"""
# Concatenate password bytes and salt bytes, then hash
combined = password.encode() + salt_bytes
return hashlib.sha256(combined).hexdigest()
def read_salted_password_database(filename):
"""
Read salted password database from a text file.
Args:
filename: Path to the file containing [username, salt, hash] entries
Returns:
List of [username, salt, hash] entries
"""
database = []
try:
with open(filename, 'r') as f:
for line in f:
line = line.strip()
if line and line.startswith('[') and line.endswith(']'):
# Remove brackets and split by comma
content = line[1:-1]
parts = content.split(',', 2) # Split into max 3 parts
if len(parts) == 3:
username = parts[0].strip()
salt_hex = parts[1].strip()
password_hash = parts[2].strip()
# Convert salt from hex string to bytes
salt_bytes = bytes.fromhex(salt_hex)
database.append([username, salt_bytes, password_hash])
print(f"Loaded {len(database)} accounts from {filename}")
return database
except FileNotFoundError:
print(f"Error: File '{filename}' not found.")
return []
except Exception as e:
print(f"Error reading file: {e}")
return []
def dictionary_attack_salted(password_database, N):
"""
Perform dictionary attack on salted password database.
Args:
password_database: List of [username, salt, hash] entries
N: Length of passwords to try
Returns:
Dictionary mapping usernames to cracked passwords
Time taken for the attack
"""
print(f"\n{'='*60}")
print(f"Starting Dictionary Attack on Salted Hashes")
print(f"Password length: {N}")
print(f"Character set size: {len(CHARACTERS)}")
print(f"Total possible passwords: {len(CHARACTERS)**N}")
print(f"Number of accounts to crack: {len(password_database)}")
print(f"{'='*60}\n")
cracked_passwords = {}
start_time = time.time()
attempts = 0
# For each user, we need to try all possible passwords with their specific salt
for username, salt_bytes, stored_hash in password_database:
print(f"Attacking {username} (salt: {salt_bytes.hex()})...")
user_cracked = False
user_attempts = 0
# Generate all possible passwords of length N
for password_tuple in itertools.product(CHARACTERS, repeat=N):
password = ''.join(password_tuple)
user_attempts += 1
attempts += 1
# Hash the password with this user's salt
password_hash = generate_salted_sha256_hash(password, salt_bytes)
# Check if this hash matches the stored hash
if password_hash == stored_hash:
cracked_passwords[username] = password
print(f"[+] Cracked! {username}: {password} (after {user_attempts} attempts)")
user_cracked = True
break
# Progress indicator for this user
if user_attempts % 10000 == 0:
print(f" Tried {user_attempts} passwords for {username}...")
if not user_cracked:
print(f"[-] Failed to crack {username}")
end_time = time.time()
time_taken = end_time - start_time
print(f"\n{'='*60}")
print(f"Attack Complete!")
print(f"Time taken: {time_taken:.4f} seconds")
print(f"Total attempts: {attempts}")
print(f"Passwords cracked: {len(cracked_passwords)}/{len(password_database)}")
print(f"{'='*60}\n")
return cracked_passwords, time_taken
def main():
"""Main function to run the dictionary attack on salted passwords."""
print("Dictionary Attack on Salted SHA256 Password Hashes")
print("=" * 60)
# Get input file and password length from user
filename = input("Enter password database filename: ")
N = int(input("Enter password length N: "))
# Warn if N is too large
if N > 4:
total_passwords = len(CHARACTERS) ** N
print(f"\nWarning: With N={N}, there are {total_passwords:,} possible passwords.")
print("With salting, each user requires a separate full search!")
confirm = input("Continue? (yes/no): ")
if confirm.lower() != 'yes':
print("Attack cancelled.")
return
# Read password database from file
print("\nReading password database...")
password_database = read_salted_password_database(filename)
if not password_database:
print("No valid data found. Exiting.")
return
print("\nPassword Database:")
for username, salt_bytes, password_hash in password_database:
print(f"[{username}, {salt_bytes.hex()}, {password_hash}]")
# Perform dictionary attack
cracked_passwords, time_taken = dictionary_attack_salted(password_database, N)
# Display results
print("\nRecovered Passwords:")
for username, password in cracked_passwords.items():
print(f"{username}: {password}")
print(f"\nTotal time needed: {time_taken:.4f} seconds")
if __name__ == "__main__":
main()