diff options
| author | Russell Bryant <rbryant@redhat.com> | 2012-03-19 17:07:24 -0400 |
|---|---|---|
| committer | Russell Bryant <rbryant@redhat.com> | 2012-03-19 17:11:23 -0400 |
| commit | b3f900170561c03b40d376e76fdedf49799e0c7d (patch) | |
| tree | b8710138e3d6b50777e506325465defa81eb96c6 | |
| parent | 13ed88186bb5c6a1900c3bb742d06743fd21ac58 (diff) | |
| download | oslo-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.py | 24 | ||||
| -rw-r--r-- | tests/unit/test_utils.py | 6 |
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): |
