summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDonald Stufft <donald@stufft.io>2014-04-22 17:53:08 -0400
committerDonald Stufft <donald@stufft.io>2014-04-22 17:53:08 -0400
commit03401701f3671f62ef51ff791e226b0d38a978ca (patch)
treefda4f09c5cab243ffb091ccdcbf341f66f5297e4
parent9fb95dfc9fa1f9df73e384624c345199dd281dd5 (diff)
parent58176dee88ac7c1038c7f685af023e634b143d02 (diff)
Merge pull request #2600 from alex/builtin-constant-time-compare
Use the stdlib's compare_digest for constant time comparisons when available
-rw-r--r--django/utils/crypto.py42
1 files changed, 23 insertions, 19 deletions
diff --git a/django/utils/crypto.py b/django/utils/crypto.py
index d02ee5351d..8bf884a72f 100644
--- a/django/utils/crypto.py
+++ b/django/utils/crypto.py
@@ -77,27 +77,31 @@ def get_random_string(length=12,
return ''.join(random.choice(allowed_chars) for i in range(length))
-def constant_time_compare(val1, val2):
- """
- Returns True if the two strings are equal, False otherwise.
+if hasattr(hmac, "compare_digest"):
+ # Prefer the stdlib implementation, when available.
+ constant_time_compare = hmac.compare_digest
+else:
+ def constant_time_compare(val1, val2):
+ """
+ Returns True if the two strings are equal, False otherwise.
- The time taken is independent of the number of characters that match.
+ The time taken is independent of the number of characters that match.
- For the sake of simplicity, this function executes in constant time only
- when the two strings have the same length. It short-circuits when they
- have different lengths. Since Django only uses it to compare hashes of
- known expected length, this is acceptable.
- """
- if len(val1) != len(val2):
- return False
- result = 0
- if six.PY3 and isinstance(val1, bytes) and isinstance(val2, bytes):
- for x, y in zip(val1, val2):
- result |= x ^ y
- else:
- for x, y in zip(val1, val2):
- result |= ord(x) ^ ord(y)
- return result == 0
+ For the sake of simplicity, this function executes in constant time only
+ when the two strings have the same length. It short-circuits when they
+ have different lengths. Since Django only uses it to compare hashes of
+ known expected length, this is acceptable.
+ """
+ if len(val1) != len(val2):
+ return False
+ result = 0
+ if six.PY3 and isinstance(val1, bytes) and isinstance(val2, bytes):
+ for x, y in zip(val1, val2):
+ result |= x ^ y
+ else:
+ for x, y in zip(val1, val2):
+ result |= ord(x) ^ ord(y)
+ return result == 0
def _bin_to_long(x):