diff --git a/oslo_utils/secretutils.py b/oslo_utils/secretutils.py index 09b1b739..963c6341 100644 --- a/oslo_utils/secretutils.py +++ b/oslo_utils/secretutils.py @@ -20,28 +20,26 @@ Secret utilities. import hmac -import six +def _constant_time_compare(first, second): + """Return True if both string or binary inputs are equal, otherwise False. + + This function should take a constant amount of time regardless of + how many characters in the strings match. This function uses an + approach designed to prevent timing analysis by avoiding + content-based short circuiting behaviour, making it appropriate + for cryptography. + """ + first = str(first) + second = str(second) + if len(first) != len(second): + return False + result = 0 + for x, y in zip(first, second): + result |= ord(x) ^ ord(y) + return result == 0 try: constant_time_compare = hmac.compare_digest except AttributeError: - def constant_time_compare(first, second): - """Returns True if both string inputs are equal, otherwise False. - - This function should take a constant amount of time regardless of - how many characters in the strings match. This function uses an - approach designed to prevent timing analysis by avoiding - content-based short circuiting behaviour, making it appropriate - for cryptography. - """ - if isinstance(first, six.string_types): - first = first.encode('utf-8') - if isinstance(second, six.string_types): - second = second.encode('utf-8') - if len(first) != len(second): - return False - result = 0 - for x, y in zip(first, second): - result |= ord(x) ^ ord(y) - return result == 0 + constant_time_compare = _constant_time_compare diff --git a/oslo_utils/tests/test_secretutils.py b/oslo_utils/tests/test_secretutils.py index 1c4b366b..faea3dd3 100644 --- a/oslo_utils/tests/test_secretutils.py +++ b/oslo_utils/tests/test_secretutils.py @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +import hmac + from oslotest import base as test_base import testscenarios @@ -21,15 +23,20 @@ from oslo_utils import secretutils class SecretUtilsTest(testscenarios.TestWithScenarios, test_base.BaseTestCase): + _gen_digest = lambda text: hmac.new(b'foo', text.encode('utf-8')).digest() scenarios = [ - ('binary', {'converter': lambda text: text.encode('utf-8')}), + ('binary', {'converter': _gen_digest}), ('unicode', {'converter': lambda text: text}), ] def test_constant_time_compare(self): # make sure it works as a compare, the "constant time" aspect # isn't appropriate to test in unittests - ctc = secretutils.constant_time_compare + + # Make sure the unittests are applied to our function instead of + # the built-in function, otherwise that is in vain. + ctc = secretutils._constant_time_compare + self.assertTrue(ctc(self.converter(u'abcd'), self.converter(u'abcd'))) self.assertTrue(ctc(self.converter(u''),