[py3] Fixed #17040 -- ported django.utils.crypto.constant_time_compare.
This is a private API; adding a type check is acceptable.
This commit is contained in:
parent
54899d810d
commit
62954ba04c
|
@ -24,6 +24,7 @@ except NotImplementedError:
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import smart_bytes
|
||||||
|
from django.utils import six
|
||||||
from django.utils.six.moves import xrange
|
from django.utils.six.moves import xrange
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,15 +82,21 @@ def get_random_string(length=12,
|
||||||
|
|
||||||
def constant_time_compare(val1, val2):
|
def constant_time_compare(val1, val2):
|
||||||
"""
|
"""
|
||||||
Returns True if the two strings are equal, False otherwise.
|
Returns True if the two bytestrings 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.
|
||||||
"""
|
"""
|
||||||
|
if not (isinstance(val1, bytes) and isinstance(val2, bytes)):
|
||||||
|
raise TypeError("constant_time_compare only supports bytes")
|
||||||
if len(val1) != len(val2):
|
if len(val1) != len(val2):
|
||||||
return False
|
return False
|
||||||
result = 0
|
result = 0
|
||||||
for x, y in zip(val1, val2):
|
if six.PY3:
|
||||||
result |= ord(x) ^ ord(y)
|
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
|
return result == 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,17 @@ import timeit
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from django.utils import unittest
|
from django.utils import unittest
|
||||||
from django.utils.crypto import pbkdf2
|
from django.utils.crypto import constant_time_compare, pbkdf2
|
||||||
|
|
||||||
|
|
||||||
|
class TestUtilsCryptoMisc(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_constant_time_compare(self):
|
||||||
|
# It's hard to test for constant time, just test the result.
|
||||||
|
self.assertTrue(constant_time_compare(b'spam', b'spam'))
|
||||||
|
self.assertFalse(constant_time_compare(b'spam', b'eggs'))
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
constant_time_compare('spam', 'spam')
|
||||||
|
|
||||||
|
|
||||||
class TestUtilsCryptoPBKDF2(unittest.TestCase):
|
class TestUtilsCryptoPBKDF2(unittest.TestCase):
|
||||||
|
|
|
@ -6,7 +6,7 @@ from __future__ import absolute_import
|
||||||
from .archive import TestBzip2Tar, TestGzipTar, TestTar, TestZip
|
from .archive import TestBzip2Tar, TestGzipTar, TestTar, TestZip
|
||||||
from .baseconv import TestBaseConv
|
from .baseconv import TestBaseConv
|
||||||
from .checksums import TestUtilsChecksums
|
from .checksums import TestUtilsChecksums
|
||||||
from .crypto import TestUtilsCryptoPBKDF2
|
from .crypto import TestUtilsCryptoMisc, TestUtilsCryptoPBKDF2
|
||||||
from .datastructures import (DictWrapperTests, ImmutableListTests,
|
from .datastructures import (DictWrapperTests, ImmutableListTests,
|
||||||
MergeDictTests, MultiValueDictTests, SortedDictTests)
|
MergeDictTests, MultiValueDictTests, SortedDictTests)
|
||||||
from .dateformat import DateFormatTests
|
from .dateformat import DateFormatTests
|
||||||
|
|
Loading…
Reference in New Issue