-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhash_check.py
More file actions
124 lines (104 loc) · 3.65 KB
/
hash_check.py
File metadata and controls
124 lines (104 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env python3
import sys
import re
import base64
# ----------------------------
# Helper functions
# ----------------------------
def looks_like_md5(s):
return bool(re.fullmatch(r"[a-fA-F0-9]{32}", s))
def looks_like_sha1(s):
return bool(re.fullmatch(r"[a-fA-F0-9]{40}", s))
def looks_like_sha256(s):
return bool(re.fullmatch(r"[a-fA-F0-9]{64}", s))
def looks_like_bcrypt(s):
# bcrypt format: $2a$12$ followed by 53 characters [./A-Za-z0-9]
return bool(re.fullmatch(r"\$2[aby]\$\d{2}\$[./A-Za-z0-9]{53}", s))
def looks_like_hex(s):
if len(s) % 2 != 0:
return False
try:
bytes.fromhex(s)
return True
except ValueError:
return False
def decode_hex(s):
try:
return bytes.fromhex(s).decode('utf-8', errors='replace')
except ValueError:
return None
def is_strict_base64(s):
# Minimum length of 8 characters, multiple of 4
if not s or len(s) < 8 or len(s) % 4 != 0:
return False, None
if not re.fullmatch(r"[A-Za-z0-9+/]*={0,2}", s):
return False, None
try:
decoded = base64.b64decode(s, validate=True)
return True, decoded.decode('utf-8', errors='replace')
except (ValueError, UnicodeDecodeError):
return False, None
def pretty_decoded(flag, decoded):
if flag:
return "Yes — decoded text: {}".format(repr(decoded))
return "No"
# ----------------------------
# Main function
# ----------------------------
def main():
try:
s = input("Input the hash: ")
except (KeyboardInterrupt, EOFError):
print("\nAborted.")
sys.exit(1)
print("\nChecking...\n")
# One-way hashes first
md5_flag = looks_like_md5(s)
sha1_flag = looks_like_sha1(s)
sha256_flag = looks_like_sha256(s)
bcrypt_flag = looks_like_bcrypt(s)
one_way = md5_flag or sha1_flag or sha256_flag or bcrypt_flag
# Only reversible if NOT one-way
if not one_way:
# HEX
hex_flag = looks_like_hex(s)
hex_decoded = decode_hex(s) if hex_flag else None
# BASE64
b64_flag, b64_decoded = is_strict_base64(s)
else:
hex_flag = False
hex_decoded = None
b64_flag = False
b64_decoded = None
reversible = b64_flag or hex_flag
# Overall status
if reversible and not one_way:
overall = "Decryptable"
elif one_way and not reversible:
overall = "One-way (format-match)"
elif one_way and reversible:
overall = "Ambiguous (both reversible and matches one-way format)"
else:
overall = "Wrong / Unknown format"
print(f"The hash you input is: {overall}\n")
print("The hash is:")
print("Base64: " + pretty_decoded(b64_flag, b64_decoded))
print("Hex: " + pretty_decoded(hex_flag, hex_decoded))
print("MD5: " + ("Yes" if md5_flag else "No"))
print("SHA-1: " + ("Yes" if sha1_flag else "No"))
print("SHA-256: " + ("Yes" if sha256_flag else "No"))
print("Bcrypt: " + ("Yes" if bcrypt_flag else "No"))
print("\nNotes:")
if one_way:
print("- Detected a common one-way hash format above. This script WILL NOT try to crack or brute-force one-way hashes.")
if reversible:
print("- One or more reversible encodings detected; decoded contents shown where possible.")
if overall.startswith("Ambiguous"):
print("- Ambiguous result: your input may be an encoding that decodes to a one-way hash (or vice versa).")
if overall == "Wrong / Unknown format":
print("- Could not match common encodings/hashes. Might be something else or corrupted.")
# ----------------------------
# Entry point
# ----------------------------
if __name__ == "__main__":
main()