Skip to content

Commit

Permalink
Push
Browse files Browse the repository at this point in the history
  • Loading branch information
ihaveroot committed Feb 17, 2023
1 parent fe6bc3c commit 907a846
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 1 deletion.
287 changes: 287 additions & 0 deletions Hashcheck.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
# Hashcheck.py
#
# This program will get the hash of a specified file
# and compares it to the hash stored in the clipboard.
# This uses the most common file hashing algorithms when
# verifying files.
#
# This program assumes you've copied the hash of a file
# before running.
#
# If you'd like to add alternative hashing algorithms
# you can do so by adding the library and use the template
# in the `compute_file_hash` function.
#
# If you have added a new hashing algorithm in the
# `compute_file_hash` function you must add it in order
# in the `hash_types` array in the `assign` function.
# I'm sure you can figure it out. If you're calculating
# the `foobar` hash before the `blake2b` hash in the
# `compute_file_hash` function then the `foobar` string
# must come before the `blake2b` string in the assign function.
#
# If the `foobar` hash you're adding is a different length.
# you must modify the mapping variable in the
# `display_confidence_hashes` pertaining to the position
# of the `foobar` hash in the `list` variable in `assign`.
#
# The last point in the program is the check between the
# generated hash as well as the hash stored in your
# clipboard. You will need to add the check if you had
# added a library into this program.
#
#
import re
import os
import sys
import zlib
import tqdm
import hashlib
import pyperclip
from termcolor import colored
from colorama import just_fix_windows_console



def banner():
print(colored("\n\t __ __ __ __ __ \n", "magenta") +
colored("\t / / / /_created__/ /_ _by__/ /_ ihaveroot_/ /__\n", "magenta") +
colored("\t / /_/ / __ `/ ___/ __ \/ ___/ __ \/ _ \/ ___/ //_/\n", "magenta") +
colored("\t / __ / /_/ (__ ) / / / /__/ / / / __/ /__/ ,< \n", "cyan") +
colored("\t/_/ /_/\__,_/____/_/ /_/\___/_/ /_/\___/\___/_/|_| \n", "cyan") +
"{:>55}\n".format("ver 1.0"),
"\tSupported hashes: MD5, SHA-1, SHA256, SHA512, BLAKE2s, BLAKE2b\n\n")


# Function to compute the hash of a file
def compute_file_hash(file_name, hash_type):
with open(file_name, 'rb') as file:
if hash_type == 'MD5':
hash_func = hashlib.md5()
elif hash_type == 'SHA-1':
hash_func = hashlib.sha1()
elif hash_type == 'SHA256':
hash_func = hashlib.sha256()
elif hash_type == 'SHA512':
hash_func = hashlib.sha512()
elif hash_type == 'BLAKE2s':
hash_func = hashlib.blake2s()
#elif hash_type == 'foobar':
# hash_func = library.hashing_algorithm()
elif hash_type == 'BLAKE2b':
hash_func = hashlib.blake2b()
else:
# Check speeling of hash_type being called
raise ValueError(f"Unsupported hash type: {hash_type}")
buffer_size = 65536
buffer = file.read(buffer_size)
# tqdm progress bar, Flair
pbar = tqdm.tqdm(total = round(os.path.getsize(file_name) / buffer_size) + 1, desc = f"Calculating {hash_type.upper()} hash", leave = False, ncols=100)
while len(buffer) > 0:
hash_func.update(buffer)
buffer = file.read(buffer_size)
pbar.update(1)
return hash_func.hexdigest()


# Function to compute the CRC32 checksum
def compute_crc32_checksum(file_name):
# Open the file in binary mode
with open(file_name, 'rb') as f:
# Read the contents of the file
data = f.read()
zlib.crc32(data)
# Calculate the CRC32 checksum of the file's contents
crc = zlib.crc32(data)
# Return the CRC32 checksum
return crc


# Compare Strings
# Compares both string hashes and checks
# whether both characters are the same. If
# they are then output it in green, if not
# then output it in red
def compare_strings(clipboard_hash, hash_string):
# Print the hash from the clipboard
print("{:>5} Hash from clipboard: ".format(""), end = "")

# Compare each character from the clipboard_hash
# and the hash in the list. If it matches,
# color it green, if not then red
for y, w in zip(clipboard_hash, hash_string):
if y == w:
print(colored(y, 'green'), end = "")
else:
print(colored(y, 'red'), end = "")
print("\n")


