Statically verify interface implementations, and fix all the resulting bugs
diff --git a/cryptography/hazmat/backends/commoncrypto/hashes.py b/cryptography/hazmat/backends/commoncrypto/hashes.py
index ebad720..217f4e8 100644
--- a/cryptography/hazmat/backends/commoncrypto/hashes.py
+++ b/cryptography/hazmat/backends/commoncrypto/hashes.py
@@ -21,7 +21,7 @@
 @utils.register_interface(interfaces.HashContext)
 class _HashContext(object):
     def __init__(self, backend, algorithm, ctx=None):
-        self.algorithm = algorithm
+        self._algorithm = algorithm
         self._backend = backend
 
         if ctx is None:
@@ -39,6 +39,8 @@
 
         self._ctx = ctx
 
+    algorithm = utils.read_only_property("_algorithm")
+
     def copy(self):
         methods = self._backend._hash_mapping[self.algorithm.name]
         new_ctx = self._backend._ffi.new(methods.ctx)
diff --git a/cryptography/hazmat/backends/commoncrypto/hmac.py b/cryptography/hazmat/backends/commoncrypto/hmac.py
index ec3a878..404aac6 100644
--- a/cryptography/hazmat/backends/commoncrypto/hmac.py
+++ b/cryptography/hazmat/backends/commoncrypto/hmac.py
@@ -21,7 +21,7 @@
 @utils.register_interface(interfaces.HashContext)
 class _HMACContext(object):
     def __init__(self, backend, key, algorithm, ctx=None):
-        self.algorithm = algorithm
+        self._algorithm = algorithm
         self._backend = backend
         if ctx is None:
             ctx = self._backend._ffi.new("CCHmacContext *")
@@ -39,6 +39,8 @@
         self._ctx = ctx
         self._key = key
 
+    algorithm = utils.read_only_property("_algorithm")
+
     def copy(self):
         copied_ctx = self._backend._ffi.new("CCHmacContext *")
         # CommonCrypto has no APIs for copying HMACs, so we have to copy the
diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py
index e873f50..c62b790 100644
--- a/cryptography/hazmat/backends/multibackend.py
+++ b/cryptography/hazmat/backends/multibackend.py
@@ -47,33 +47,33 @@
             if isinstance(b, interface):
                 yield b
 
-    def cipher_supported(self, algorithm, mode):
+    def cipher_supported(self, cipher, mode):
         return any(
-            b.cipher_supported(algorithm, mode)
+            b.cipher_supported(cipher, mode)
             for b in self._filtered_backends(CipherBackend)
         )
 
-    def create_symmetric_encryption_ctx(self, algorithm, mode):
+    def create_symmetric_encryption_ctx(self, cipher, mode):
         for b in self._filtered_backends(CipherBackend):
             try:
-                return b.create_symmetric_encryption_ctx(algorithm, mode)
+                return b.create_symmetric_encryption_ctx(cipher, mode)
             except UnsupportedAlgorithm:
                 pass
         raise UnsupportedAlgorithm(
             "cipher {0} in {1} mode is not supported by this backend.".format(
-                algorithm.name, mode.name if mode else mode),
+                cipher.name, mode.name if mode else mode),
             _Reasons.UNSUPPORTED_CIPHER
         )
 
-    def create_symmetric_decryption_ctx(self, algorithm, mode):
+    def create_symmetric_decryption_ctx(self, cipher, mode):
         for b in self._filtered_backends(CipherBackend):
             try:
-                return b.create_symmetric_decryption_ctx(algorithm, mode)
+                return b.create_symmetric_decryption_ctx(cipher, mode)
             except UnsupportedAlgorithm:
                 pass
         raise UnsupportedAlgorithm(
             "cipher {0} in {1} mode is not supported by this backend.".format(
-                algorithm.name, mode.name if mode else mode),
+                cipher.name, mode.name if mode else mode),
             _Reasons.UNSUPPORTED_CIPHER
         )
 
diff --git a/cryptography/hazmat/backends/openssl/cmac.py b/cryptography/hazmat/backends/openssl/cmac.py
index da7b748..113188c 100644
--- a/cryptography/hazmat/backends/openssl/cmac.py
+++ b/cryptography/hazmat/backends/openssl/cmac.py
@@ -15,8 +15,10 @@
 
 
 from cryptography import utils
-from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
-from cryptography.hazmat.primitives import interfaces
+from cryptography.exceptions import (
+    InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.primitives import constant_time, interfaces
 from cryptography.hazmat.primitives.ciphers.modes import CBC
 
 
@@ -50,6 +52,8 @@
 
         self._ctx = ctx
 
+    algorithm = utils.read_only_property("_algorithm")
+
     def update(self, data):
         res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
         assert res == 1
@@ -78,3 +82,10 @@
         return _CMACContext(
             self._backend, self._algorithm, ctx=copied_ctx
         )
+
+    def verify(self, signature):
+        if not isinstance(signature, bytes):
+            raise TypeError("signature must be bytes.")
+        digest = self.finalize()
+        if not constant_time.bytes_eq(digest, signature):
+            raise InvalidSignature("Signature did not match digest.")
diff --git a/cryptography/hazmat/backends/openssl/dsa.py b/cryptography/hazmat/backends/openssl/dsa.py
index 2298e7d..8652d50 100644
--- a/cryptography/hazmat/backends/openssl/dsa.py
+++ b/cryptography/hazmat/backends/openssl/dsa.py
@@ -131,8 +131,8 @@
 
     key_size = utils.read_only_property("_key_size")
 
-    def signer(self, algorithm):
-        return _DSASignatureContext(self._backend, self, algorithm)
+    def signer(self, signature_algorithm):
+        return _DSASignatureContext(self._backend, self, signature_algorithm)
 
     def private_numbers(self):
         return dsa.DSAPrivateNumbers(
@@ -180,9 +180,9 @@
 
     key_size = utils.read_only_property("_key_size")
 
-    def verifier(self, signature, algorithm):
+    def verifier(self, signature, signature_algorithm):
         return _DSAVerificationContext(
-            self._backend, self, signature, algorithm
+            self._backend, self, signature, signature_algorithm
         )
 
     def public_numbers(self):
diff --git a/cryptography/hazmat/backends/openssl/hashes.py b/cryptography/hazmat/backends/openssl/hashes.py
index da91eef..591c014 100644
--- a/cryptography/hazmat/backends/openssl/hashes.py
+++ b/cryptography/hazmat/backends/openssl/hashes.py
@@ -22,7 +22,7 @@
 @utils.register_interface(interfaces.HashContext)
 class _HashContext(object):
     def __init__(self, backend, algorithm, ctx=None):
-        self.algorithm = algorithm
+        self._algorithm = algorithm
 
         self._backend = backend
 
@@ -44,6 +44,8 @@
 
         self._ctx = ctx
 
+    algorithm = utils.read_only_property("_algorithm")
+
     def copy(self):
         copied_ctx = self._backend._lib.EVP_MD_CTX_create()
         copied_ctx = self._backend._ffi.gc(
diff --git a/cryptography/hazmat/backends/openssl/hmac.py b/cryptography/hazmat/backends/openssl/hmac.py
index 3f1576f..f22b086 100644
--- a/cryptography/hazmat/backends/openssl/hmac.py
+++ b/cryptography/hazmat/backends/openssl/hmac.py
@@ -22,7 +22,7 @@
 @utils.register_interface(interfaces.HashContext)
 class _HMACContext(object):
     def __init__(self, backend, key, algorithm, ctx=None):
-        self.algorithm = algorithm
+        self._algorithm = algorithm
         self._backend = backend
 
         if ctx is None:
@@ -47,6 +47,8 @@
         self._ctx = ctx
         self._key = key
 
+    algorithm = utils.read_only_property("_algorithm")
+
     def copy(self):
         copied_ctx = self._backend._ffi.new("HMAC_CTX *")
         self._backend._lib.HMAC_CTX_init(copied_ctx)
diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py
index 509b4de..d995b87 100644
--- a/cryptography/hazmat/primitives/ciphers/modes.py
+++ b/cryptography/hazmat/primitives/ciphers/modes.py
@@ -17,10 +17,10 @@
 from cryptography.hazmat.primitives import interfaces
 
 
-def _check_iv_length(mode, algorithm):
-    if len(mode.initialization_vector) * 8 != algorithm.block_size:
+def _check_iv_length(self, algorithm):
+    if len(self.initialization_vector) * 8 != algorithm.block_size:
         raise ValueError("Invalid IV size ({0}) for {1}.".format(
-            len(mode.initialization_vector), mode.name
+            len(self.initialization_vector), self.name
         ))
 
 
@@ -30,8 +30,9 @@
     name = "CBC"
 
     def __init__(self, initialization_vector):
-        self.initialization_vector = initialization_vector
+        self._initialization_vector = initialization_vector
 
+    initialization_vector = utils.read_only_property("_initialization_vector")
     validate_for_algorithm = _check_iv_length
 
 
@@ -49,8 +50,9 @@
     name = "OFB"
 
     def __init__(self, initialization_vector):
-        self.initialization_vector = initialization_vector
+        self._initialization_vector = initialization_vector
 
+    initialization_vector = utils.read_only_property("_initialization_vector")
     validate_for_algorithm = _check_iv_length
 
 
@@ -60,8 +62,9 @@
     name = "CFB"
 
     def __init__(self, initialization_vector):
-        self.initialization_vector = initialization_vector
+        self._initialization_vector = initialization_vector
 
+    initialization_vector = utils.read_only_property("_initialization_vector")
     validate_for_algorithm = _check_iv_length
 
 
@@ -71,8 +74,9 @@
     name = "CFB8"
 
     def __init__(self, initialization_vector):
-        self.initialization_vector = initialization_vector
+        self._initialization_vector = initialization_vector
 
+    initialization_vector = utils.read_only_property("_initialization_vector")
     validate_for_algorithm = _check_iv_length
 
 
@@ -82,7 +86,9 @@
     name = "CTR"
 
     def __init__(self, nonce):
-        self.nonce = nonce
+        self._nonce = nonce
+
+    nonce = utils.read_only_property("_nonce")
 
     def validate_for_algorithm(self, algorithm):
         if len(self.nonce) * 8 != algorithm.block_size:
@@ -109,8 +115,11 @@
                     min_tag_length)
             )
 
-        self.initialization_vector = initialization_vector
-        self.tag = tag
+        self._initialization_vector = initialization_vector
+        self._tag = tag
+
+    tag = utils.read_only_property("_tag")
+    initialization_vector = utils.read_only_property("_initialization_vector")
 
     def validate_for_algorithm(self, algorithm):
         pass
diff --git a/cryptography/hazmat/primitives/cmac.py b/cryptography/hazmat/primitives/cmac.py
index 7ae5c11..a70a9a4 100644
--- a/cryptography/hazmat/primitives/cmac.py
+++ b/cryptography/hazmat/primitives/cmac.py
@@ -15,10 +15,10 @@
 
 from cryptography import utils
 from cryptography.exceptions import (
-    AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
+    AlreadyFinalized, UnsupportedAlgorithm, _Reasons
 )
 from cryptography.hazmat.backends.interfaces import CMACBackend
-from cryptography.hazmat.primitives import constant_time, interfaces
+from cryptography.hazmat.primitives import interfaces
 
 
 @utils.register_interface(interfaces.MACContext)
@@ -57,11 +57,7 @@
         return digest
 
     def verify(self, signature):
-        if not isinstance(signature, bytes):
-            raise TypeError("signature must be bytes.")
-        digest = self.finalize()
-        if not constant_time.bytes_eq(digest, signature):
-            raise InvalidSignature("Signature did not match digest.")
+        self._ctx.verify(signature)
 
     def copy(self):
         if self._ctx is None:
diff --git a/cryptography/hazmat/primitives/hashes.py b/cryptography/hazmat/primitives/hashes.py
index 04f7620..8c2284e 100644
--- a/cryptography/hazmat/primitives/hashes.py
+++ b/cryptography/hazmat/primitives/hashes.py
@@ -32,7 +32,7 @@
 
         if not isinstance(algorithm, interfaces.HashAlgorithm):
             raise TypeError("Expected instance of interfaces.HashAlgorithm.")
-        self.algorithm = algorithm
+        self._algorithm = algorithm
 
         self._backend = backend
 
@@ -41,6 +41,8 @@
         else:
             self._ctx = ctx
 
+    algorithm = utils.read_only_property("_algorithm")
+
     def update(self, data):
         if self._ctx is None:
             raise AlreadyFinalized("Context was already finalized.")
diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py
index 2329243..22a3139 100644
--- a/cryptography/hazmat/primitives/hmac.py
+++ b/cryptography/hazmat/primitives/hmac.py
@@ -33,7 +33,7 @@
 
         if not isinstance(algorithm, interfaces.HashAlgorithm):
             raise TypeError("Expected instance of interfaces.HashAlgorithm.")
-        self.algorithm = algorithm
+        self._algorithm = algorithm
 
         self._backend = backend
         self._key = key
@@ -42,12 +42,14 @@
         else:
             self._ctx = ctx
 
-    def update(self, msg):
+    algorithm = utils.read_only_property("_algorithm")
+
+    def update(self, data):
         if self._ctx is None:
             raise AlreadyFinalized("Context was already finalized.")
-        if not isinstance(msg, bytes):
-            raise TypeError("msg must be bytes.")
-        self._ctx.update(msg)
+        if not isinstance(data, bytes):
+            raise TypeError("data must be bytes.")
+        self._ctx.update(data)
 
     def copy(self):
         if self._ctx is None:
diff --git a/cryptography/utils.py b/cryptography/utils.py
index 8fbcabc..03c8c0e 100644
--- a/cryptography/utils.py
+++ b/cryptography/utils.py
@@ -23,6 +23,7 @@
 
 def register_interface(iface):
     def register_decorator(klass):
+        verify_interface(iface, klass)
         iface.register(klass)
         return klass
     return register_decorator
diff --git a/tests/hazmat/backends/test_commoncrypto.py b/tests/hazmat/backends/test_commoncrypto.py
index 28d1a6c..b79c02e 100644
--- a/tests/hazmat/backends/test_commoncrypto.py
+++ b/tests/hazmat/backends/test_commoncrypto.py
@@ -30,6 +30,7 @@
 class DummyCipher(object):
     name = "dummy-cipher"
     block_size = 128
+    key_size = 128
 
 
 @pytest.mark.skipif("commoncrypto" not in
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 3bea413..83494d0 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -51,6 +51,7 @@
 @utils.register_interface(interfaces.CipherAlgorithm)
 class DummyCipher(object):
     name = "dummy-cipher"
+    key_size = 128
 
 
 @utils.register_interface(interfaces.AsymmetricPadding)
@@ -61,6 +62,8 @@
 @utils.register_interface(interfaces.HashAlgorithm)
 class DummyHash(object):
     name = "dummy-hash"
+    block_size = 128
+    digest_size = 128
 
 
 class DummyMGF(object):
diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py
index 022e3af..0b90dd9 100644
--- a/tests/hazmat/primitives/test_block.py
+++ b/tests/hazmat/primitives/test_block.py
@@ -43,6 +43,7 @@
 @utils.register_interface(interfaces.CipherAlgorithm)
 class DummyCipher(object):
     name = "dummy-cipher"
+    key_size = 128
 
 
 @pytest.mark.cipher
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index 1b3bb9b..9ed762c 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -68,11 +68,20 @@
 
 @utils.register_interface(interfaces.EllipticCurveSignatureAlgorithm)
 class DummySignatureAlgorithm(object):
-    pass
+    algorithm = None
 
 
 @utils.register_interface(EllipticCurveBackend)
 class DeprecatedDummyECBackend(object):
+    def _unimplemented(self):
+        raise NotImplementedError
+
+    elliptic_curve_signature_algorithm_supported = _unimplemented
+    load_elliptic_curve_private_numbers = _unimplemented
+    load_elliptic_curve_public_numbers = _unimplemented
+    elliptic_curve_supported = _unimplemented
+    generate_elliptic_curve_private_key = _unimplemented
+
     def elliptic_curve_private_key_from_numbers(self, numbers):
         return b"private_key"
 
diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py
index ffd65bd..2bf1f8e 100644
--- a/tests/hazmat/primitives/test_hashes.py
+++ b/tests/hazmat/primitives/test_hashes.py
@@ -33,6 +33,8 @@
 @utils.register_interface(interfaces.HashAlgorithm)
 class UnsupportedDummyHash(object):
     name = "unsupported-dummy-hash"
+    block_size = 128
+    digest_size = 128
 
 
 @pytest.mark.hash
diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py
index 77dfb6b..21be73a 100644
--- a/tests/hazmat/primitives/test_hmac.py
+++ b/tests/hazmat/primitives/test_hmac.py
@@ -32,7 +32,9 @@
 
 @utils.register_interface(interfaces.HashAlgorithm)
 class UnsupportedDummyHash(object):
-        name = "unsupported-dummy-hash"
+    name = "unsupported-dummy-hash"
+    block_size = 128
+    digest_size = 128
 
 
 @pytest.mark.supported(
diff --git a/tests/hazmat/primitives/test_pbkdf2hmac.py b/tests/hazmat/primitives/test_pbkdf2hmac.py
index e928fc6..fa92587 100644
--- a/tests/hazmat/primitives/test_pbkdf2hmac.py
+++ b/tests/hazmat/primitives/test_pbkdf2hmac.py
@@ -31,6 +31,8 @@
 @utils.register_interface(interfaces.HashAlgorithm)
 class DummyHash(object):
     name = "dummy-hash"
+    block_size = 128
+    digest_size = 128
 
 
 class TestPBKDF2HMAC(object):