my solution
This commit is contained in:
		
							parent
							
								
									3bead9f7b6
								
							
						
					
					
						commit
						a0d4fa9c86
					
				
					 1 changed files with 67 additions and 36 deletions
				
			
		
							
								
								
									
										103
									
								
								auth.py
									
										
									
									
									
								
							
							
						
						
									
										103
									
								
								auth.py
									
										
									
									
									
								
							|  | @ -1,57 +1,88 @@ | ||||||
|  | import getpass | ||||||
| import json | import json | ||||||
|  | import pathlib | ||||||
|  | import random | ||||||
|  | import string | ||||||
| import sys | import sys | ||||||
| from getpass import getpass |  | ||||||
| from hashlib import sha256 |  | ||||||
| 
 | 
 | ||||||
| PWDB_PATH = 'pwdb.json' | # name of the file where we store the pw database | ||||||
|  | PWDB_FLNAME = pathlib.Path('pwdb.json') | ||||||
|  | 
 | ||||||
|  | # 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(): | def get_credentials(): | ||||||
|  |     # get input from terminal | ||||||
|     username = input('Enter your username: ') |     username = input('Enter your username: ') | ||||||
|     hashed_password = pwhash(getpass('Enter your password: ')) |     # get password using the appropriate module, so that typed characters are not | ||||||
|     return (username, hashed_password) |     # echoed to the terminal | ||||||
|  |     password = getpass.getpass('Enter your password: ') | ||||||
|  |     return (username, password) | ||||||
| 
 | 
 | ||||||
| def authenticate(username, hashed_password, pwdb): | def authenticate(username, pass_text, pwdb): | ||||||
|     return hashed_password == pwdb[username] |     # get the salt from the database | ||||||
|  |     salt = pwdb[username][1] | ||||||
|  |     # calculate hash and compare with stored hash | ||||||
|  |     return pwhash(pass_text, salt) == pwdb[username][0] | ||||||
| 
 | 
 | ||||||
| def add_user(username, pwdb): | def add_user(username, pwdb): | ||||||
|     pwdb[username] = pwhash(getpass(f'Enter password for {username}: ')) |     # do not try to add a username twice | ||||||
|  |     if username in pwdb: | ||||||
|  |         raise Exception(f'Username already exists [{username}]!') | ||||||
|  |     else: | ||||||
|  |         password = getpass.getpass(f'Enter password for {username}: ') | ||||||
|  |         salt = get_salt() | ||||||
|  |         pwdb[username] = (pwhash(password,salt), salt) | ||||||
|     return pwdb |     return pwdb | ||||||
| 
 | 
 | ||||||
| def read_pwdb(PWDB_PATH): | def read_pwdb(pwdb_path): | ||||||
|     try: |     if not pwdb_path.exists(): | ||||||
|         pwdb_file = open(PWDB_PATH, 'rt') |  | ||||||
|         pwdb = json.load(pwdb_file) |  | ||||||
|     except Exception: |  | ||||||
|         pwdb = {} |         pwdb = {} | ||||||
|  |     else: | ||||||
|  |         with open(pwdb_path, 'rt') as pwdb_file: | ||||||
|  |             pwdb = json.load(pwdb_file) | ||||||
|     return pwdb |     return pwdb | ||||||
| 
 | 
 | ||||||
| def write_pwdb(pwdb, PWDB_PATH): | def write_pwdb(pwdb, pwdb_path): | ||||||
|     pwdb_file = open(PWDB_PATH, 'wt') |     with open(pwdb_path, 'wt') as pwdb_file: | ||||||
|     json.dump(pwdb, 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 pwhash(pwd): | def get_salt(): | ||||||
|     encoded_pwd = pwd.encode("utf-8") |     salt_chars = random.choices(CHARS, k=SALT_LENGTH) | ||||||
|     m = sha256() |     return ''.join(salt_chars) | ||||||
|     m.update(encoded_pwd) |  | ||||||
|     return m.hexdigest() |  | ||||||
| 
 | 
 | ||||||
|  | def main(pwdb_path): | ||||||
|  |     # load the password database from file | ||||||
|  |     pwdb = read_pwdb(pwdb_path) | ||||||
| 
 | 
 | ||||||
| 
 |     # if we are passed an argument, we want to add a new user | ||||||
| if __name__ == "__main__": |  | ||||||
|     PWDB_PATH = 'pwdb.json' |  | ||||||
|     pwdb = read_pwdb(PWDB_PATH) |  | ||||||
| 
 |  | ||||||
|     if len(sys.argv) > 1: |     if len(sys.argv) > 1: | ||||||
|         pwdb = add_user(sys.argv[1], pwdb) |         pwdb = add_user(sys.argv[1], pwdb) | ||||||
|         write_pwdb(pwdb, PWDB_PATH) |         write_pwdb(pwdb, pwdb_path) | ||||||
|     else: |         return | ||||||
|         username, password = get_credentials() | 
 | ||||||
|         if username not in pwdb: |     # ask for credentials | ||||||
|             print('Wrong username!') |     username, password = get_credentials() | ||||||
|         else: |     if username not in pwdb or not authenticate(username, password, pwdb): | ||||||
|             if authenticate(username, password, pwdb): |         print('Wrong username or password!') | ||||||
|                 print('Successfully authenticated!') |     else: | ||||||
|             else: |         print('Successfully authenticated!') | ||||||
|                 print('Wrong password!') | 
 | ||||||
|  |     return | ||||||
|  | 
 | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     main(PWDB_FLNAME) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue