Skip to content

Instantly share code, notes, and snippets.

@hartwork
Created May 27, 2023 18:39
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
Test a password against the Have-I-Been-Pwned database API interactively with ease and k-anonymity (Python 3)
#! /usr/bin/env python3
# Copyright (C) 2023 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the MIT license
#
# Version 2023-05-27 20:38 UTC+2
#
# Inspired by https://github.com/weddige/django-hibp/blob/main/django_hibp.py
# of django-hibp by Konstantin Weddige (@weddige).
import getpass
import hashlib
import signal
import sys
import urllib.request
def test_password(password: str) -> [str, int]:
full_upper_sha1 = hashlib.sha1(password.encode("utf-8")).hexdigest().upper()
upper_sha1_prefix = full_upper_sha1[:5]
url = f"https://api.pwnedpasswords.com/range/{upper_sha1_prefix}"
response = urllib.request.urlopen(url).read().decode("utf-8")
upper_sha1_remainder = full_upper_sha1[5:]
for line in response.split("\n"):
if line.startswith(upper_sha1_remainder):
_, times, *_ = line.split(":")
return upper_sha1_prefix, int(times)
return upper_sha1_prefix, 0
def main():
print(
"WARNING: The first and last characters of your password will be echoed back to the terminal."
)
password = getpass.getpass(prompt="Password: ")
upper_sha1_prefix, seen_times = test_password(password)
if seen_times == 0:
exit_code = 0
summary = "not seen, good (no guarantee!)"
else:
exit_code = 1
summary = f"seen {seen_times:,} times, BAD"
obfuscated_password = f"{password[0]}[..]{password[-1]}"
obfuscated_sha1 = f"{upper_sha1_prefix}[..]"
print(f"Password {obfuscated_password!r} (SHA1 {obfuscated_sha1}) {summary}.")
return exit_code
if __name__ == "__main__":
try:
exit_code = main()
except KeyboardInterrupt:
exit_code = 128 + signal.SIGINT
sys.exit(exit_code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment