Constant time password hash match

main
Bob Mottram 2020-09-03 19:07:02 +01:00
parent 949f54f5f3
commit 6568be91ff
2 changed files with 28 additions and 8 deletions

35
auth.py
View File

@ -10,7 +10,6 @@ import base64
import hashlib import hashlib
import binascii import binascii
import os import os
import secrets
def hashPassword(password: str) -> str: def hashPassword(password: str) -> str:
@ -24,17 +23,39 @@ def hashPassword(password: str) -> str:
return (salt + pwdhash).decode('ascii') return (salt + pwdhash).decode('ascii')
def verifyPassword(storedPassword: str, providedPassword: str) -> bool: def getPasswordHash(salt: str, providedPassword: str) -> str:
"""Verify a stored password against one provided by user """Returns the hash of a password
""" """
salt = storedPassword[:64]
storedPassword = storedPassword[64:]
pwdhash = hashlib.pbkdf2_hmac('sha512', pwdhash = hashlib.pbkdf2_hmac('sha512',
providedPassword.encode('utf-8'), providedPassword.encode('utf-8'),
salt.encode('ascii'), salt.encode('ascii'),
100000) 100000)
pwdhash = binascii.hexlify(pwdhash).decode('ascii') return binascii.hexlify(pwdhash).decode('ascii')
return pwdhash == storedPassword
def verifyPassword(storedPassword: str, providedPassword: str) -> bool:
"""Verify a stored password against one provided by user
"""
if not storedPassword:
return False
if not providedPassword:
return False
salt = storedPassword[:64]
storedPassword = storedPassword[64:]
pwHash = getPasswordHash(salt, providedPassword)
# check that hashes are of equal length
if len(pwHash) != len(storedPassword):
return False
# Compare all of the characters before returning true or false.
# Hence the match should take a constant amount of time.
# See https://sqreen.github.io/DevelopersSecurityBestPractices/
# timing-attack/python
ctr = 0
matched = True
for ch in pwHash:
if ch != storedPassword[ctr]:
matched = False
ctr += 1
return matched
def createBasicAuthHeader(nickname: str, password: str) -> str: def createBasicAuthHeader(nickname: str, password: str) -> str:

View File

@ -2084,7 +2084,6 @@ def testTranslations():
print(englishStr + ' is missing from ' + lang + '.json') print(englishStr + ' is missing from ' + lang + '.json')
assert langJson.get(englishStr) assert langJson.get(englishStr)
def runAllTests(): def runAllTests():
print('Running tests...') print('Running tests...')
testTranslations() testTranslations()