Merge pull request #1195 from public/ec-safety-docs

Advice on choosing a curve
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index e057b63..13bc23f 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,11 @@
 
 .. note:: This version is not yet released and is under active development.
 
+* **BACKWARDS INCOMPATIBLE:**
+  :class:`~cryptography.hazmat.primitives.ciphers.modes.GCM` no longer allows
+  truncation of tags by default. Previous versions of ``cryptography`` allowed
+  tags to be truncated by default, applications wishing to preserve this
+  behavior (not recommended) can pass the ``min_tag_length`` argument.
 * Added :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDFExpand`.
 * Added :class:`~cryptography.hazmat.primitives.ciphers.modes.CFB8` support
   for :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` and
diff --git a/cryptography/__about__.py b/cryptography/__about__.py
index ee53902..ccbcdfe 100644
--- a/cryptography/__about__.py
+++ b/cryptography/__about__.py
@@ -28,4 +28,4 @@
 __email__ = "cryptography-dev@python.org"
 
 __license__ = "Apache License, Version 2.0"
-__copyright__ = "Copyright 2013-2014 %s" % __author__
+__copyright__ = "Copyright 2013-2014 {0}".format(__author__)
diff --git a/cryptography/hazmat/backends/commoncrypto/backend.py b/cryptography/hazmat/backends/commoncrypto/backend.py
index 41be11f..7bab979 100644
--- a/cryptography/hazmat/backends/commoncrypto/backend.py
+++ b/cryptography/hazmat/backends/commoncrypto/backend.py
@@ -16,14 +16,16 @@
 from collections import namedtuple
 
 from cryptography import utils
-from cryptography.exceptions import (
-    InternalError, InvalidTag, UnsupportedAlgorithm, _Reasons
+from cryptography.exceptions import InternalError
+from cryptography.hazmat.backends.commoncrypto.ciphers import (
+    _CipherContext, _GCMCipherContext
 )
+from cryptography.hazmat.backends.commoncrypto.hashes import _HashContext
+from cryptography.hazmat.backends.commoncrypto.hmac import _HMACContext
 from cryptography.hazmat.backends.interfaces import (
     CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend
 )
 from cryptography.hazmat.bindings.commoncrypto.binding import Binding
-from cryptography.hazmat.primitives import constant_time, interfaces
 from cryptography.hazmat.primitives.ciphers.algorithms import (
     AES, ARC4, Blowfish, CAST5, TripleDES
 )
@@ -147,7 +149,7 @@
             buf,
             length
         )
-        self._check_response(res)
+        self._check_cipher_response(res)
 
         return self._ffi.buffer(buf)[:]
 
@@ -221,7 +223,7 @@
             self._lib.kCCModeRC4
         )
 
-    def _check_response(self, response):
+    def _check_cipher_response(self, response):
         if response == self._lib.kCCSuccess:
             return
         elif response == self._lib.kCCAlignmentError:
@@ -237,266 +239,15 @@
                 " Code: {0}.".format(response)
             )
 
