Merge pull request #227 from dreid/explicit-backend-in-hazmat

Explicit backend
diff --git a/cryptography/hazmat/bindings/__init__.py b/cryptography/hazmat/bindings/__init__.py
index eb82899..bd15819 100644
--- a/cryptography/hazmat/bindings/__init__.py
+++ b/cryptography/hazmat/bindings/__init__.py
@@ -14,7 +14,10 @@
 from cryptography.hazmat.bindings import openssl
 
 
-_default_backend = openssl.backend
 _ALL_BACKENDS = [
     openssl.backend
 ]
+
+
+def default_backend():
+    return openssl.backend
diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py
index 3d733af..48e6da6 100644
--- a/cryptography/hazmat/primitives/ciphers/base.py
+++ b/cryptography/hazmat/primitives/ciphers/base.py
@@ -19,12 +19,7 @@
 
 
 class Cipher(object):
-    def __init__(self, algorithm, mode, backend=None):
-        if backend is None:
-            from cryptography.hazmat.bindings import (
-                _default_backend as backend,
-            )
-
+    def __init__(self, algorithm, mode, backend):
         if not isinstance(algorithm, interfaces.CipherAlgorithm):
             raise TypeError("Expected interface of interfaces.CipherAlgorithm")
 
diff --git a/cryptography/hazmat/primitives/hashes.py b/cryptography/hazmat/primitives/hashes.py
index 93fc8c4..bee188b 100644
--- a/cryptography/hazmat/primitives/hashes.py
+++ b/cryptography/hazmat/primitives/hashes.py
@@ -22,15 +22,11 @@
 
 @utils.register_interface(interfaces.HashContext)
 class Hash(object):
-    def __init__(self, algorithm, backend=None, ctx=None):
+    def __init__(self, algorithm, backend, ctx=None):
         if not isinstance(algorithm, interfaces.HashAlgorithm):
             raise TypeError("Expected instance of interfaces.HashAlgorithm.")
         self.algorithm = algorithm
 
-        if backend is None:
-            from cryptography.hazmat.bindings import _default_backend
-            backend = _default_backend
-
         self._backend = backend
 
         if ctx is None:
diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py
index 08dfae0..618bccc 100644
--- a/cryptography/hazmat/primitives/hmac.py
+++ b/cryptography/hazmat/primitives/hmac.py
@@ -22,15 +22,11 @@
 
 @utils.register_interface(interfaces.HashContext)
 class HMAC(object):
-    def __init__(self, key, algorithm, ctx=None, backend=None):
+    def __init__(self, key, algorithm, backend, ctx=None):
         if not isinstance(algorithm, interfaces.HashAlgorithm):
             raise TypeError("Expected instance of interfaces.HashAlgorithm.")
         self.algorithm = algorithm
 
-        if backend is None:
-            from cryptography.hazmat.bindings import _default_backend
-            backend = _default_backend
-
         self._backend = backend
         self._key = key
         if ctx is None:
diff --git a/docs/hazmat/bindings/index.rst b/docs/hazmat/bindings/index.rst
index 11355bf..746f459 100644
--- a/docs/hazmat/bindings/index.rst
+++ b/docs/hazmat/bindings/index.rst
@@ -8,3 +8,27 @@
 
     openssl
     interfaces
+
+
+Getting a Backend Provider
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. currentmodule:: cryptography.hazmat.bindings
+
+``cryptography`` aims to support multiple backends to ensure it can provide
+the widest number of supported cryptographic algorithms as well as supporting
+platform specific implementations.
+
+You can get the default backend by calling
+:func:`~default_backend`.
+
+The default backend will change over time as we implement new backends and
+the libraries we use in those backends changes.
+
+
+.. function:: default_backend()
+
+    :returns: An object that provides at least
+        :class:`~interfaces.CipherBackend`, :class:`~interfaces.HashBackend`, and
+        :class:`~interfaces.HMACBackend`.
+
diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst
index 52e8770..312d7e6 100644
--- a/docs/hazmat/primitives/cryptographic-hashes.rst
+++ b/docs/hazmat/primitives/cryptographic-hashes.rst
@@ -5,7 +5,7 @@
 
 .. currentmodule:: cryptography.hazmat.primitives.hashes
 
-.. class:: Hash(algorithm)
+.. class:: Hash(algorithm, backend)
 
     A cryptographic hash function takes an arbitrary block of data and
     calculates a fixed-size bit string (a digest), such that different data
@@ -20,8 +20,9 @@
 
     .. doctest::
 
+        >>> from cryptography.hazmat.bindings import default_backend
         >>> from cryptography.hazmat.primitives import hashes
-        >>> digest = hashes.Hash(hashes.SHA256())
+        >>> digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
         >>> digest.update(b"abc")
         >>> digest.update(b"123")
         >>> digest.finalize()
@@ -33,6 +34,14 @@
     upgrading the hash algorithm you use over time. For more information, see
     `Lifetimes of cryptographic hash functions`_.
 
+    :param algorithm: A
+        :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
+        provider such as those described in
+        :ref:`below <cryptographic-hash-algorithms>`.
+    :param backend: A
+        :class:`~cryptography.hazmat.bindings.interfaces.HashBackend`
+        provider.
+
     .. method:: update(data)
 
         :param bytes data: The bytes you wish to hash.
@@ -59,6 +68,8 @@
         :return bytes: The message digest as bytes.
 
 
+.. _cryptographic-hash-algorithms:
+
 SHA-1
 ~~~~~
 
diff --git a/docs/hazmat/primitives/hmac.rst b/docs/hazmat/primitives/hmac.rst
index cff2dbf..db5e98d 100644
--- a/docs/hazmat/primitives/hmac.rst
+++ b/docs/hazmat/primitives/hmac.rst
@@ -15,7 +15,7 @@
 secret key. You can use an HMAC to verify integrity as well as authenticate a
 message.
 
-.. class:: HMAC(key, algorithm)
+.. class:: HMAC(key, algorithm, backend)
 
     HMAC objects take a ``key`` and a provider of
     :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`.
@@ -27,12 +27,23 @@
 
     .. doctest::
 
+        >>> from cryptography.hazmat.bindings import default_backend
         >>> from cryptography.hazmat.primitives import hashes, hmac
-        >>> h = hmac.HMAC(key, hashes.SHA256())
+        >>> h = hmac.HMAC(key, hashes.SHA256(), backend=default_backend())
         >>> h.update(b"message to hash")
         >>> h.finalize()
         '#F\xdaI\x8b"e\xc4\xf1\xbb\x9a\x8fc\xff\xf5\xdex.\xbc\xcd/+\x8a\x86\x1d\x84\'\xc3\xa6\x1d\xd8J'
 
+
+    :param key: Secret key as ``bytes``.
+    :param algorithm: A
+        :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
+        provider such as those described in
+        :ref:`Cryptographic Hashes <cryptographic-hash-algorithms>`.
+    :param backend: A
+        :class:`~cryptography.hazmat.bindings.interfaces.HMACBackend`
+        provider.
+
     .. method:: update(msg)
 
         :param bytes msg: The bytes to hash and authenticate.
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 732af33..4ab9140 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -12,6 +12,9 @@
     key = binascii.unhexlify(b"0" * 32)
     iv = binascii.unhexlify(b"0" * 32)
 
+    from cryptography.hazmat.bindings import default_backend
+    backend = default_backend()
+
 
 Symmetric encryption is a way to encrypt (hide the plaintext value) material
 where the sender and receiver both use the same key. Note that symmetric
@@ -22,7 +25,7 @@
 message authentication code, such as :doc:`HMAC </hazmat/primitives/hmac>`, in
 an "encrypt-then-MAC" formulation as `described by Colin Percival`_.
 
-.. class:: Cipher(algorithm, mode)
+.. class:: Cipher(algorithm, mode, backend)
 
     Cipher objects combine an algorithm (such as
     :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`) with a
