Some time ago I've made a little command line utility for myself. Download it if you find it useful.
The program was never published before (or signed) so it may be detected as malware (at least VirusTotal says so).
It's written in Python 3. This is the source:
# -*- coding: utf-8 -*-
import os.path
import pprint
import time
import json
import sys
import re
import hashlib
import zlib
import sha3 # This adds sha_3 functions to the hashlib module, install with 'pip install pysha3'
class crc32(object):
name = 'crc32'
digest_size = 4
block_size = 1
def __init__(self, arg=''):
arg = arg.encode()
self.__digest = 0
self.update(arg)
def copy(self):
copy = super(self.__class__, self).__new__(__class__)
copy.__digest = self.__digest
return copy
def digest(self):
return self.__digest
def hexdigest(self):
return '{:08x}'.format(self.__digest)
def update(self, arg):
self.__digest = zlib.crc32(arg, self.__digest) & 0xffffffff
hashlib.crc32 = crc32
def md4File(path, block_size=256*128):
md4 = hashlib.new("md4")
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
md4.update(chunk)
return md4.hexdigest()
def md5File(path, block_size=256*128):
md5 = hashlib.md5()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
md5.update(chunk)
return md5.hexdigest()
def sha1File(path, block_size=256*128):
sha1 = hashlib.sha1()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
sha1.update(chunk)
return sha1.hexdigest()
def crc32File(path, block_size=256*128):
crc32 = hashlib.crc32()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
crc32.update(chunk)
return crc32.hexdigest()
def sha224File(path, block_size=256*128):
sha224 = hashlib.sha224()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
sha224.update(chunk)
return sha224.hexdigest()
def sha256File(path, block_size=256*128):
sha256 = hashlib.sha224()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
sha256.update(chunk)
return sha256.hexdigest()
def sha384File(path, block_size=256*128):
sha384 = hashlib.sha384()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
sha384.update(chunk)
return sha384.hexdigest()
def sha512File(path, block_size=256*128):
sha512 = hashlib.sha512()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
sha512.update(chunk)
return sha512.hexdigest()
def ripemd160File(path, block_size=256*128):
rmd160 = hashlib.new("ripemd160")
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
rmd160.update(chunk)
return rmd160.hexdigest()
def dsaFile(path, block_size=256*128):
dsa = hashlib.new("dsa")
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
dsa.update(chunk)
return dsa.hexdigest()
def whirlpoolFile(path, block_size=256*128):
wrp = hashlib.new("whirlpool")
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
wrp.update(chunk)
return wrp.hexdigest()
def sha3_224File(path, block_size=256*128):
sha3_224 = hashlib.sha3_224()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
sha3_224.update(chunk)
return sha3_224.hexdigest()
def sha3_256File(path, block_size=256*128):
sha3_256 = hashlib.sha3_256()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
sha3_256.update(chunk)
return sha3_256.hexdigest()
def sha3_384File(path, block_size=256*128):
sha3_384 = hashlib.sha3_384()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
sha3_384.update(chunk)
return sha3_384.hexdigest()
def sha3_512File(path, block_size=256*128):
sha3_512 = hashlib.sha3_512()
with open(path,'rb') as f:
for chunk in iter(lambda: f.read(block_size), b''):
sha3_512.update(chunk)
return sha3_512.hexdigest()
def getJson(results):
jdump = json.dumps(results, ensure_ascii=False)
return re.sub('[^\s!-~]', '?', jdump)
def getString(results):
text = ""
for i in results:
text += "File: " + i + "\n"
for j in results[i]:
text += j[0] + ": " + j[1] + "\n"
text += "\n"
return re.sub('[^\s!-~]', '?', text[:-2])
def showHelp(name):
nameT = name.replace("\\","/").split("/")[-1]
helpText = """
//////////////////////
/ File/Folder hasher /
//////////////////////
Usage: %s path [-md4] [-md5]
[-sha1] [-crc32]
[-sha224] [-sha256]
[-sha384] [-sha512]
[-ripemd160] [-whirlpool]
[-sha3_224] [-sha3_256]
[-sha3_384] [-sha3_512]
[-all]
[-file <file name>]
[-json]
Options:
path Path to file or directory to hash
-all Use all hash algorithms.
-file Save hash report to a text file
-json Format output in json
Hash algorithm options:
-md4
-md5
-sha1
-crc32
-sha224
-sha256
-sha384
-sha512
-ripemd160
-whirlpool
-sha3_224
-sha3_256
-sha3_384
-sha3_512
"""
print(helpText % nameT)
def main():
args = sys.argv
if len(args) < 3:
print("Not enough arguments!")
showHelp(args[0])
sys.exit(1)
allowed = [
"-file",
"-all",
"-md4",
"-md5",
"-sha1",
"-crc32",
"-sha224",
"-sha256",
"-sha384",
"-sha512",
"-ripemd160",
"-whirlpool",
"-json",
"-raw",
"-sha3_224",
"-sha3_256",
"-sha3_384",
"-sha3_512",
]
hashes = [
"-md4",
"-md5",
"-sha1",
"-crc32",
"-sha224",
"-sha256",
"-sha384",
"-sha512",
"-ripemd160",
"-whirlpool",
"-sha3_224",
"-sha3_256",
"-sha3_384",
"-sha3_512",
]
dataContain = [
"-file",
]
b = 2
for i in args[b:]:
if args.count(i) > 1:
print("Repeating options: " + i)
showHelp(args[0])
sys.exit(1)
if not i in allowed and args[b-1] not in dataContain:
print("Invalid option: " + i)
print(args[b+1])
showHelp(args[0])
sys.exit(1)
b += 1
else:
if args[-1] in dataContain:
print("'%s' option must have a file path next to it." % i)
showHelp(args[0])
sys.exit(1)
for i in args[2:]:
if i in hashes + ["-all"]:
break
else:
print("No hashes specified.")
showHelp(args[0])
sys.exit(1)
collisions = {
"-all" : ["-md4", "-md5", "-sha1",
"-crc32", "-sha224", "-sha256",
"-sha384", "-sha512", "-ripemd160",
"-whirlpool", "-sha3_224", "-sha3_256",
"-sha3_384", "-sha3_512",]
}
for i in collisions:
if i in args:
for j in collisions[i]:
if j in args:
print("Colliding options. (" + i + " and " + j + ")")
showHelp(args[0])
sys.exit(1)
fileName = args[1]
fileNameT = fileName.replace("\\", "/").split("/")[-1]
if os.path.isfile(fileName):
ftype = "file"
elif os.path.isdir(fileName):
ftype = "directory"
else:
print("File or directory does not exits or you don't have permission to read it.")
showHelp(args[0])
sys.exit(1)
funcTable = {
"-md4" : ("MD4", md4File),
"-md5" : ("MD5", md5File),
"-sha1" : ("SHA1", sha1File),
"-crc32" : ("CRC32", crc32File),
"-sha224" : ("SHA224", sha224File),
"-sha256" : ("SHA256", sha256File),
"-sha384" : ("SHA384", sha384File),
"-sha512" : ("SHA512", sha512File),
"-ripemd160" : ("Ripemd160", ripemd160File),
"-whirlpool" : ("Whirlpool", whirlpoolFile),
"-sha3_224" : ("SHA3-224", sha3_224File),
"-sha3_256" : ("SHA3-256", sha3_256File),
"-sha3_384" : ("SHA3-384", sha3_384File),
"-sha3_512" : ("SHA3-512", sha3_512File),
}
funcList = []
if "-all" in args:
for i in hashes:
funcList.append(funcTable[i])
else:
for i in hashes:
if i in args:
funcList.append(funcTable[i])
try:
if ftype == "file":
print("Hashing...\n")
results = {}
results[fileNameT] = []
st = time.time()
try:
for function in funcList:
hash = function[1](fileName)
results[fileNameT].append([function[0], hash])
except KeyboardInterrupt:
print("Hashing canceled.")
sys.exit(2)
except PermissionError:
print("You don't have permission to access the file.")
showHelp(args[0])
sys.exit(2)
et = time.time()
if "-json" in args:
strResults = getJson(results)
elif "-raw" in args:
strResults = results
else:
strResults = getString(results)
if "-file" in args:
print("Writing file...")
f = open(args[args.index("-file") + 1], "w")
f.write(strResults)
f.close()
print("File saved sucessfully in %s seconds." % str("{0:.2f}".format(et-st)))
else:
print(strResults)
print("\nCalculated in %s seconds." % str("{0:.2f}".format(et-st)))
sys.exit(0)
else:
filenum = 0
print("Scanning files...")
st = time.time()
try:
for subdir, dirs, files in os.walk(fileName):
for file in files:
filenum += 1
except KeyboardInterrupt:
print("Files not scanned. Progress cannot be tracked.")
filenum = -1
if filenum == 0:
print("Directory is empty or you don't have permission to read it.")
showHelp(args[0])
sys.exit(1)
print("Number of files: " + str(filenum))
print("Hashing...\n")
results = {}
onfile = 1
passed = 0
try:
if filenum == -1:
print(" | Hashing... | ???%", end="\r")
for subdir, dirs, files in os.walk(fileName):
for file in files:
results[os.path.join(subdir, file)] = []
if filenum != -1:
perc = onfile/filenum
percnum = "{0:.2f}".format(perc*100)
toprint = " |" + ("#" * int((20*perc))) + " " * int(20-int(20*perc)) + "| " + percnum + "%"
print(toprint, end="\r")
for function in funcList:
try:
try:
hash = function[1](os.path.join(subdir, file))
results[os.path.join(subdir, file)].append([function[0], hash])
except PermissionError:
results[os.path.join(subdir, file)].append(["Error", "Access denied"])
passed += 1
except FileNotFoundError:
results[os.path.join(subdir, file)].append(["Error", "File not found"])
passed += 1
except Exception as e:
results[os.path.join(subdir, file)].append(["Error", str(e)])
passed += 1
onfile += 1
else:
print(" |####################| 100% \n")
except KeyboardInterrupt:
print("Hashing canceled. ")
sys.exit(2)
et = time.time()
print("Passed %s files" % str(passed))
if "-json" in args:
strResults = getJson(results)
elif "-raw" in args:
strResults = results
else:
strResults = getString(results)
if "-file" in args:
print("Writing file...")
f = open(args[args.index("-file") + 1], "wb")
f.write(strResults.encode())
f.close()
print("\nFile saved sucessfully in %s seconds." % str("{0:.2f}".format(et-st)))
else:
print(strResults)
print("\nCalculated in %s seconds." % str("{0:.2f}".format(et-st)))
sys.exit(0)
except MemoryError:
print("Maximum memory reached. Please consider using an x64 version of the program and upgrading your RAM.\n")
if __name__ == "__main__":
main()
It can hash a file or a folder with these algorithms:
The nice thing with this is that you can easily make a .bat file to automate it.
If you actually need this program, but trust your antivirus more than me, compile the above source with pyinstaller.
- Install python 3 (watch out for 32bit/64bit versions)
- Install pyinstaller:
pip install pyinstaller
- Save source to a file called hasher.py
- Run the command:
pyinstaller hasher.py
4.5 Opotionally run: pyinstaller hasher.py --onefile
if you want just a single file executable
- Profit
Note that the compatibility of the compiled exe was not tested because I don't have time.
Click me for download.