Skip to content

Instantly share code, notes, and snippets.

@turret-io
Last active January 24, 2022 09:47
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save turret-io/74767215cf66b5ec329f to your computer and use it in GitHub Desktop.
Save turret-io/74767215cf66b5ec329f to your computer and use it in GitHub Desktop.
Verify HMAC in Python
import hmac, hashlib, json, time, base64, urlparse
SHARED_SECRET = 'sup3rs3cr3t!!'
def verifySignature(string_to_verify, signature, shared_secret):
return ct_compare(hmac.new(shared_secret,
string_to_verify, hashlib.sha512).digest(), signature)
def verifyTime(decoded_json):
j = json.loads(decoded_json)
if int(time.time()) - int(j['timestamp']) > 30:
raise Exception('Timestamp too far in the past')
return j
def ct_compare(a, b):
"""
** From Django source **
Run a constant time comparison against two strings
Returns true if a and b are equal.
a and b must both be the same length, or False is
returned immediately
"""
if len(a) != len(b):
return False
result = 0
for ch_a, ch_b in zip(a, b):
result |= ord(ch_a) ^ ord(ch_b)
return result == 0
if __name__ == '__main__':
url = '[QUERYSTRING]'
query = urlparse.parse_qs(urlparse.urlparse(url).query)
decoded_signature = base64.urlsafe_b64decode(query['signature'][0])
decoded_json = base64.urlsafe_b64decode(query['data'][0])
if verifySignature(decoded_json, decoded_signature, SHARED_SECRET) is True:
print('Valid signature')
# Verify timestamp
payload = verifyTime(decoded_json)
print('Timestamp verified')
print(payload)
else:
print('Invalid signature')
@daneah
Copy link

daneah commented May 20, 2015

Can you explain how the ct_compare is constant time if it has to do work for each character in the string?

@HT154
Copy link

HT154 commented Oct 1, 2018

@daneah the point is that the comparison always takes the same amount of time given strings of the same length, not the same time given any string. If the comparison bailed at the first non-matching character (like the regular == string comparison does), then an attacker (who controls the input) might be able to use a timing attack to discover your secret

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment