-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathauth.py
100 lines (85 loc) · 3.15 KB
/
auth.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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import getpass
import json
import pathlib
import random
import string
import tempfile
# name of the file where we store the pw database
PWDB_FLNAME = pathlib.Path('pwdb.json')
# the pw database will be stored in a temporary directory
PWDB_DEFAULTPATH = PWDB_FLNAME
# list of valid characters for salt (only ASCII letters + digits + punctuation)
CHARS = string.ascii_letters + string.digits + string.punctuation
# length of salt
SALT_LENGTH = 5
def get_credentials():
# get input from terminal
username = input('Enter your username: ')
# get password using the appropriate module, so that typed characters are not
# echoed to the terminal
password = getpass.getpass('Enter your password: ')
return (username, password)
def authenticate(username, pass_text, pwdb):
status = False
if username in pwdb:
# get the salt from the database
salt = pwdb[username][1]
# calculate hash and compare with stored hash
if pwhash(pass_text, salt) == pwdb[username][0]:
status = True
return status
def add_user(username, password, salt, pwdb, pwdb_path):
# do not try to add a username twice
if username in pwdb:
raise Exception('Username already exists [%s]' %username)
else:
pwdb[username] = (pwhash(password,salt), salt)
write_pwdb(pwdb, pwdb_path)
def read_pwdb(pwdb_path):
# try to read from the database
# if anything happens, report the error!
try:
with open(pwdb_path, 'rt') as pwdb_file:
pwdb = json.load(pwdb_file)
except json.decoder.JSONDecodeError as exc:
# this happens when the json data is invalid
raise Exception(f'Invalid database {pwdb_path}: {exc}')
except Exception as exc:
# this is a catch-all condition
raise Exception(f'Unkown error reading {pwdb_path}: {exc}')
return pwdb
def write_pwdb(pwdb, pwdb_path):
with open(pwdb_path, 'wt') as pwdb_file:
json.dump(pwdb, pwdb_file)
def pwhash(pass_text, salt):
# simple additive hash -> very insecure!
hash_ = 0
full_pass_text = pass_text + salt
for idx, char in enumerate(full_pass_text):
# use idx as a multiplier, so that shuffling the characters returns a
# different hash
hash_ += (idx+1)*ord(char)
return hash_
def get_salt():
salt_chars = random.choices(CHARS, k=SALT_LENGTH)
return ''.join(salt_chars)
if __name__ == '__main__':
# ask for credentials
username, password = get_credentials()
# if the database does not exist yet, create an empty one by default
if not PWDB_DEFAULTPATH.exists():
write_pwdb({}, PWDB_DEFAULTPATH)
# load the password database from file
pwdb = read_pwdb(PWDB_DEFAULTPATH)
# try to authenticate
if authenticate(username, password, pwdb):
print('Successfully authenticated!')
elif username not in pwdb:
# if the user is not known, ask if a new user must be added
ans = input('Create new user [y/n]? ')
if ans == 'y':
salt = get_salt()
add_user(username, password, salt, pwdb, PWDB_DEFAULTPATH)
else:
# report wrong password
print('Wrong password!')