-
-def _release_cipher_ctx(ctx):
-    """
-    Called by the garbage collector and used to safely dereference and
-    release the context.
-    """
-    if ctx[0] != backend._ffi.NULL:
-        res = backend._lib.CCCryptorRelease(ctx[0])
-        backend._check_response(res)
-        ctx[0] = backend._ffi.NULL
-
-
-@utils.register_interface(interfaces.CipherContext)
-class _CipherContext(object):
-    def __init__(self, backend, cipher, mode, operation):
-        self._backend = backend
-        self._cipher = cipher
-        self._mode = mode
-        self._operation = operation
-        # There is a bug in CommonCrypto where block ciphers do not raise
-        # kCCAlignmentError when finalizing if you supply non-block aligned
-        # data. To work around this we need to keep track of the block
-        # alignment ourselves, but only for alg+mode combos that require
-        # block alignment. OFB, CFB, and CTR make a block cipher algorithm
-        # into a stream cipher so we don't need to track them (and thus their
-        # block size is effectively 1 byte just like OpenSSL/CommonCrypto
-        # treat RC4 and other stream cipher block sizes).
-        # This bug has been filed as rdar://15589470
-        self._bytes_processed = 0
-        if (isinstance(cipher, interfaces.BlockCipherAlgorithm) and not
-                isinstance(mode, (OFB, CFB, CFB8, CTR))):
-            self._byte_block_size = cipher.block_size // 8
-        else:
-            self._byte_block_size = 1
-
-        registry = self._backend._cipher_registry
-        try:
-            cipher_enum, mode_enum = registry[type(cipher), type(mode)]
-        except KeyError:
-            raise UnsupportedAlgorithm(
-                "cipher {0} in {1} mode is not supported "
-                "by this backend.".format(
-                    cipher.name, mode.name if mode else mode),
-                _Reasons.UNSUPPORTED_CIPHER
-            )
-
-        ctx = self._backend._ffi.new("CCCryptorRef *")
-        ctx = self._backend._ffi.gc(ctx, _release_cipher_ctx)
-
-        if isinstance(mode, interfaces.ModeWithInitializationVector):
-            iv_nonce = mode.initialization_vector
-        elif isinstance(mode, interfaces.ModeWithNonce):
-            iv_nonce = mode.nonce
-        else:
-            iv_nonce = self._backend._ffi.NULL
-
-        if isinstance(mode, CTR):
-            mode_option = self._backend._lib.kCCModeOptionCTR_BE
-        else:
-            mode_option = 0
-
-        res = self._backend._lib.CCCryptorCreateWithMode(
-            operation,
-            mode_enum, cipher_enum,
-            self._backend._lib.ccNoPadding, iv_nonce,
-            cipher.key, len(cipher.key),
-            self._backend._ffi.NULL, 0, 0, mode_option, ctx)
-        self._backend._check_response(res)
-
-        self._ctx = ctx
-
-    def update(self, data):
-        # Count bytes processed to handle block alignment.
-        self._bytes_processed += len(data)
-        buf = self._backend._ffi.new(
-            "unsigned char[]", len(data) + self._byte_block_size - 1)
-        outlen = self._backend._ffi.new("size_t *")
-        res = self._backend._lib.CCCryptorUpdate(
-            self._ctx[0], data, len(data), buf,
-            len(data) + self._byte_block_size - 1, outlen)
-        self._backend._check_response(res)
-        return self._backend._ffi.buffer(buf)[:outlen[0]]
-
-    def finalize(self):
-        # Raise error if block alignment is wrong.
-        if self._bytes_processed % self._byte_block_size:
-            raise ValueError(
-                "The length of the provided data is not a multiple of "
-                "the block length."
-            )
-        buf = self._backend._ffi.new("unsigned char[]", self._byte_block_size)
-        outlen = self._backend._ffi.new("size_t *")
-        res = self._backend._lib.CCCryptorFinal(
-            self._ctx[0], buf, len(buf), outlen)
-        self._backend._check_response(res)
-        _release_cipher_ctx(self._ctx)
-        return self._backend._ffi.buffer(buf)[:outlen[0]]
-
-
-@utils.register_interface(interfaces.AEADCipherContext)
-@utils.register_interface(interfaces.AEADEncryptionContext)
-class _GCMCipherContext(object):
-    def __init__(self, backend, cipher, mode, operation):
-        self._backend = backend
-        self._cipher = cipher
-        self._mode = mode
-        self._operation = operation
-        self._tag = None
-
-        registry = self._backend._cipher_registry
-        try:
-            cipher_enum, mode_enum = registry[type(cipher), type(mode)]
-        except KeyError:
-            raise UnsupportedAlgorithm(
-                "cipher {0} in {1} mode is not supported "
-                "by this backend.".format(
-                    cipher.name, mode.name if mode else mode),
-                _Reasons.UNSUPPORTED_CIPHER
-            )
-
-        ctx = self._backend._ffi.new("CCCryptorRef *")
-        ctx = self._backend._ffi.gc(ctx, _release_cipher_ctx)
-
-        self._ctx = ctx
-
-        res = self._backend._lib.CCCryptorCreateWithMode(
-            operation,
-            mode_enum, cipher_enum,
-            self._backend._lib.ccNoPadding,
-            self._backend._ffi.NULL,
-            cipher.key, len(cipher.key),
-            self._backend._ffi.NULL, 0, 0, 0, self._ctx)
-        self._backend._check_response(res)
-
-        res = self._backend._lib.CCCryptorGCMAddIV(
-            self._ctx[0],
-            mode.initialization_vector,
-            len(mode.initialization_vector)
-        )
-        self._backend._check_response(res)
-
-    def update(self, data):
-        buf = self._backend._ffi.new("unsigned char[]", len(data))
-        args = (self._ctx[0], data, len(data), buf)
-        if self._operation == self._backend._lib.kCCEncrypt:
-            res = self._backend._lib.CCCryptorGCMEncrypt(*args)
-        else:
-            res = self._backend._lib.CCCryptorGCMDecrypt(*args)
-
-        self._backend._check_response(res)
-        return self._backend._ffi.buffer(buf)[:]
-
-    def finalize(self):
-        tag_size = self._cipher.block_size // 8
-        tag_buf = self._backend._ffi.new("unsigned char[]", tag_size)
-        tag_len = self._backend._ffi.new("size_t *", tag_size)
-        res = backend._lib.CCCryptorGCMFinal(self._ctx[0], tag_buf, tag_len)
-        self._backend._check_response(res)
-        _release_cipher_ctx(self._ctx)
-        self._tag = self._backend._ffi.buffer(tag_buf)[:]
-        if (self._operation == self._backend._lib.kCCDecrypt and
-                not constant_time.bytes_eq(
-                    self._tag[:len(self._mode.tag)], self._mode.tag
-                )):
-            raise InvalidTag
-        return b""
-
-    def authenticate_additional_data(self, data):
-        res = self._backend._lib.CCCryptorGCMAddAAD(
-            self._ctx[0], data, len(data)
-        )
-        self._backend._check_response(res)
-
-    @property
-    def tag(self):
-        return self._tag
-
-
-@utils.register_interface(interfaces.HashContext)
-class _HashContext(object):
-    def __init__(self, backend, algorithm, ctx=None):
-        self.algorithm = algorithm
-        self._backend = backend
-
-        if ctx is None:
-            try:
-                methods = self._backend._hash_mapping[self.algorithm.name]
-            except KeyError:
-                raise UnsupportedAlgorithm(
-                    "{0} is not a supported hash on this backend.".format(
-                        algorithm.name),
-                    _Reasons.UNSUPPORTED_HASH
-                )
-            ctx = self._backend._ffi.new(methods.ctx)
-            res = methods.hash_init(ctx)
-            assert res == 1
-
-        self._ctx = ctx
-
-    def copy(self):
-        methods = self._backend._hash_mapping[self.algorithm.name]
-        new_ctx = self._backend._ffi.new(methods.ctx)
-        # CommonCrypto has no APIs for copying hashes, so we have to copy the
-        # underlying struct.
-        new_ctx[0] = self._ctx[0]
-
-        return _HashContext(self._backend, self.algorithm, ctx=new_ctx)
-
-    def update(self, data):
-        methods = self._backend._hash_mapping[self.algorithm.name]
-        res = methods.hash_update(self._ctx, data, len(data))
-        assert res == 1
-
-    def finalize(self):
-        methods = self._backend._hash_mapping[self.algorithm.name]
-        buf = self._backend._ffi.new("unsigned char[]",
-                                     self.algorithm.digest_size)
-        res = methods.hash_final(buf, self._ctx)
-        assert res == 1
-        return self._backend._ffi.buffer(buf)[:]
-
-
-@utils.register_interface(interfaces.HashContext)
-class _HMACContext(object):
-    def __init__(self, backend, key, algorithm, ctx=None):
-        self.algorithm = algorithm
-        self._backend = backend
-        if ctx is None:
-            ctx = self._backend._ffi.new("CCHmacContext *")
-            try:
-                alg = self._backend._supported_hmac_algorithms[algorithm.name]
-            except KeyError:
-                raise UnsupportedAlgorithm(
-                    "{0} is not a supported HMAC hash on this backend.".format(
-                        algorithm.name),
-                    _Reasons.UNSUPPORTED_HASH
-                )
-
-            self._backend._lib.CCHmacInit(ctx, alg, key, len(key))
-
-        self._ctx = ctx
-        self._key = key
-
-    def copy(self):
-        copied_ctx = self._backend._ffi.new("CCHmacContext *")
-        # CommonCrypto has no APIs for copying HMACs, so we have to copy the
-        # underlying struct.
-        copied_ctx[0] = self._ctx[0]
-        return _HMACContext(
-            self._backend, self._key, self.algorithm, ctx=copied_ctx
-        )
-
-    def update(self, data):
-        self._backend._lib.CCHmacUpdate(self._ctx, data, len(data))
-
-    def finalize(self):
-        buf = self._backend._ffi.new("unsigned char[]",
-                                     self.algorithm.digest_size)
-        self._backend._lib.CCHmacFinal(self._ctx, buf)
-        return self._backend._ffi.buffer(buf)[:]
+    def _release_cipher_ctx(self, ctx):
+        """
+        Called by the garbage collector and used to safely dereference and
+        release the context.
+        """
+        if ctx[0] != self._ffi.NULL:
+            res = self._lib.CCCryptorRelease(ctx[0])
+            self._check_cipher_response(res)
+            ctx[0] = self._ffi.NULL
 
 
 backend = Backend()
