#!/usr/bin/env python3 import argparse import hashlib import itertools import string import sys import time from pathlib import Path sys.path.insert(0, str(Path(__file__).parent)) from config import PASSWD_FILE CHARSET = string.ascii_letters + string.digits + "!@#$%^&*()" FIRST_CHARS = string.ascii_letters MAX_HOURS = 8 def hash_password(password: str) -> str: return hashlib.sha256(password.encode("ascii")).hexdigest() def get_target_hash(login: str) -> str | None: if not PASSWD_FILE.exists(): return None with open(PASSWD_FILE) as f: for line in f: parts = line.strip().split(":", 4) if len(parts) == 5 and parts[0] == login: return parts[1] return None def max_combinations(length: int) -> int: if length == 1: return len(FIRST_CHARS) return len(FIRST_CHARS) * (len(CHARSET) ** (length - 1)) def brute_force_length(target_hash: str, length: int) -> tuple[str, int, float] | None: count = 0 start = time.perf_counter() if length == 1: for first in FIRST_CHARS: count += 1 if hash_password(first) == target_hash: return first, count, time.perf_counter() - start return None for first in FIRST_CHARS: for rest in itertools.product(CHARSET, repeat=length - 1): if time.perf_counter() - start > MAX_HOURS * 3600: return None count += 1 password = first + "".join(rest) if hash_password(password) == target_hash: return password, count, time.perf_counter() - start return None def main() -> None: parser = argparse.ArgumentParser(description="Brute force password cracker (SHA-256)") parser.add_argument("login", help="Target username") parser.add_argument( "--max-length", type=int, default=6, help="Maximum password length to try (default: 6)", ) args = parser.parse_args() target_hash = get_target_hash(args.login) if not target_hash: print(f"User '{args.login}' not found in passwd file.") return print(f"Target: {args.login}") print(f"Hash: {target_hash}") print(f"Charset size: {len(CHARSET)} ({len(FIRST_CHARS)} valid for first char)") print(f"Algorithm: SHA-256") print() for length in range(1, args.max_length + 1): total = max_combinations(length) print(f"Length {length}: max {total:>15,} combinations") result = brute_force_length(target_hash, length) if result is not None: password, count, elapsed = result print(f" >>> FOUND: '{password}'") print(f" Iterations: {count:,}") print(f" Time: {elapsed:.4f}s") print(f" Speed: {count / elapsed:,.0f} hashes/s") return else: print(f" Not found at length {length} (timeout or exhausted)") print(f"\nPassword not found within length {args.max_length}.") if __name__ == "__main__": main()