commit
2bea07cee7
@ -3,6 +3,13 @@ Pwned Password API lookup
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
python pwned.py [password]
|
* `python pwned.py` – reads passwords from standard input;
|
||||||
|
* `pytohn pwned.py <[file-with-passwords]` – reads passwords from
|
||||||
|
a file;
|
||||||
|
* `another-command | pytohn pwned.py <[file-with-passwords]` – reads
|
||||||
|
passwords written to standard output by another command;
|
||||||
|
* `python pwned.py [password]` – checks passwords given as command line
|
||||||
|
arguments (beware the password may be saved in shell history and that
|
||||||
|
other users on the system ma be able to observe the command line).
|
||||||
|
|
||||||
Have fun! Oh, and if you find one of your own passwords, change it asap!
|
Have fun! Oh, and if you find one of your own passwords, change it asap!
|
||||||
|
61
pwned.py
61
pwned.py
@ -1,35 +1,48 @@
|
|||||||
|
import hashlib
|
||||||
import requests
|
import requests
|
||||||
import cryptography
|
|
||||||
from base64 import b16encode
|
|
||||||
import sys
|
import sys
|
||||||
from cryptography.hazmat.backends import default_backend
|
|
||||||
from cryptography.hazmat.primitives import hashes
|
|
||||||
|
|
||||||
def hash_password_sha1_hex(pwd):
|
|
||||||
digest = hashes.Hash(hashes.SHA1(), backend=default_backend())
|
|
||||||
digest.update(pwd.encode('ASCII'))
|
|
||||||
sha1 = b16encode(digest.finalize()).decode('ASCII')
|
|
||||||
return sha1
|
|
||||||
|
|
||||||
def lookup_pwned_api(pwd):
|
def lookup_pwned_api(pwd):
|
||||||
sha1pwd = hash_password_sha1_hex(pwd)
|
"""Returns hash and number of times password was seen in pwned database.
|
||||||
head = sha1pwd[:5]
|
|
||||||
tail = sha1pwd[5:]
|
|
||||||
|
|
||||||
r = requests.get('https://api.pwnedpasswords.com/range/{0}'.format(head))
|
Args:
|
||||||
if r.status_code == 200:
|
pwd: password to check
|
||||||
hashes = (s.split(':') for s in r.text.split('\r\n'))
|
|
||||||
pred = ((head + t,count) for t,count in hashes if t == tail)
|
|
||||||
|
|
||||||
password_hit = next(pred, None)
|
Returns:
|
||||||
return password_hit
|
A (sha1, count) tuple where sha1 is SHA1 hash of pwd and count is number
|
||||||
|
of times the password was seen in the pwned database. count equal zero
|
||||||
|
indicates that password has not been found.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: if there was an error trying to fetch data from pwned
|
||||||
|
database.
|
||||||
|
"""
|
||||||
|
sha1pwd = hashlib.sha1(pwd.encode('ascii')).hexdigest().upper()
|
||||||
|
head, tail = sha1pwd[:5], sha1pwd[5:]
|
||||||
|
url = 'https://api.pwnedpasswords.com/range/' + head
|
||||||
|
res = requests.get(url)
|
||||||
|
if res.status_code != 200:
|
||||||
|
raise RuntimeError('Error fetching "{}": {}'.format(
|
||||||
|
url, res.status_code))
|
||||||
|
hashes = (line.split(':') for line in res.text.splitlines())
|
||||||
|
count = next((int(count) for t, count in hashes if t == tail), 0)
|
||||||
|
return sha1pwd, count
|
||||||
|
|
||||||
|
|
||||||
api_return = lookup_pwned_api(sys.argv[1])
|
def main(args):
|
||||||
if (api_return):
|
ec = 0
|
||||||
print (sys.argv[1], "was found")
|
for pwd in args or sys.stdin:
|
||||||
print ("Hash {0}, {1} occurences".format(api_return[0], api_return[1]))
|
pwd = pwd.strip()
|
||||||
|
sha1pwd, count = lookup_pwned_api(pwd)
|
||||||
|
if count:
|
||||||
|
print(pwd, "was found")
|
||||||
|
print("Hash {0}, {1} occurrences".format(sha1pwd, count))
|
||||||
|
ec = 1
|
||||||
else:
|
else:
|
||||||
print (sys.argv[1], "was not found")
|
print(pwd, "was not found")
|
||||||
|
return ec
|
||||||
|
|
||||||
exit()
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
||||||
|
Loading…
Reference in New Issue
Block a user