import crypt; import argparse def check_password(hashed, password): """ Check if the provided password matches the hashed password. :param hashed: The hashed password to check against. :param password: The plain text password to verify. :return: True if the password matches the hash, False otherwise. """ return crypt.crypt(password, hashed) == hashed def algorithm_name(identifier): """ Get the name of the algorithm based on the identifier. :param identifier: The identifier for the algorithm. :return: The name of the algorithm. """ algorithms = { '1': 'MD5', '2a': 'bcrypt Blowfish (older)', '2b': 'bcrypt Blowfish (newer)', '2y': 'bcrypt Blowfish (php variant)', 'y': 'bcrypt Blowfish (rare, newer systems/libs, e.g, Ubuntu 24.04)', '5': 'SHA-256', '6': 'SHA-512', '*': 'Account disabled/locked', '!': 'Password disabled (block login with a password)', } return algorithms.get(identifier, 'unknown') def main(): parser = argparse.ArgumentParser( description="Check password against hash", epilog="\n".join( [ "Example:", ' python validate.py --hashed "$6$tJlbId$SomeHash" --password "mypassword"', ' python validate.py --parse --hashed "$6$tJlbId$SomeHash"', "", ] ), formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument('--hashed', required=True, help='The hashed password') parser.add_argument('--password', required=False, help='The plain password') parser.add_argument('--parse', required=False, help='Parse the hash and print its components', action='store_true') args = parser.parse_args() if args.parse and not args.hashed: parser.error("You must provide a hashed password to parse.") splitted = args.hashed.split('$') if len(splitted) < 3: parser.error("Invalid hash format. Expected format: $$$") algo = splitted[1] if len(splitted) > 0 else 'unknown' salt = splitted[2] if len(splitted) > 1 else 'unknown' hash = splitted[3] if len(splitted) > 2 else 'unknown' if args.parse: algo_name = algorithm_name(algo) print(f"Hashed: {args.hashed}") print(f"Algorithm: ({algo}) '{algo_name}'") print(f"Salt: {salt}") print(f"Hash: {hash}") return if not args.password: parser.error("You must provide a password to check against the hash.") print(f"Hashed: {args.hashed}") print(f"Password: {args.password}") print(f"Algorithm: {algo}") print(f"Salt: {salt}") print(f"Hash: {hash}") print(f"Match: {check_password(args.hashed, args.password)}") if __name__ == "__main__": main()