diff --git a/hhhash/__init__.py b/hhhash/__init__.py index 685d7a6..f08de11 100644 --- a/hhhash/__init__.py +++ b/hhhash/__init__.py @@ -1 +1 @@ -from hhhash.create import buildhash +from hhhash.create import buildhash, hash_from_banner diff --git a/hhhash/create.py b/hhhash/create.py index 787f649..64e8b81 100644 --- a/hhhash/create.py +++ b/hhhash/create.py @@ -28,3 +28,42 @@ def buildhash(url=None, debug=False, method='GET', timeout=5): m.update(hhhash[1:].encode()) digest = m.hexdigest() return f"hhh:1:{digest}" + +def hash_from_banner(banner, debug=False): + """Create a HHHash from an already fetched banner. Lines without colons will be skipped. + + Keyword arguments: + banner -- HTTP banner string + debug -- output the headers returned before hashing + + Example: + >>> hash_from_banner('''HTTP/1.1 200 OK + ... Content-Type: text/html; charset=ISO-8859-1 + ... Content-Security-Policy-Report-Only: object-src 'none';base-uri 'self';script-src 'nonce-iV-j91UJEG2jNx4j6EeTug' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp + ... P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info." + ... Date: Wed, 12 Jul 2023 20:23:42 GMT + ... Server: gws + ... X-XSS-Protection: 0 + ... X-Frame-Options: SAMEORIGIN + ... Transfer-Encoding: chunked + ... Expires: Wed, 12 Jul 2023 20:23:42 GMT + ... Cache-Control: private + ... Set-Cookie: + ... Set-Cookie: + ... Set-Cookie: + ... Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000''') + hhh:1:d9576f3e7a381562f7d18a514ab095fa8699e96891d346d0042f83e942373215 + """ + hhhash = "" + for line in banner.splitlines(): + if ":" not in line: + continue + + header, _ = line.split(":", maxsplit=1) + hhhash = f"{hhhash}:{header.strip()}" + if debug: + print(hhhash[1:]) + m = hashlib.sha256() + m.update(hhhash[1:].encode()) + digest = m.hexdigest() + return f"hhh:1:{digest}"