forked from indymedia/epicyon
Constant time password hash match
parent
949f54f5f3
commit
6568be91ff
35
auth.py
35
auth.py
|
@ -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:
|
||||||
|
|
1
tests.py
1
tests.py
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue