Last active
January 24, 2022 09:47
-
-
Save turret-io/74767215cf66b5ec329f to your computer and use it in GitHub Desktop.
Verify HMAC in Python
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
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 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
Can you explain how the
ct_compare
is constant time if it has to do work for each character in the string?