Merge pull request #308 from alex/rename-bindings

Renamed bindings to backends
diff --git a/cryptography/hazmat/primitives/constant_time.py b/cryptography/hazmat/primitives/constant_time.py
new file mode 100644
index 0000000..a835150
--- /dev/null
+++ b/cryptography/hazmat/primitives/constant_time.py
@@ -0,0 +1,53 @@
+# 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 __future__ import absolute_import, division, print_function
+
+import cffi
+
+import six
+
+
+_ffi = cffi.FFI()
+_ffi.cdef("""
+bool Cryptography_constant_time_bytes_eq(uint8_t *, size_t, uint8_t *, size_t);
+""")
+_lib = _ffi.verify("""
+#include <stdbool.h>
+
+bool Cryptography_constant_time_bytes_eq(uint8_t *a, size_t len_a, uint8_t *b,
+                                         size_t len_b) {
+    size_t i = 0;
+    uint8_t mismatch = 0;
+    if (len_a != len_b) {
+        return false;
+    }
+    for (i = 0; i < len_a; i++) {
+        mismatch |= a[i] ^ b[i];
+    }
+
+    /* Make sure any bits set are copied to the lowest bit */
+    mismatch |= mismatch >> 4;
+    mismatch |= mismatch >> 2;
+    mismatch |= mismatch >> 1;
+    /* Now check the low bit to see if it's set */
+    return (mismatch & 1) == 0;
+}
+""")
+
+
+def bytes_eq(a, b):
+    if isinstance(a, six.text_type) or isinstance(b, six.text_type):
+        raise TypeError("Unicode-objects must be encoded before comparing")
+
+    return _lib.Cryptography_constant_time_bytes_eq(a, len(a), b, len(b)) == 1
diff --git a/docs/conf.py b/docs/conf.py
index 77050e7..5092e4d 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -257,6 +257,5 @@
 # How to display URL addresses: 'footnote', 'no', or 'inline'.
 #texinfo_show_urls = 'footnote'
 
-
 # Example configuration for intersphinx: refer to the Python standard library.
 intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/docs/hazmat/primitives/constant-time.rst b/docs/hazmat/primitives/constant-time.rst
new file mode 100644
index 0000000..632e7c6
--- /dev/null
+++ b/docs/hazmat/primitives/constant-time.rst
@@ -0,0 +1,38 @@
+.. hazmat::
+
+Constant time functions
+=======================
+
+.. currentmodule:: cryptography.hazmat.primitives.constant_time
+
+This module contains functions for operating with secret data in a way that
+does not leak information about that data through how long it takes to perform
+the operation. These functions should be used whenever operating on secret data
+along with data that is user supplied.
+
+An example would be comparing a HMAC signature received from a client to the
+one generated by the server code for authentication purposes.
+
+For more information about this sort of issue, see `Coda Hale's blog post`_
+about the timing attacks on KeyCzar and Java's ``MessageDigest.isEqual()``.
+
+
+.. function:: bytes_eq(a, b)
+
+    Compare ``a`` and ``b`` to one another in constant time if they are of the
+    same length.
+
+    .. doctest::
+
+        >>> from cryptography.hazmat.primitives import constant_time
+        >>> constant_time.bytes_eq(b"foo", b"foo")
+        True
+        >>> constant_time.bytes_eq(b"foo", b"bar")
+        False
+
+    :param a bytes: The left-hand side.
+    :param b bytes: The right-hand side.
+    :returns boolean: True if ``a`` has the same bytes as ``b``.
+
+
+.. _`Coda Hale's blog post`: http://codahale.com/a-lesson-in-timing-attacks/
diff --git a/docs/hazmat/primitives/index.rst b/docs/hazmat/primitives/index.rst
index 614c414..b115fdb 100644
--- a/docs/hazmat/primitives/index.rst
+++ b/docs/hazmat/primitives/index.rst
@@ -10,4 +10,5 @@
     hmac
     symmetric-encryption
     padding
+    constant-time
     interfaces
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 9fccf55..f4d0457 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -266,16 +266,18 @@
 
     A good construction looks like:
 
-    .. code-block:: pycon
+    .. doctest::
 
         >>> import os
+        >>> from cryptography.hazmat.primitives.ciphers.modes import CBC
         >>> iv = os.urandom(16)
         >>> mode = CBC(iv)
 
     While the following is bad and will leak information:
 
-    .. code-block:: pycon
+    .. doctest::
 
+        >>> from cryptography.hazmat.primitives.ciphers.modes import CBC
         >>> iv = "a" * 16
         >>> mode = CBC(iv)
 
diff --git a/tests/hazmat/primitives/test_constant_time.py b/tests/hazmat/primitives/test_constant_time.py
new file mode 100644
index 0000000..dd910de
--- /dev/null
+++ b/tests/hazmat/primitives/test_constant_time.py
@@ -0,0 +1,41 @@
+# 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 __future__ import absolute_import, division, print_function
+
+import pytest
+
+import six
+
+from cryptography.hazmat.primitives import constant_time
+
+
+class TestConstantTimeBytesEq(object):
+    def test_reject_unicode(self):
+        with pytest.raises(TypeError):
+            constant_time.bytes_eq(b"foo", six.u("foo"))
+
+        with pytest.raises(TypeError):
+            constant_time.bytes_eq(six.u("foo"), b"foo")
+
+        with pytest.raises(TypeError):
+            constant_time.bytes_eq(six.u("foo"), six.u("foo"))
+
+    def test_compares(self):
+        assert constant_time.bytes_eq(b"foo", b"foo") is True
+
+        assert constant_time.bytes_eq(b"foo", b"bar") is False
+
+        assert constant_time.bytes_eq(b"foobar", b"foo") is False
+
+        assert constant_time.bytes_eq(b"foo", b"foobar") is False
diff --git a/tox.ini b/tox.ini
index 56603da..39fe024 100644
--- a/tox.ini
+++ b/tox.ini
@@ -17,6 +17,7 @@
 basepython = python2.7
 commands =
     sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html
+    sphinx-build -W -b latex -d {envtmpdir}/doctrees docs docs/_build/latex
     sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html
     sphinx-build -W -b linkcheck docs docs/_build/html