diff --git a/cryptography/hazmat/backends/commoncrypto/ciphers.py b/cryptography/hazmat/backends/commoncrypto/ciphers.py
new file mode 100644
index 0000000..525500c
--- /dev/null
+++ b/cryptography/hazmat/backends/commoncrypto/ciphers.py
@@ -0,0 +1,191 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import (
+    InvalidTag, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.primitives import constant_time, interfaces
+from cryptography.hazmat.primitives.ciphers.modes import (
+    CFB, CFB8, CTR, OFB
+)
+
+
+@utils.register_interface(interfaces.CipherContext)
+class _CipherContext(object):
+    def __init__(self, backend, cipher, mode, operation):
+        self._backend = backend
+        self._cipher = cipher
+        self._mode = mode
+        self._operation = operation
+        # There is a bug in CommonCrypto where block ciphers do not raise
+        # kCCAlignmentError when finalizing if you supply non-block aligned
+        # data. To work around this we need to keep track of the block
+        # alignment ourselves, but only for alg+mode combos that require
+        # block alignment. OFB, CFB, and CTR make a block cipher algorithm
+        # into a stream cipher so we don't need to track them (and thus their
+        # block size is effectively 1 byte just like OpenSSL/CommonCrypto
+        # treat RC4 and other stream cipher block sizes).
+        # This bug has been filed as rdar://15589470
+        self._bytes_processed = 0
+        if (isinstance(cipher, interfaces.BlockCipherAlgorithm) and not
+                isinstance(mode, (OFB, CFB, CFB8, CTR))):
+            self._byte_block_size = cipher.block_size // 8
+        else:
+            self._byte_block_size = 1
+
+        registry = self._backend._cipher_registry
+        try:
+            cipher_enum, mode_enum = registry[type(cipher), type(mode)]
+        except KeyError:
+            raise UnsupportedAlgorithm(
+                "cipher {0} in {1} mode is not supported "
+                "by this backend.".format(
+                    cipher.name, mode.name if mode else mode),
+                _Reasons.UNSUPPORTED_CIPHER
+            )
+
+        ctx = self._backend._ffi.new("CCCryptorRef *")
+        ctx = self._backend._ffi.gc(ctx, self._backend._release_cipher_ctx)
+
+        if isinstance(mode, interfaces.ModeWithInitializationVector):
+            iv_nonce = mode.initialization_vector
+        elif isinstance(mode, interfaces.ModeWithNonce):
+            iv_nonce = mode.nonce
+        else:
+            iv_nonce = self._backend._ffi.NULL
+
+        if isinstance(mode, CTR):
+            mode_option = self._backend._lib.kCCModeOptionCTR_BE
+        else:
+            mode_option = 0
+
+        res = self._backend._lib.CCCryptorCreateWithMode(
+            operation,
+            mode_enum, cipher_enum,
+            self._backend._lib.ccNoPadding, iv_nonce,
+            cipher.key, len(cipher.key),
+            self._backend._ffi.NULL, 0, 0, mode_option, ctx)
+        self._backend._check_cipher_response(res)
+
+        self._ctx = ctx
+
+    def update(self, data):
+        # Count bytes processed to handle block alignment.
+        self._bytes_processed += len(data)
+        buf = self._backend._ffi.new(
+            "unsigned char[]", len(data) + self._byte_block_size - 1)
+        outlen = self._backend._ffi.new("size_t *")
+        res = self._backend._lib.CCCryptorUpdate(
+            self._ctx[0], data, len(data), buf,
+            len(data) + self._byte_block_size - 1, outlen)
+        self._backend._check_cipher_response(res)
+        return self._backend._ffi.buffer(buf)[:outlen[0]]
+
+    def finalize(self):
+        # Raise error if block alignment is wrong.
+        if self._bytes_processed % self._byte_block_size:
+            raise ValueError(
+                "The length of the provided data is not a multiple of "
+                "the block length."
+            )
+        buf = self._backend._ffi.new("unsigned char[]", self._byte_block_size)
+        outlen = self._backend._ffi.new("size_t *")
+        res = self._backend._lib.CCCryptorFinal(
+            self._ctx[0], buf, len(buf), outlen)
+        self._backend._check_cipher_response(res)
+        self._backend._release_cipher_ctx(self._ctx)
+        return self._backend._ffi.buffer(buf)[:outlen[0]]
+
+
+@utils.register_interface(interfaces.AEADCipherContext)
+@utils.register_interface(interfaces.AEADEncryptionContext)
+class _GCMCipherContext(object):
+    def __init__(self, backend, cipher, mode, operation):
+        self._backend = backend
+        self._cipher = cipher
+        self._mode = mode
+        self._operation = operation
+        self._tag = None
+
+        registry = self._backend._cipher_registry
+        try:
+            cipher_enum, mode_enum = registry[type(cipher), type(mode)]
+        except KeyError:
+            raise UnsupportedAlgorithm(
+                "cipher {0} in {1} mode is not supported "
+                "by this backend.".format(
+                    cipher.name, mode.name if mode else mode),
+                _Reasons.UNSUPPORTED_CIPHER
+            )
+
+        ctx = self._backend._ffi.new("CCCryptorRef *")
+        ctx = self._backend._ffi.gc(ctx, self._backend._release_cipher_ctx)
+
+        self._ctx = ctx
+
+        res = self._backend._lib.CCCryptorCreateWithMode(
+            operation,
+            mode_enum, cipher_enum,
+            self._backend._lib.ccNoPadding,
+            self._backend._ffi.NULL,
+            cipher.key, len(cipher.key),
+            self._backend._ffi.NULL, 0, 0, 0, self._ctx)
+        self._backend._check_cipher_response(res)
+
+        res = self._backend._lib.CCCryptorGCMAddIV(
+            self._ctx[0],
+            mode.initialization_vector,
+            len(mode.initialization_vector)
+        )
+        self._backend._check_cipher_response(res)
+
+    def update(self, data):
+        buf = self._backend._ffi.new("unsigned char[]", len(data))
+        args = (self._ctx[0], data, len(data), buf)
+        if self._operation == self._backend._lib.kCCEncrypt:
+            res = self._backend._lib.CCCryptorGCMEncrypt(*args)
+        else:
+            res = self._backend._lib.CCCryptorGCMDecrypt(*args)
+
+        self._backend._check_cipher_response(res)
+        return self._backend._ffi.buffer(buf)[:]
+
+    def finalize(self):
+        tag_size = self._cipher.block_size // 8
+        tag_buf = self._backend._ffi.new("unsigned char[]", tag_size)
+        tag_len = self._backend._ffi.new("size_t *", tag_size)
+        res = self._backend._lib.CCCryptorGCMFinal(
+            self._ctx[0], tag_buf, tag_len
+        )
+        self._backend._check_cipher_response(res)
+        self._backend._release_cipher_ctx(self._ctx)
+        self._tag = self._backend._ffi.buffer(tag_buf)[:]
+        if (self._operation == self._backend._lib.kCCDecrypt and
+                not constant_time.bytes_eq(
+                    self._tag[:len(self._mode.tag)], self._mode.tag
+                )):
+            raise InvalidTag
+        return b""
+
+    def authenticate_additional_data(self, data):
+        res = self._backend._lib.CCCryptorGCMAddAAD(
+            self._ctx[0], data, len(data)
+        )
+        self._backend._check_cipher_response(res)
+
+    @property
+    def tag(self):
+        return self._tag
diff --git a/cryptography/hazmat/backends/commoncrypto/hashes.py b/cryptography/hazmat/backends/commoncrypto/hashes.py
new file mode 100644
index 0000000..ebad720
--- /dev/null
+++ b/cryptography/hazmat/backends/commoncrypto/hashes.py
@@ -0,0 +1,62 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.HashContext)
+class _HashContext(object):
+    def __init__(self, backend, algorithm, ctx=None):
+        self.algorithm = algorithm
+        self._backend = backend
+
+        if ctx is None:
+            try:
+                methods = self._backend._hash_mapping[self.algorithm.name]
+            except KeyError:
+                raise UnsupportedAlgorithm(
+                    "{0} is not a supported hash on this backend.".format(
+                        algorithm.name),
+                    _Reasons.UNSUPPORTED_HASH
+                )
+            ctx = self._backend._ffi.new(methods.ctx)
+            res = methods.hash_init(ctx)
+            assert res == 1
+
+        self._ctx = ctx
+
+    def copy(self):
+        methods = self._backend._hash_mapping[self.algorithm.name]
+        new_ctx = self._backend._ffi.new(methods.ctx)
+        # CommonCrypto has no APIs for copying hashes, so we have to copy the
+        # underlying struct.
+        new_ctx[0] = self._ctx[0]
+
+        return _HashContext(self._backend, self.algorithm, ctx=new_ctx)
+
+    def update(self, data):
+        methods = self._backend._hash_mapping[self.algorithm.name]
+        res = methods.hash_update(self._ctx, data, len(data))
+        assert res == 1
+
+    def finalize(self):
+        methods = self._backend._hash_mapping[self.algorithm.name]
+        buf = self._backend._ffi.new("unsigned char[]",
+                                     self.algorithm.digest_size)
+        res = methods.hash_final(buf, self._ctx)
+        assert res == 1
+        return self._backend._ffi.buffer(buf)[:]
diff --git a/cryptography/hazmat/backends/commoncrypto/hmac.py b/cryptography/hazmat/backends/commoncrypto/hmac.py
new file mode 100644
index 0000000..ec3a878
--- /dev/null
+++ b/cryptography/hazmat/backends/commoncrypto/hmac.py
@@ -0,0 +1,58 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.HashContext)
+class _HMACContext(object):
+    def __init__(self, backend, key, algorithm, ctx=None):
+        self.algorithm = algorithm
+        self._backend = backend
+        if ctx is None:
+            ctx = self._backend._ffi.new("CCHmacContext *")
+            try:
+                alg = self._backend._supported_hmac_algorithms[algorithm.name]
+            except KeyError:
+                raise UnsupportedAlgorithm(
+                    "{0} is not a supported HMAC hash on this backend.".format(
+                        algorithm.name),
+                    _Reasons.UNSUPPORTED_HASH
+                )
+
+            self._backend._lib.CCHmacInit(ctx, alg, key, len(key))
+
+        self._ctx = ctx
+        self._key = key
+
+    def copy(self):
+        copied_ctx = self._backend._ffi.new("CCHmacContext *")
+        # CommonCrypto has no APIs for copying HMACs, so we have to copy the
+        # underlying struct.
+        copied_ctx[0] = self._ctx[0]
+        return _HMACContext(
+            self._backend, self._key, self.algorithm, ctx=copied_ctx
+        )
+
+    def update(self, data):
+        self._backend._lib.CCHmacUpdate(self._ctx, data, len(data))
+
+    def finalize(self):
+        buf = self._backend._ffi.new("unsigned char[]",
+                                     self.algorithm.digest_size)
+        self._backend._lib.CCHmacFinal(self._ctx, buf)
+        return self._backend._ffi.buffer(buf)[:]
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index e8fc3a4..4991177 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -506,10 +506,10 @@
         )
 
     def _rsa_cdata_from_private_key(self, private_key):
