More secure comparison of HMAC strings
To avoid timing attacks. The implementation of SecureCompareStrings is pulled directly from python 3.4 sources.
This commit is contained in:
parent
b56858d2b0
commit
ccf0a2ed4d
@ -215,10 +215,33 @@ def SafePopen( *args, **kwargs ):
|
||||
|
||||
|
||||
def ContentHexHmacValid( content, hmac, hmac_secret ):
|
||||
return hmac == CreateHexHmac( content, hmac_secret )
|
||||
return SecureCompareStrings( CreateHexHmac( content, hmac_secret ), hmac )
|
||||
|
||||
|
||||
def CreateHexHmac( content, hmac_secret ):
|
||||
return hmac.new( hmac_secret,
|
||||
msg = content,
|
||||
digestmod = hashlib.sha256 ).hexdigest()
|
||||
|
||||
|
||||
# This is the compare_digest function from python 3.4, adapted for 2.7:
|
||||
# http://hg.python.org/cpython/file/460407f35aa9/Lib/hmac.py#l16
|
||||
def SecureCompareStrings( a, b ):
|
||||
"""Returns the equivalent of 'a == b', but avoids content based short
|
||||
circuiting to reduce the vulnerability to timing attacks."""
|
||||
# Consistent timing matters more here than data type flexibility
|
||||
if not ( isinstance( a, str ) and isinstance( b, str ) ):
|
||||
raise TypeError( "inputs must be str instances" )
|
||||
|
||||
# We assume the length of the expected digest is public knowledge,
|
||||
# thus this early return isn't leaking anything an attacker wouldn't
|
||||
# already know
|
||||
if len( a ) != len( b ):
|
||||
return False
|
||||
|
||||
# We assume that integers in the bytes range are all cached,
|
||||
# thus timing shouldn't vary much due to integer object creation
|
||||
result = 0
|
||||
for x, y in zip( a, b ):
|
||||
result |= ord( x ) ^ ord( y )
|
||||
return result == 0
|
||||
|
Loading…
Reference in New Issue
Block a user