# Confidence Level
# Compares both string hashes and checks
# whether both characters are the same. If
# they are then increase confidence level
def confidence_level(clipboard_hash, list):
confidence = 0
for x, w in zip(clipboard_hash, list):
if x == w:
confidence += 1
return round(confidence / len(clipboard_hash) * 100)


# Hash Confidence
# Output the hash that has the most character similarities
# Just some fun flair
def display_confidence_hashes(clipboard_hash, list):
# Map the lengths of clipboard_hash to the corresponding elements in list and their confidence levels
hash_length_map = {
128: [list[3][1], list[5][1]],
64: [list[2][1], list[4][1]],
40: [list[1][1], list[1][1]],
32: [list[0][1], list[0][1]],
# foobar hash length of 16
# foobar hash is in the 5th
# position, and the hash is
# in the first array.
#16: [list[5][1], list[5][1]]
}

# Get the element in list and confidence level for the length of clipboard_hash
hash_string, hash_string2 = hash_length_map.get(len(clipboard_hash), [None, None])

# Break out from display if there is no hash, or value in clipboard is invalid
if hash_string is None:
print(colored('Warning', 'yellow') + ": The value in the clipboard is not a hash that this program identifies. Check your clipboard\n"
"\tSupported hashes: MD5, SHA-1, SHA256, SHA512, BLAKE2s, BLAKE2b\n")
return

# Calculate the confidence level for the element in list
confidence = confidence_level(clipboard_hash, hash_string)
if confidence <= 50:
confidence = confidence_level(clipboard_hash, hash_string2)
hash_string = hash_string2

# Find the index of the element in list that is the same as hash_string
index = -1
for a, b in enumerate(list):
if b[1] == hash_string:
index = a
break

# Print the confidence level and the relevant hash in list
print(f"Confidence: {confidence}%")
print("{0[0]:>12} hash of file: {0[1]}".format(list[index], list[index]))
compare_strings(clipboard_hash, hash_string)


# Display match, if not then display that
# there is no match or if what user has
# in their clipboard isn't a hash type
# display what they currently have copied
def display(nohash, list, clipboard_hash):
match = False

for name, hash in list:
if hash == clipboard_hash:
print("[", colored('O', 'green'), "] The hash matches the", colored(name, 'blue', 'on_white'), "hash of the file.\n")
match = True
return
if not match:
if nohash == 0:
print("[", colored('X', 'red'), "] The hash does not match any of the calculated file hashes.\n")
elif nohash == 1:
print(colored('Info', 'yellow') + ": Current clipboard contents (128 chars shown): {:.128}\n".format(clipboard_hash))


# Assign the calculated hashes to
# the corresponding hash_type in list
def assign(file_name):
hash_types = ['MD5',
'SHA-1',
'SHA256',
'SHA512',
'BLAKE2s',
#'FOOBAR',
'BLAKE2b']
list = []

for hash_type in hash_types:
hash_value = compute_file_hash(file_name, hash_type)
list.append([hash_type, hash_value])
print(f"\t[{colored('O', 'green')}] {hash_type} hash calculation finished.")

print("\t[" + colored('-', 'yellow') + f"] Calculating CRC32 checksum", end = "\r")
crc32_hash = compute_crc32_checksum(file_name)
print("\t[" + colored('O', 'green') + f"] CRC32 checksum finished.{'':5s}")

return list, crc32_hash


def main():
# Throw error if no file is supplied
if len(sys.argv) < 2:
print("\nError: incorrect number of arguments. Usage: Hashcheck.py <file_name/path to file>")
os.system('pause')
return 1

# Get the file to be checked
file_name = sys.argv[1]

# Use Colorama to make Termcolor work on Windows
just_fix_windows_console()

# Flair
banner()

try:
# Get the hash from the clipboard
clipboard_hash = pyperclip.paste().replace(" ", "")

# If clipboard hash doesn't match the hash algorithm type
# continue anyway to generate hash types for the file
if re.match(r"^[a-fA-F0-9]{32,64}$|^[a-fA-F0-9]{128}$", clipboard_hash) or re.match(r"^[0-9A-Fa-f]{8}$", clipboard_hash):
nohash = 0
else:
nohash = 1

# Assign calculated hash to hash type
list, crc32_hash = assign(file_name)

# print out file being checked and properties
print("\n\n\tFile got: " + colored(os.path.basename(file_name), 'blue', 'on_white'), end = "\n\n")

