Created
June 26, 2017 09:09
-
-
Save lunaluxie/3b25d965af3f29e2457fe9b634fe21ff to your computer and use it in GitHub Desktop.
Small utility that lets you compute and compare cryptographically secure password hashes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Small utility that lets you compute and compare cryptographically secure password hashes | |
""" | |
def hash_password(password, salt=None, iterations=100000): | |
""" | |
Compute hash for a string using SHA1 | |
input: | |
String: password | |
String: salt (use if you are comparing existing hash) | |
If empty, it generates new salt | |
Optional Input: | |
Int: iterations | |
How many times the hash hashes itself | |
should be consistent across your application | |
Return: | |
Tuple with the password hash and salt used | |
Example: (pass_hash, salt) | |
""" | |
# Do type checking | |
if not type(password) == type("String"): | |
raise TypeError("Password should be a string") | |
import hashlib, random, string | |
# if no salt is given | |
# generate 16 alphanumeric long salt using system random | |
if not salt: | |
salt = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(16)) | |
# encode to make it compatible with hashlib algorithm | |
encoded_password = bytes(password, encoding='utf-8') | |
encoded_salt = bytes(salt, encoding='utf-8') | |
pass_hash = hashlib.sha1(encoded_password+encoded_salt).hexdigest() | |
# use iterative hashing | |
for _ in range(iterations): | |
pass_hash = hashlib.sha1(bytes(pass_hash, encoding="utf-8")).hexdigest() | |
return (pass_hash, salt) | |
def validate_password(password, pw_hash_tuple): | |
""" | |
Check if entered password matches a stored password hash | |
Input: | |
String: password | |
Tuple: pw_hash_tuple | |
of the scheme: (password_hash, salt) | |
Output: | |
Boolean: if they are identical. | |
""" | |
# Do input validation | |
if not len(pw_hash_tuple) == 2: | |
raise ValueError("pw_hash_tuple should have length 2") | |
if not type(password) == type('string'): | |
raise TypeError("password should be a string") | |
for item in pw_hash_tuple: | |
if not type(item) == type("string"): | |
raise TypeError("items in pw_hash_tuple should be strings") | |
stored_pw_hash = pw_hash_tuple[0] | |
stored_pw_salt = pw_hash_tuple[1] | |
# compute the hash of guesspassword using the same salt | |
user_pw_hash_tuple = hash_password(password, salt=stored_pw_salt) | |
# compare the two hashes | |
if user_pw_hash_tuple[0] == stored_pw_hash: | |
return True | |
else: | |
return False | |
# example | |
pw_hash_tuple = ('1023dd447f7212fd39b5a5df7c0d4e9fed0c22d5', 'XWZ3JIAWXXNSIMZA') | |
guess_password = "123456" | |
print (validate_password(guess_password, pw_hash_tuple)) # True |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment