diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2014-06-29 20:43:29 -0700 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2014-06-29 20:43:29 -0700 |
commit | 8f1b8e88e6e9ed7d73661bb90f0e558059b610f3 (patch) | |
tree | 5b3fd5321c77e1f1b0da4d93497d03bd20f75282 | |
parent | 2d6e91f81266129c48ae775228a18d92c2d0f2c7 (diff) | |
download | cryptography-8f1b8e88e6e9ed7d73661bb90f0e558059b610f3.tar.gz cryptography-8f1b8e88e6e9ed7d73661bb90f0e558059b610f3.tar.bz2 cryptography-8f1b8e88e6e9ed7d73661bb90f0e558059b610f3.zip |
Fixes #1200 -- disallow GCM truncation by default
-rw-r--r-- | CHANGELOG.rst | 5 | ||||
-rw-r--r-- | cryptography/__about__.py | 2 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/ciphers/modes.py | 7 | ||||
-rw-r--r-- | docs/hazmat/primitives/symmetric-encryption.rst | 21 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_aes.py | 2 | ||||
-rw-r--r-- | tests/hazmat/primitives/utils.py | 10 |
6 files changed, 29 insertions, 18 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e057b636..1175e6f6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,11 @@ Changelog .. 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 reccomended) 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 ee53902b..ccbcdfe8 100644 --- a/cryptography/__about__.py +++ b/cryptography/__about__.py @@ -28,4 +28,4 @@ __author__ = "The cryptography developers" __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/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index e70a9db5..f09478fc 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -97,13 +97,14 @@ class CTR(object): 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 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/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index abc2b076..fffad6e8 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -317,14 +317,22 @@ Modes Cryptography will generate a 128-bit tag when finalizing encryption. 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. + 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 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 up 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. + .. testcode:: import os @@ -356,11 +364,6 @@ Modes 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/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py index 173075d6..003b3ba0 100644 --- a/tests/hazmat/primitives/test_aes.py +++ b/tests/hazmat/primitives/test_aes.py @@ -226,5 +226,5 @@ class TestAESModeGCM(object): "gcmEncryptExtIV256.rsp", ], lambda key: algorithms.AES(key), - lambda iv, tag: modes.GCM(iv, tag), + lambda iv, tag, min_tag_length=16: modes.GCM(iv, tag, min_tag_length), ) diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 49b73f01..4640c2ea 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -90,7 +90,8 @@ def aead_test(backend, cipher_factory, mode_factory, params): 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 @@ def aead_test(backend, cipher_factory, mode_factory, params): 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() |