commit f2d2aad26016fd3cdd76281d7a6240f3d20701fa Author: JISAUAY Date: Tue Nov 25 16:01:49 2025 -0600 init diff --git a/part1.py b/part1.py new file mode 100644 index 0000000..487110e --- /dev/null +++ b/part1.py @@ -0,0 +1,165 @@ +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_sha256_hash(password): + """Generate SHA256 hash of a password.""" + return hashlib.sha256(password.encode()).hexdigest() + + +def read_password_database(filename): + """ + Read password database from a text file. + + Args: + filename: Path to the file containing [username, hash] pairs + + Returns: + List of [username, hash] pairs + """ + 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(',', 1) # Split only on first comma + if len(parts) == 2: + username = parts[0].strip() + password_hash = parts[1].strip() + database.append([username, 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(password_database, N): + """ + Perform dictionary attack on password database. + + Args: + password_database: List of [username, hash] pairs + 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") + 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") + + # Create a dictionary of hash -> username for faster lookup + hash_to_user = {entry[1]: entry[0] for entry in password_database} + cracked_passwords = {} + + start_time = time.time() + attempts = 0 + + # Generate all possible passwords of length N + for password_tuple in itertools.product(CHARACTERS, repeat=N): + password = ''.join(password_tuple) + attempts += 1 + + # Hash the password + password_hash = generate_sha256_hash(password) + + # Check if this hash matches any in the database + if password_hash in hash_to_user: + username = hash_to_user[password_hash] + cracked_passwords[username] = password + print(f"[+] Cracked! {username}: {password}") + + # If all passwords are cracked, we can stop + if len(cracked_passwords) == len(password_database): + break + + # Progress indicator (every 10000 attempts for small N, adjust as needed) + if attempts % 10000 == 0: + print(f"Tried {attempts} passwords...") + + 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 demonstration.""" + print("Dictionary Attack on 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("This may take a very long time!") + 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_password_database(filename) + + if not password_database: + print("No valid data found. Exiting.") + return + + print("\nPassword Database:") + for username, password_hash in password_database: + print(f"[{username}, {password_hash}]") + + # Perform dictionary attack + cracked_passwords, time_taken = dictionary_attack(password_database, N) + + # Display results + print("\nResults:") + for username, password in cracked_passwords.items(): + print(f"{username}: {password}") + + print(f"\nTotal time: {time_taken:.4f} seconds") + + +if __name__ == "__main__": + main() + + + + + + + + + diff --git a/part2.py b/part2.py new file mode 100644 index 0000000..90195b2 --- /dev/null +++ b/part2.py @@ -0,0 +1,174 @@ +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()