-        # Does not GC the RSA cdata. You *must* make sure it's freed
-        # correctly yourself!
         ctx = self._lib.RSA_new()
         assert ctx != self._ffi.NULL
+        ctx = self._ffi.gc(ctx, self._lib.RSA_free)
+
         ctx.p = self._int_to_bn(private_key.p)
         ctx.q = self._int_to_bn(private_key.q)
         ctx.d = self._int_to_bn(private_key.d)
@@ -524,11 +524,10 @@
         return ctx
 
     def _rsa_cdata_from_public_key(self, public_key):
-        # Does not GC the RSA cdata. You *must* make sure it's freed
-        # correctly yourself!
-
         ctx = self._lib.RSA_new()
         assert ctx != self._ffi.NULL
+        ctx = self._ffi.gc(ctx, self._lib.RSA_free)
+
         ctx.e = self._int_to_bn(public_key.e)
         ctx.n = self._int_to_bn(public_key.n)
         res = self._lib.RSA_blinding_on(ctx, self._ffi.NULL)
@@ -544,7 +543,6 @@
             stacklevel=2
         )
         rsa_cdata = self._rsa_cdata_from_private_key(private_key)
-        rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
         key = _RSAPrivateKey(self, rsa_cdata)
         return _RSASignatureContext(self, key, padding, algorithm)
 
@@ -557,7 +555,6 @@
             stacklevel=2
         )
         rsa_cdata = self._rsa_cdata_from_public_key(public_key)
-        rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
         key = _RSAPublicKey(self, rsa_cdata)
         return _RSAVerificationContext(self, key, signature, padding,
                                        algorithm)
@@ -739,7 +736,6 @@
             stacklevel=2
         )
         rsa_cdata = self._rsa_cdata_from_private_key(private_key)
-        rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
         key = _RSAPrivateKey(self, rsa_cdata)
         return key.decrypt(ciphertext, padding)
 
@@ -751,7 +747,6 @@
             stacklevel=2
         )
         rsa_cdata = self._rsa_cdata_from_public_key(public_key)
-        rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
         key = _RSAPublicKey(self, rsa_cdata)
         return key.encrypt(plaintext, padding)
 
@@ -917,7 +912,7 @@
         Generate a new private key on the named curve.
         """
 
-        if backend.elliptic_curve_supported(curve):
+        if self.elliptic_curve_supported(curve):
             curve_nid = self._elliptic_curve_to_nid(curve)
 
             ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid)
diff --git a/cryptography/hazmat/bindings/commoncrypto/seckey.py b/cryptography/hazmat/bindings/commoncrypto/seckey.py
index 38aaece..5e4b6da 100644
--- a/cryptography/hazmat/bindings/commoncrypto/seckey.py
+++ b/cryptography/hazmat/bindings/commoncrypto/seckey.py
@@ -23,6 +23,7 @@
 
 FUNCTIONS = """
 OSStatus SecKeyGeneratePair(CFDictionaryRef, SecKeyRef *, SecKeyRef *);
