diff options
| author | Donald Stufft <donald@stufft.io> | 2014-04-22 17:53:08 -0400 |
|---|---|---|
| committer | Donald Stufft <donald@stufft.io> | 2014-04-22 17:53:08 -0400 |
| commit | 03401701f3671f62ef51ff791e226b0d38a978ca (patch) | |
| tree | fda4f09c5cab243ffb091ccdcbf341f66f5297e4 | |
| parent | 9fb95dfc9fa1f9df73e384624c345199dd281dd5 (diff) | |
| parent | 58176dee88ac7c1038c7f685af023e634b143d02 (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.py | 42 |
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): |
