diff --git a/hash.py b/hash.py new file mode 100644 index 0000000..00fd0bd --- /dev/null +++ b/hash.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +import argparse +import hashlib +import sys +from pathlib import Path + +DEFAULT_BLOCK_SIZE = 1024 * 1024 # 1 MB +SUPPORTED_ALGOS = ["md5", "sha1", "sha224", "sha256"] + +def compute_hash(path: Path, algorithm: str, block_size: int = DEFAULT_BLOCK_SIZE) -> str: + """Compute the hash of a file using the chosen algorithm.""" + try: + h = hashlib.new(algorithm) + except ValueError: + raise SystemExit(f"Error: Unsupported hash algorithm '{algorithm}'") + + with path.open("rb") as f: + for chunk in iter(lambda: f.read(block_size), b""): + h.update(chunk) + + return h.hexdigest() + +def main(): + parser = argparse.ArgumentParser( + description="Compute hash(es) of a file or verify against a known hash." + ) + parser.add_argument("file", type=Path, help="Path to the file to hash") + parser.add_argument( + "known_hash", + nargs="?", + help="Optional known hash to verify the file against", + ) + + parser.add_argument("-md5", action="store_true", help="Use MD5 algorithm") + parser.add_argument("-sha1", action="store_true", help="Use SHA-1 algorithm") + parser.add_argument("-sha224", action="store_true", help="Use SHA-224 algorithm") + parser.add_argument("-sha256", action="store_true", help="Use SHA-256 algorithm") + + args = parser.parse_args() + + if not args.file.exists() or not args.file.is_file(): + print(f"Error: File not found -> {args.file}", file=sys.stderr) + sys.exit(1) + + selected_algos = [ + algo + for algo, used in { + "md5": args.md5, + "sha1": args.sha1, + "sha224": args.sha224, + "sha256": args.sha256, + }.items() + if used + ] + + if not selected_algos: + selected_algos = ["sha1"] if args.known_hash else SUPPORTED_ALGOS + + print() + if args.known_hash: + # Verification mode + algo = selected_algos[0] + digest = compute_hash(args.file, algo) + print(f"{algo.upper()} hash: {digest}") + if digest.lower() == args.known_hash.lower(): + print("\033[32mCorrect\033[0m") + print("") + sys.exit(0) + else: + print("\033[31mIncorrect\033[0m") + print("") + sys.exit(1) + else: + # Normal hashing mode + print("Algorithm Hash") + print("--------- ----") + for algo in selected_algos: + digest = compute_hash(args.file, algo) + print(f"{algo.upper():<8} {digest}") + print() + +if __name__ == "__main__": + main()