+size_t SecKeyGetBlockSize(SecKeyRef);
 """
 
 MACROS = """
diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py
index e70a9db..509b4de 100644
--- a/cryptography/hazmat/primitives/ciphers/modes.py
+++ b/cryptography/hazmat/primitives/ciphers/modes.py
@@ -97,13 +97,16 @@
 class GCM(object):
     name = "GCM"
 
-    def __init__(self, initialization_vector, tag=None):
+    def __init__(self, initialization_vector, tag=None, min_tag_length=16):
         # len(initialization_vector) must in [1, 2 ** 64), but it's impossible
         # to actually construct a bytes object that large, so we don't check
         # for it
-        if tag is not None and len(tag) < 4:
+        if min_tag_length < 4:
+            raise ValueError("min_tag_length must be >= 4")
+        if tag is not None and len(tag) < min_tag_length:
             raise ValueError(
-                "Authentication tag must be 4 bytes or longer."
+                "Authentication tag must be {0} bytes or longer.".format(
+                    min_tag_length)
             )
 
         self.initialization_vector = initialization_vector
diff --git a/cryptography/hazmat/primitives/constant_time.py b/cryptography/hazmat/primitives/constant_time.py
index 4547da1..9789851 100644
--- a/cryptography/hazmat/primitives/constant_time.py
+++ b/cryptography/hazmat/primitives/constant_time.py
@@ -13,6 +13,7 @@
 
 from __future__ import absolute_import, division, print_function
 
