-
Notifications
You must be signed in to change notification settings - Fork 18
/
binary_search.py
66 lines (60 loc) · 2.97 KB
/
binary_search.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from hashlib import sha1
from os import stat
from argparse import ArgumentParser
def binary_search(hex_hash, list_file, file_size):
def get_full_line(file, pos):
file.seek(pos)
while pos > 0 and file.read(1) != "\n":
pos -= 1
file.seek(pos)
return file.readline(), pos
def search_hash(file, my_hash, start, end):
if start >= end:
return 0
new_pos = start + (end - start) // 2
candidate_line, pivot = get_full_line(file, new_pos)
# print("Trying line at pos {:11d}: \"{}\" (pivot position: {})".format(
# new_pos, candidate_line.strip(), pivot))
pwned_hash, count = candidate_line.split(':')
if pwned_hash == my_hash:
print("Password found at byte {:11d}: \"{}\"".format(pivot, candidate_line.strip()))
return int(count.strip())
if my_hash > pwned_hash:
return search_hash(file, my_hash, file.tell(), end)
else:
return search_hash(file, my_hash, start, pivot)
return search_hash(list_file, hex_hash, 0, file_size)
if __name__ == "__main__":
parser = ArgumentParser(description='Test passwords locally.' +
' Each password you pass as an argument will be hashed and this script' +
' will search for the hash in the list.')
parser.add_argument('passwords', nargs='+')
parser.add_argument('--pwned-passwords-ordered-by-hash-filename', required=False,
default="pwned-passwords-sha1-ordered-by-hash-v5.txt")
args = parser.parse_args()
with open(args.pwned_passwords_ordered_by_hash_filename, 'r') as pwned_passwords_file:
pwned_passwords_file_size = stat(args.pwned_passwords_ordered_by_hash_filename).st_size
# print("File size: {} Bytes".format(pwned_passwords_file_size))
for password in args.passwords:
if 'decode' in dir(str):
password = password.decode('utf-8')
encodings = ['utf-8', 'latin', 'iso8859-15', 'iso8859-1']
hashes = []
for encoding in encodings:
try:
hash_candidate = sha1(password.encode(encoding)).hexdigest().upper()
if hash_candidate not in hashes:
hashes.append(hash_candidate)
except UnicodeEncodeError:
continue
count = 0
for h in hashes:
print("Searching for hash {} of password \"{}\".".format(h, password))
count += binary_search(h, pwned_passwords_file, pwned_passwords_file_size)
if count > 0:
print("Your password \"{}\" was in {} leaks or hacked databases!".format(password, count) +
" Please change it immediately.")
else:
print("Your password \"{}\" is not in the dataset. You may relax.".format(password))