@@ -34,15 +37,23 @@
     .. doctest::
 
         >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
-        >>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
+        >>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
         >>> encryptor = cipher.encryptor()
         >>> ct = encryptor.update(b"a secret message") + encryptor.finalize()
         >>> decryptor = cipher.decryptor()
         >>> decryptor.update(ct) + decryptor.finalize()
         'a secret message'
 
-    :param algorithms: One of the algorithms described below.
-    :param mode: One of the modes described below.
+    :param algorithms: A
+        :class:`~cryptography.hazmat.primitives.interfaces.CipherAlgorithm`
+        provider such as those described
+        :ref:`below <symmetric-encryption-algorithms>`.
+    :param mode: A :class:`~cryptography.hazmat.primitives.interfaces.Mode`
+        provider such as those described
+        :ref:`below <symmetric-encryption-modes>`.
+    :param backend: A
+        :class:`~cryptography.hazmat.bindings.interfaces.CipherBackend`
+        provider.
 
     .. method:: encryptor()
 
@@ -107,6 +118,8 @@
         :meth:`update` and :meth:`finalize` will raise
         :class:`~cryptography.exceptions.AlreadyFinalized`.
 
+.. _symmetric-encryption-algorithms:
+
 Algorithms
 ~~~~~~~~~~
 
@@ -188,7 +201,7 @@
 
         >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
         >>> algorithm = algorithms.ARC4(key)
-        >>> cipher = Cipher(algorithm, mode=None)
+        >>> cipher = Cipher(algorithm, mode=None, backend=backend)
         >>> encryptor = cipher.encryptor()
         >>> ct = encryptor.update(b"a secret message")
         >>> decryptor = cipher.decryptor()
diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py
index 0ebf38a..1eb6f20 100644
--- a/tests/hazmat/bindings/test_openssl.py
+++ b/tests/hazmat/bindings/test_openssl.py
@@ -15,6 +15,7 @@
 
 from cryptography import utils
 from cryptography.exceptions import UnsupportedAlgorithm
+from cryptography.hazmat.bindings import default_backend
 from cryptography.hazmat.bindings.openssl.backend import backend, Backend
 from cryptography.hazmat.primitives import interfaces
 from cryptography.hazmat.primitives.ciphers import Cipher
@@ -35,6 +36,9 @@
     def test_backend_exists(self):
         assert backend
 