+import hmac
 import sys
 
 import cffi
@@ -53,9 +54,18 @@
     ext_package="cryptography",
 )
 
-
-def bytes_eq(a, b):
-    if not isinstance(a, bytes) or not isinstance(b, bytes):
+if hasattr(hmac, "compare_digest"):
+    def bytes_eq(a, b):
+        if not isinstance(a, bytes) or not isinstance(b, bytes):
             raise TypeError("a and b must be bytes.")
 
-    return _lib.Cryptography_constant_time_bytes_eq(a, len(a), b, len(b)) == 1
+        return hmac.compare_digest(a, b)
+
+else:
+    def bytes_eq(a, b):
+        if not isinstance(a, bytes) or not isinstance(b, bytes):
+            raise TypeError("a and b must be bytes.")
+
+        return _lib.Cryptography_constant_time_bytes_eq(
+            a, len(a), b, len(b)
+        ) == 1
diff --git a/docs/fernet.rst b/docs/fernet.rst
index 1c4918a..4b713a5 100644
--- a/docs/fernet.rst
+++ b/docs/fernet.rst
@@ -83,7 +83,7 @@
 * :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` in
   :class:`~cryptography.hazmat.primitives.ciphers.modes.CBC` mode with a
   128-bit key for encryption; using
-  :class:`~cryptography.hazmat.primitives.ciphers.PKCS7` padding.
+  :class:`~cryptography.hazmat.primitives.padding.PKCS7` padding.
 * :class:`~cryptography.hazmat.primitives.hmac.HMAC` using
   :class:`~cryptography.hazmat.primitives.hashes.SHA256` for authentication.
 * Initialization vectors are generated using ``os.urandom()``.
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index abc2b07..586285b 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -288,7 +288,7 @@
         Must be the same number of bytes as the ``block_size`` of the cipher.
         Do not reuse an ``initialization_vector`` with a given ``key``.
 
-.. class:: GCM(initialization_vector, tag=None)
+.. class:: GCM(initialization_vector, tag=None, min_tag_length=16)
 
     .. danger::
 
@@ -318,13 +318,23 @@
         You can shorten a tag by truncating it to the desired length but this
         is **not recommended** as it lowers the security margins of the
         authentication (`NIST SP-800-38D`_ recommends 96-bits or greater).
-        If you must shorten the tag the minimum allowed length is 4 bytes
-        (32-bits). Applications **must** verify the tag is the expected length
-        to guarantee the expected security margin.
+        Applications wishing to allow truncation must pass the
+        ``min_tag_length`` parameter.
+
+        .. versionchanged:: 0.5
+
+            The ``min_tag_length`` parameter was added in ``0.5``, previously
+            truncation down to ``4`` bytes was always allowed.
 
     :param bytes tag: The tag bytes to verify during decryption. When
         encrypting this must be ``None``.
 
+    :param bytes min_tag_length: The minimum length ``tag`` must be. By default
+        this is ``16``, meaning tag truncation is not allowed. Allowing tag
+        truncation is strongly discouraged for most applications.
+
+    :raises ValueError: This is raised if ``len(tag) < min_tag_length``.
+
     .. testcode::
 
         import os
@@ -356,11 +366,6 @@
             return (iv, ciphertext, encryptor.tag)
 
         def decrypt(key, associated_data, iv, ciphertext, tag):
-            if len(tag) != 16:
-                raise ValueError(
-                    "tag must be 16 bytes -- truncation not supported"
-                )
-
             # Construct a Cipher object, with the key, iv, and additionally the
             # GCM tag used for authenticating the message.
             decryptor = Cipher(
diff --git a/tests/hazmat/backends/test_commoncrypto.py b/tests/hazmat/backends/test_commoncrypto.py
index 7c703f6..e2c6f4a 100644
--- a/tests/hazmat/backends/test_commoncrypto.py
+++ b/tests/hazmat/backends/test_commoncrypto.py
@@ -51,13 +51,13 @@
         from cryptography.hazmat.backends.commoncrypto.backend import backend
 
         with pytest.raises(ValueError):
-            backend._check_response(backend._lib.kCCAlignmentError)
+            backend._check_cipher_response(backend._lib.kCCAlignmentError)
 
         with pytest.raises(InternalError):
-            backend._check_response(backend._lib.kCCMemoryFailure)
+            backend._check_cipher_response(backend._lib.kCCMemoryFailure)
 
         with pytest.raises(InternalError):
-            backend._check_response(backend._lib.kCCDecodeError)
+            backend._check_cipher_response(backend._lib.kCCDecodeError)
 
     def test_nonexistent_aead_cipher(self):
         from cryptography.hazmat.backends.commoncrypto.backend import Backend
diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py
index 173075d..5bde7d3 100644
--- a/tests/hazmat/primitives/test_aes.py
+++ b/tests/hazmat/primitives/test_aes.py
@@ -225,6 +225,6 @@
             "gcmEncryptExtIV192.rsp",
             "gcmEncryptExtIV256.rsp",
         ],
-        lambda key: algorithms.AES(key),
-        lambda iv, tag: modes.GCM(iv, tag),
+        algorithms.AES,
+        modes.GCM,
     )
diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py
index 49b73f0..6428b03 100644
--- a/tests/hazmat/primitives/utils.py
+++ b/tests/hazmat/primitives/utils.py
@@ -90,7 +90,8 @@
         cipher = Cipher(
             cipher_factory(binascii.unhexlify(params["key"])),
             mode_factory(binascii.unhexlify(params["iv"]),
-                         binascii.unhexlify(params["tag"])),
+                         binascii.unhexlify(params["tag"]),
+                         len(binascii.unhexlify(params["tag"]))),
             backend
         )
         decryptor = cipher.decryptor()
@@ -108,12 +109,13 @@
         encryptor.authenticate_additional_data(binascii.unhexlify(aad))
         actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext))
         actual_ciphertext += encryptor.finalize()
-        tag_len = len(params["tag"])
-        assert binascii.hexlify(encryptor.tag)[:tag_len] == params["tag"]
+        tag_len = len(binascii.unhexlify(params["tag"]))
+        assert binascii.hexlify(encryptor.tag[:tag_len]) == params["tag"]
         cipher = Cipher(
             cipher_factory(binascii.unhexlify(params["key"])),
             mode_factory(binascii.unhexlify(params["iv"]),
-                         binascii.unhexlify(params["tag"])),
+                         binascii.unhexlify(params["tag"]),
+                         min_tag_length=tag_len),
             backend
         )
         decryptor = cipher.decryptor()
@@ -309,6 +311,9 @@
     with pytest.raises(ValueError):
         mode_factory(binascii.unhexlify(b"0" * 24), b"000")
 
+    with pytest.raises(ValueError):
+        mode_factory(binascii.unhexlify(b"0" * 24), b"000000", 2)
+
     cipher = Cipher(
         cipher_factory(binascii.unhexlify(b"0" * 32)),
         mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16),