A simple python script and library that uses the haveibeenpwned APIv2 to check if a password or password hash has been pwned using k-Anonymity.
This module implements the range
query from the haveibeenpwned APIv2, which uses k-Anonymity to better secure the hash you are requesting results for.
It works like this: Only the first 5 characters from the SHA-1 hash is sent to the server. The server then responds with hashes that matches the prefix. The hashes the server send back all have the first 5 chars cut away. The hashes are then assembled using the prefix and suffix, locally, to check if the password matches the one you provided.
You can read the blog post on this by the site's developer, here
1Password has implemented this in their service, so go make up your own opinion. You should of course always be skeptical of where you punch in your password. You should also read the source code.
$ python3 ./main.py --help
usage: main.py [-h] [--password PWD] [--hash PWDHASH]
Check if a password has been pwned using the haveibeenpwned APIv2.
optional arguments:
-h, --help show this help message and exit
--password PWD, -p PWD
Password to check, in cleartext.
--hash PWDHASH Password to check, as a SHA-1 hash.
$ python3 ./main.py
Password:
$ python3 ./main.py --password "test"
$ python3 ./main.py --password test
$ python3 ./main.py --p "test"
$ python3 ./main.py --hash a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
All of the above will give this result:
There was a match, go change your password!
Seen # times in the database: 68340
If there was no match found:
No match.
Import the Pwned
class.
from pwnedpy import Pwned, RateLimitException
Use the functions check
and check_hash
.
Both check
and check_hash
return the full hash and the number of time the password has been seen in the database, if it was a match.
h, count = p.check(pwd)
If there was no match, the functions return None
and 0
, respectively.
(...)
args = parser.parse_args()
p = Pwned()
try:
if not args.pwd and not args.pwdhash:
pwd = getpass.getpass("Password: ")
h, count = p.check(pwd)
elif args.pwd:
h, count = p.check(args.pwd)
elif args.pwdhash:
h, count = p.check_hash(args.pwdhash)
if h:
print("There was a match, go change your password!")
print("Seen # times in the database: {}".format(count))
else:
print("No match.")
except RateLimitException as e:
print("You're being rate-limited.")
except Exception as e:
print("Error: {}".format(e))
- Implement the rest of the REST APIv2
The script has only been tested with Python 3.6.4
, it should work down to Python 3.4.x
.
requests
is the only other requirement. Install with pip install -r Requirements.txt
, or pip install requests
.
The code is licensed under an MIT license.