From 7fe3bbbb5cd6074b1dde8f708e1ead035831d4db Mon Sep 17 00:00:00 2001 From: Andrea Barberio Date: Tue, 4 Apr 2017 22:18:07 +0100 Subject: [PATCH 1/2] Added support for callables; added base64 and hex string prototypes --- hashid.py | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/hashid.py b/hashid.py index f0deb5b..8d16ced 100755 --- a/hashid.py +++ b/hashid.py @@ -21,6 +21,8 @@ import os import re import sys +import base64 +import binascii import argparse from collections import namedtuple @@ -30,9 +32,34 @@ __license__ = "License GPLv3+: GNU GPL version 3 or later " __banner__ = "hashID v{0} by {1} ({2})".format(__version__, __author__, __github__) -Prototype = namedtuple('Prototype', ['regex', 'modes']) +class Prototype: + def __init__(self, regex=None, modes=None, callable=None): + self.regex = regex + self.modes = modes or [] + self.callable = callable + if not (self.regex or self.callable): + raise RuntimeError( + 'At least one of `regex` and `callable` must be defined') + HashInfo = namedtuple('HashInfo', ['name', 'hashcat', 'john', 'extended']) + +def is_base64(data): + try: + base64.b64decode(data) + return True + except (TypeError, binascii.Error): + return False + + +def is_hexstring(data): + try: + binascii.unhexlify(data) + return True + except binascii.Error: + return False + + prototypes = [ Prototype( regex=re.compile(r'^[a-f0-9]{4}$', re.IGNORECASE), @@ -740,7 +767,19 @@ Prototype( regex=re.compile(r'^\$pdf\$[24]\*[34]\*128\*[0-9-]{1,5}\*1\*(16|32)\*[a-f0-9]{32,64}\*32\*[a-f0-9]{64}\*(8|16|32)\*[a-f0-9]{16,64}$', re.IGNORECASE), modes=[ - HashInfo(name='PDF 1.4 - 1.6 (Acrobat 5 - 8)', hashcat=10500, john='pdf', extended=False)]) + HashInfo(name='PDF 1.4 - 1.6 (Acrobat 5 - 8)', hashcat=10500, john='pdf', extended=False)]), + Prototype( + callable=is_base64, + modes=[ + HashInfo(name='Base64', hashcat=None, john=None, extended=False) + ], + ), + Prototype( + callable=is_hexstring, + modes=[ + HashInfo(name='Hex string', hashcat=None, john=None, extended=False) + ], + ), ] @@ -759,7 +798,8 @@ def identifyHash(self, phash): """Returns identified HashInfo""" phash = phash.strip() for prototype in self.prototypes: - if prototype.regex.match(phash): + if (prototype.regex and prototype.regex.match(phash)) or\ + (prototype.callable and prototype.callable(phash)): for mode in prototype.modes: yield mode From c7a3d73378b77b1bcfcd5321c72b51c792a0f40e Mon Sep 17 00:00:00 2001 From: Andrea Barberio Date: Thu, 6 Apr 2017 09:31:32 +0100 Subject: [PATCH 2/2] Removed callable; back to regex-only --- hashid.py | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/hashid.py b/hashid.py index 8d16ced..68e9866 100755 --- a/hashid.py +++ b/hashid.py @@ -32,15 +32,7 @@ __license__ = "License GPLv3+: GNU GPL version 3 or later " __banner__ = "hashID v{0} by {1} ({2})".format(__version__, __author__, __github__) -class Prototype: - def __init__(self, regex=None, modes=None, callable=None): - self.regex = regex - self.modes = modes or [] - self.callable = callable - if not (self.regex or self.callable): - raise RuntimeError( - 'At least one of `regex` and `callable` must be defined') - +Prototype = namedtuple('Prototype', ['regex', 'modes']) HashInfo = namedtuple('HashInfo', ['name', 'hashcat', 'john', 'extended']) @@ -769,17 +761,15 @@ def is_hexstring(data): modes=[ HashInfo(name='PDF 1.4 - 1.6 (Acrobat 5 - 8)', hashcat=10500, john='pdf', extended=False)]), Prototype( - callable=is_base64, + regex=re.compile(r'^([a-fA-F0-9]{2})+$', re.IGNORECASE), modes=[ - HashInfo(name='Base64', hashcat=None, john=None, extended=False) - ], - ), + HashInfo(name='Hex string', hashcat=None, john=None, extended=False), + ]), Prototype( - callable=is_hexstring, + regex=re.compile(r'^([a-zA-Z0-9+/]{4})*([a-zA-Z0-9+/]{4}|[a-zA-Z0-9+/]{2}==|[a-zA-Z0-9+/]{3}=)$'), modes=[ - HashInfo(name='Hex string', hashcat=None, john=None, extended=False) - ], - ), + HashInfo(name='Base64', hashcat=None, john=None, extended=False) + ]), ] @@ -798,8 +788,7 @@ def identifyHash(self, phash): """Returns identified HashInfo""" phash = phash.strip() for prototype in self.prototypes: - if (prototype.regex and prototype.regex.match(phash)) or\ - (prototype.callable and prototype.callable(phash)): + if prototype.regex.match(phash): for mode in prototype.modes: yield mode