+    def test_is_default(self):
+        assert backend == default_backend()
+
     def test_openssl_version_text(self):
         """
         This test checks the value of OPENSSL_VERSION_TEXT.
diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py
index ea40127..4a8e88b 100644
--- a/tests/hazmat/primitives/test_block.py
+++ b/tests/hazmat/primitives/test_block.py
@@ -31,23 +31,19 @@
 
 
 class TestCipher(object):
-    def test_instantiate_without_backend(self):
-        Cipher(
-            algorithms.AES(binascii.unhexlify(b"0" * 32)),
-            modes.CBC(binascii.unhexlify(b"0" * 32))
-        )
-
-    def test_creates_encryptor(self):
+    def test_creates_encryptor(self, backend):
         cipher = Cipher(
             algorithms.AES(binascii.unhexlify(b"0" * 32)),
-            modes.CBC(binascii.unhexlify(b"0" * 32))
+            modes.CBC(binascii.unhexlify(b"0" * 32)),
+            backend
         )
         assert isinstance(cipher.encryptor(), interfaces.CipherContext)
 
-    def test_creates_decryptor(self):
+    def test_creates_decryptor(self, backend):
         cipher = Cipher(
             algorithms.AES(binascii.unhexlify(b"0" * 32)),
-            modes.CBC(binascii.unhexlify(b"0" * 32))
+            modes.CBC(binascii.unhexlify(b"0" * 32)),
+            backend
         )
         assert isinstance(cipher.decryptor(), interfaces.CipherContext)
 
diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py
index 367e764..ff42e8f 100644
--- a/tests/hazmat/primitives/test_hashes.py
+++ b/tests/hazmat/primitives/test_hashes.py
@@ -20,7 +20,6 @@
 import six
 
 from cryptography.exceptions import AlreadyFinalized
-from cryptography.hazmat.bindings import _default_backend
 from cryptography.hazmat.primitives import hashes
 
 from .utils import generate_base_hash_test
@@ -41,19 +40,12 @@
         assert h._backend is pretend_backend
         assert h.copy()._backend is h._backend
 
-    def test_default_backend_creation(self):
-        """
-        This test assumes the presence of SHA1 in the default backend.
-        """
-        h = hashes.Hash(hashes.SHA1())
-        assert h._backend is _default_backend
-
-    def test_hash_algorithm_instance(self):
+    def test_hash_algorithm_instance(self, backend):
         with pytest.raises(TypeError):
-            hashes.Hash(hashes.SHA1)
+            hashes.Hash(hashes.SHA1, backend=backend)
 
-    def test_raises_after_finalize(self):
-        h = hashes.Hash(hashes.SHA1())
+    def test_raises_after_finalize(self, backend):
+        h = hashes.Hash(hashes.SHA1(), backend=backend)
         h.finalize()
 
         with pytest.raises(AlreadyFinalized):
diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py
index d17049e..992bcb1 100644
--- a/tests/hazmat/primitives/test_hmac.py
+++ b/tests/hazmat/primitives/test_hmac.py
@@ -47,12 +47,12 @@
         assert h._backend is pretend_backend
         assert h.copy()._backend is pretend_backend
 
-    def test_hmac_algorithm_instance(self):
+    def test_hmac_algorithm_instance(self, backend):
         with pytest.raises(TypeError):
-            hmac.HMAC(b"key", hashes.SHA1)
+            hmac.HMAC(b"key", hashes.SHA1, backend=backend)
 
-    def test_raises_after_finalize(self):
-        h = hmac.HMAC(b"key", hashes.SHA1())
+    def test_raises_after_finalize(self, backend):
+        h = hmac.HMAC(b"key", hashes.SHA1(), backend=backend)
         h.finalize()
 
         with pytest.raises(AlreadyFinalized):
diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py
index 9327b0e..6c67ddb 100644
--- a/tests/hazmat/primitives/utils.py
+++ b/tests/hazmat/primitives/utils.py
@@ -42,7 +42,7 @@
     cipher = Cipher(
         cipher_factory(**params),
         mode_factory(**params),
-        backend
+        backend=backend
     )
     encryptor = cipher.encryptor()
     actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext))
@@ -82,7 +82,7 @@
     plaintext = params.pop("plaintext")
     ciphertext = params.pop("ciphertext")
     offset = params.pop("offset")
-    cipher = Cipher(cipher_factory(**params), None, backend)
+    cipher = Cipher(cipher_factory(**params), None, backend=backend)
     encryptor = cipher.encryptor()
     # throw away offset bytes
     encryptor.update(b"\x00" * int(offset))
@@ -211,7 +211,7 @@
     msg = params[0]
     md = params[1]
     key = params[2]
-    h = hmac.HMAC(binascii.unhexlify(key), algorithm)
+    h = hmac.HMAC(binascii.unhexlify(key), algorithm, backend=backend)
     h.update(binascii.unhexlify(msg))
     assert h.finalize() == binascii.unhexlify(md.encode("ascii"))
 
@@ -233,7 +233,7 @@
     if only_if is not None and not only_if(backend):
         pytest.skip(skip_message)
     key = b"ab"
-    h = hmac.HMAC(binascii.unhexlify(key), algorithm)
+    h = hmac.HMAC(binascii.unhexlify(key), algorithm, backend=backend)
     h_copy = h.copy()
     assert h != h_copy
     assert h._ctx != h_copy._ctx