comparison shasum.py @ 7:47b4c98e4d40

Allow algorithm selection for all algorithms in :mod:`hashlib`. Besides of the name "shasum" the MD5, BLAKE2b, BLAKE2s and SHA-3 variants are implemented.
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 04 Dec 2020 15:16:20 +0100
parents a21e83c855cc
children 048b97213a23
comparison
equal deleted inserted replaced
6:a21e83c855cc 7:47b4c98e4d40
25 def main(argv=None): 25 def main(argv=None):
26 aparser = argparse.ArgumentParser( 26 aparser = argparse.ArgumentParser(
27 description="Python implementation of shasum", 27 description="Python implementation of shasum",
28 fromfile_prefix_chars='@') 28 fromfile_prefix_chars='@')
29 aparser.add_argument( 29 aparser.add_argument(
30 "--algorithm", "-a", action="store", type=argv2algo,
31 help="1, 224, 256 (default), 384, 512, 3-224, 3-256, 3-384, 3-512, blake2b, blake2s, md5")
32 aparser.add_argument(
30 "--binary", "-b", action="store_false", dest="text_mode", default=False, 33 "--binary", "-b", action="store_false", dest="text_mode", default=False,
31 help="read in binary mode (default)") 34 help="read in binary mode (default)")
32 aparser.add_argument( 35 aparser.add_argument(
33 "--bsd", "-B", action="store_true", 36 "--bsd", "-B", action="store_true",
34 help="write BSD style output") 37 help="write BSD style output")
42 45
43 if opts.text_mode: 46 if opts.text_mode:
44 print("ERROR: text mode not supported", file=sys.stderr) 47 print("ERROR: text mode not supported", file=sys.stderr)
45 sys.exit(78) # :manpage:`sysexits(3)` EX_CONFIG 48 sys.exit(78) # :manpage:`sysexits(3)` EX_CONFIG
46 49
50 if not opts.algorithm:
51 opts.algorithm = argv2algo("256")
52
47 if opts.bsd: 53 if opts.bsd:
48 out = out_bsd 54 out = out_bsd
49 else: 55 else:
50 out = out_std 56 out = out_std
51 57
58 msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) 64 msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
59 source = sys.stdin 65 source = sys.stdin
60 else: 66 else:
61 source = sys.stdin.buffer 67 source = sys.stdin.buffer
62 out(sys.stdout, 68 out(sys.stdout,
63 compute_digest(hashlib.sha256, source), 69 compute_digest(opts.algorithm[0], source),
64 None, 70 None,
65 "SHA256", 71 opts.algorithm[1],
66 True) 72 True)
67 else: 73 else:
68 for fn in opts.files: 74 for fn in opts.files:
69 with open(fn, "rb") as source: 75 with open(fn, "rb") as source:
70 out(sys.stdout, 76 out(sys.stdout,
71 compute_digest(hashlib.sha256, source), 77 compute_digest(opts.algorithm[0], source),
72 fn, 78 fn,
73 "SHA256", 79 opts.algorithm[1],
74 True) 80 True)
81
82
83 def argv2algo(s):
84 """Convert a commane line algorithm specifier into a tuple with the
85 type/factory of the digest and the algorithms tag for output purposes
86
87 :param str s: the specifier from the commane line
88 :return: the internal digest specification
89 :rtype: a tuple (digest_type_or_factory, name_in_output)
90
91 String comparisons are done case-insensitively.
92
93 """
94 s = s.lower()
95 if s in ("1", "sha1"):
96 return (hashlib.sha1, "SHA1")
97 elif s in ("224", "sha224"):
98 return (hashlib.sha224, "SHA224")
99 elif s in ("256", "sha256"):
100 return (hashlib.sha256, "SHA256")
101 elif s in ("384", "sha384"):
102 return (hashlib.sha384, "SHA384")
103 elif s in ("512", "sha512"):
104 return (hashlib.sha512, "SHA512")
105 elif s in ("3-224", "sha3-224"):
106 return (hashlib.sha3_224, "SHA3-224")
107 elif s in ("3-256", "sha3-256"):
108 return (hashlib.sha3_256, "SHA3-256")
109 elif s in ("3-384", "sha3-384"):
110 return (hashlib.sha3_384, "SHA3-384")
111 elif s in ("3-512", "sha3-512"):
112 return (hashlib.sha3_512, "SHA3-512")
113 elif s in ("blake2b", "blake2b-512"):
114 return (hashlib.blake2b, "BLAKE2b")
115 elif s in ("blake2s", "blake2s-256"):
116 return (hashlib.blake2s, "BLAKE2s")
117 elif s == "md5":
118 return (hashlib.md5, "MD5")
119 else:
120 raise argparse.ArgumentTypeError(
121 "`{}' is not a recognized algorithm".format(s))
75 122
76 123
77 def out_bsd(dest, digest, filename, digestname, binary): 124 def out_bsd(dest, digest, filename, digestname, binary):
78 if filename is None: 125 if filename is None:
79 print(digest, file=dest) 126 print(digest, file=dest)