summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-01-21 04:25:57 +0000
committerGerrit Code Review <review@openstack.org>2016-01-21 04:25:57 +0000
commit123e12201aebeeccc22e711eca40fa4cc3e13b2f (patch)
tree84ebfb52b798570063ca10d1fcd1f3bf1e3e2a6b
parent68d55698549511094612b7206dc2456701aaf087 (diff)
parent9d58253588401113ee62fffd049e4471f3cebc38 (diff)
downloadoslo-utils-123e12201aebeeccc22e711eca40fa4cc3e13b2f.tar.gz
Merge "Create secretutils and include 'constant_time_compare' function"
-rw-r--r--doc/source/api/secretutils.rst6
-rw-r--r--doc/source/index.rst1
-rw-r--r--oslo_utils/secretutils.py35
-rw-r--r--oslo_utils/tests/test_secretutils.py52
4 files changed, 94 insertions, 0 deletions
diff --git a/doc/source/api/secretutils.rst b/doc/source/api/secretutils.rst
new file mode 100644
index 0000000..fb88a0c
--- /dev/null
+++ b/doc/source/api/secretutils.rst
@@ -0,0 +1,6 @@
+=============
+ secretutils
+=============
+
+.. automodule:: oslo_utils.secretutils
+ :members:
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 0262d63..acc042b 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -28,6 +28,7 @@ API Documentation
api/importutils
api/netutils
api/reflection
+ api/secretutils
api/strutils
api/timeutils
api/units
diff --git a/oslo_utils/secretutils.py b/oslo_utils/secretutils.py
new file mode 100644
index 0000000..fd5c317
--- /dev/null
+++ b/oslo_utils/secretutils.py
@@ -0,0 +1,35 @@
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import hmac
+
+
+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 len(first) != len(second):
+ return False
+ result = 0
+ for x, y in zip(first, second):
+ result |= ord(x) ^ ord(y)
+ return result == 0
diff --git a/oslo_utils/tests/test_secretutils.py b/oslo_utils/tests/test_secretutils.py
new file mode 100644
index 0000000..916610b
--- /dev/null
+++ b/oslo_utils/tests/test_secretutils.py
@@ -0,0 +1,52 @@
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslotest import base as test_base
+import testscenarios
+
+from oslo_utils import secretutils
+
+
+class SecretUtilsTest(testscenarios.TestWithScenarios,
+ test_base.BaseTestCase):
+
+ scenarios = [
+ ('binary', {'converter': lambda text: text.encode('utf-8')}),
+ ('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
+ self.assertTrue(ctc(self.converter(u'abcd'),
+ self.converter(u'abcd')))
+ self.assertTrue(ctc(self.converter(u''),
+ self.converter(u'')))
+ self.assertFalse(ctc(self.converter(u'abcd'),
+ self.converter(u'efgh')))
+ self.assertFalse(ctc(self.converter(u'abc'),
+ self.converter(u'abcd')))
+ self.assertFalse(ctc(self.converter(u'abc'),
+ self.converter(u'abc\x00')))
+ self.assertFalse(ctc(self.converter(u''),
+ self.converter(u'abc')))
+ self.assertTrue(ctc(self.converter(u'abcd1234'),
+ self.converter(u'abcd1234')))
+ self.assertFalse(ctc(self.converter(u'abcd1234'),
+ self.converter(u'ABCD234')))
+ self.assertFalse(ctc(self.converter(u'abcd1234'),
+ self.converter(u'a')))
+ self.assertFalse(ctc(self.converter(u'abcd1234'),
+ self.converter(u'1234abcd')))