# Linebreak, Flair
print("\t{:=^75s}\n\n".format(""))

# Output and format for hash values
for i in range(len(list)):
print("{0[0]:>12} hash: {0[1]}".format(list[i], list[i]))

# Print out CRC checksum
print("\n{:>3}CRC32 checksum: {}\n".format("", colored(crc32_hash, 'yellow')))

# Linebreak, Flair
print("\t{:-^75s}\n".format(""))

# Since BLAKE2b/SHA512, and BLAKE2s/SHA256
# have the same bit length, I like to compare the two
# hashes and look at if there is any differences.
# Just some fun flair, it's fun to see.
display_confidence_hashes(clipboard_hash, list)

# display output of match/nomatch
display(nohash, list, clipboard_hash)

# Linebreak, Flair
print("\t{:=^75s}\n\n\n".format(""))

# Allow user to see results,
# if you're using this program on the command line then you can omit this
os.system('pause')

# Throw error if something fails
except Exception as e:
print("Error:", e)

if __name__ == '__main__':
main()
100 changes: 99 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,100 @@
# Hashcheck
file hash checker with supported common hash methods: md5, sha-1, sha256, sha512, blake2s, blake2b
A simple hash verifier for files.

I had made this a while back while tinkering with python, forgotten about it and have now updated it to release it (trying to use github more).

I've always disliked having to open another term to verify hashsums when downloading important files. Generally speaking, any organization that creates Paas, Saas or any of the types, usually have hash checksums beside the download of their binaries. I found it a bit tedious to copy the hashsum, open a term in the directory and then run 'hashutil', 'md5sum', 'sha256sum', etc. to verify the two hashes, I'm sure there's other tools that do this, though this was fun lil project to make.


## Examples
If a match is found:

![Match_found](/img/valid_hash_input_match.gif)

No match:

![No_Match_found](/img/valid_hash_input_no_match.gif)


## Info
This program was written in:
- `python 3.10.4`

**\* I'm sure it can run on previous python versions, though I have not tested this.**

The releases built with:
- `pyinstaller 5.7.0`

The arguments with pyinstaller:
```
pyinstaller --onefile hashcheck.py
```

Since it was built with the flag `--onefile`, the load time will be slower when invoking Hashcheck. I recommend building the binary yourself: [pyinstaller manual](https://pyinstaller.org/en/stable/)


## Dependancies
All of the dependancies are in the `requirements.txt` file.

Hashcheck uses the following libraries:
- `colorama 0.4.6`
- `pyperclip 1.8.2`
- `termcolor 1.1.0`
- `tqdm 4.64.1`

You can install these with `pip3`:

```
pip3 install -r requirements.txt
```

If you do not have pip3 installed then you can run:
```
sudo apt install python3-pip
```


## Running
I wrote this with the intent of having the hash already in my system clipboard. You can copy the hash of whatever program you're checking against, and run the program to the target file.

invoking through python3:
```
python3 Hashcheck.py <file>
```

If you are using the prebuilt binary:
```
Hashcheck.exe <file>
```

You may pass a directory to a target file such as:
```
Linux: python3 Hashcheck.py /bin/ping
windows: Hashcheck.exe C:\Users\ihr\Desktop\passwords.txt
```

If there are whitespaces in the directory then pass it with double quotes:
```
Linux: python3 Hashcheck.py "~/Coding/CPP/ihaveroots sketchycode.cpp"
Windows: Hashcheck.exe "C:\Users\ihr rules\Desktop\domain_admin.txt"
```


## Linux
I initally wrote this for windows, it will execute, though, if you're running it from the command line, omit line 280 else it will yield the error of:
```
sh: 1: pause: Permission denied
```


## Windows
I made this with the intent on adding it to windows' context menu for a quick run. I didn't want to mess around with opening terminals. I also wanted to avoid fondling around with the registry so I've found adding it to the `sendto` context much easier. If you're running it from the command line then see Running.

![Right_click_context](/img/sendto.gif)

You may do the same by:
- Opening run: `Windows Key+R`
- Typing in: `shell:sendto`
- Adding the most recent release to the folder location

![Sendto](/img/run.png)
Binary file added img/run.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sendto.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/valid_hash_input_match.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/valid_hash_input_no_match.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/valid_hash_input_unknown.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
colorama==0.4.6
pyperclip==1.8.2
termcolor==1.1.0
tqdm==4.64.1

0 comments on commit 907a846

Please sign in to comment.