summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell Bryant <rbryant@redhat.com>2012-03-19 17:07:24 -0400
committerRussell Bryant <rbryant@redhat.com>2012-03-19 17:11:23 -0400
commitb3f900170561c03b40d376e76fdedf49799e0c7d (patch)
treeb8710138e3d6b50777e506325465defa81eb96c6
parent13ed88186bb5c6a1900c3bb742d06743fd21ac58 (diff)
downloadoslo-b3f900170561c03b40d376e76fdedf49799e0c7d.tar.gz
oslo-b3f900170561c03b40d376e76fdedf49799e0c7d.tar.xz
oslo-b3f900170561c03b40d376e76fdedf49799e0c7d.zip
Add auth_str_equal() to common utils.
This function provides a constant-time string comparison. Its primary use case is for authentication to avoid timing vulnerabilities. Similar functions currently exist in keystone, nova, and swift. The three diverged in slight ways immediately after going in. This version comes from keystone, which I consider the "best" version to promote to openstack-common. Change-Id: I39537a21be8a402e34e526466f6b90188344a35d
-rw-r--r--openstack/common/utils.py24
-rw-r--r--tests/unit/test_utils.py6
2 files changed, 30 insertions, 0 deletions
diff --git a/openstack/common/utils.py b/openstack/common/utils.py
index 3a0e6c6..8cc400a 100644
--- a/openstack/common/utils.py
+++ b/openstack/common/utils.py
@@ -207,3 +207,27 @@ def set_time_override(override_time=datetime.datetime.utcnow()):
def clear_time_override():
"""Remove the overridden time."""
utcnow.override_time = None
+
+
+def auth_str_equal(provided, known):
+ """Constant-time string comparison.
+
+ :params provided: the first string
+ :params known: the second string
+
+ :return: True if the strings are equal.
+
+ This function takes two strings and compares them. It is intended to be
+ used when doing a comparison for authentication purposes to help guard
+ against timing attacks. When using the function for this purpose, always
+ provide the user-provided password as the first argument. The time this
+ function will take is always a factor of the length of this string.
+ """
+ result = 0
+ p_len = len(provided)
+ k_len = len(known)
+ for i in xrange(p_len):
+ a = ord(provided[i]) if i < p_len else 0
+ b = ord(known[i]) if i < k_len else 0
+ result |= a ^ b
+ return (p_len == k_len) & (result == 0)
diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py
index a59683b..1d464bb 100644
--- a/tests/unit/test_utils.py
+++ b/tests/unit/test_utils.py
@@ -119,6 +119,12 @@ class UtilsTest(unittest.TestCase):
self.assertTrue(utils.utcnow())
+ def test_auth_str_equal(self):
+ self.assertTrue(utils.auth_str_equal('abc123', 'abc123'))
+ self.assertFalse(utils.auth_str_equal('a', 'aaaaa'))
+ self.assertFalse(utils.auth_str_equal('aaaaa', 'a'))
+ self.assertFalse(utils.auth_str_equal('ABC123', 'abc123'))
+
class TestIso8601Time(unittest.TestCase):