diff options
-rw-r--r-- | docs/hazmat/primitives/aead.rst | 28 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/aead.py | 6 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/ciphers/aead.py | 12 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_aead.py | 45 |
4 files changed, 73 insertions, 18 deletions
diff --git a/docs/hazmat/primitives/aead.rst b/docs/hazmat/primitives/aead.rst index 06fecc5a..d318367b 100644 --- a/docs/hazmat/primitives/aead.rst +++ b/docs/hazmat/primitives/aead.rst @@ -18,7 +18,8 @@ also support providing integrity for associated data which is not encrypted. It is a stream cipher combined with a MAC that offers strong integrity guarantees. - :param bytes key: A 32-byte key. This **must** be kept secret. + :param key: A 32-byte key. This **must** be kept secret. + :type key: :term:`bytes-like` :raises cryptography.exceptions.UnsupportedAlgorithm: If the version of OpenSSL does not support ChaCha20Poly1305. @@ -53,8 +54,8 @@ also support providing integrity for associated data which is not encrypted. ``associated_data``. The output of this can be passed directly to the ``decrypt`` method. - :param bytes nonce: A 12 byte value. **NEVER REUSE A NONCE** with a - key. + :param nonce: A 12 byte value. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to encrypt. :param bytes associated_data: Additional data that should be authenticated with the key, but does not need to be encrypted. Can @@ -69,8 +70,9 @@ also support providing integrity for associated data which is not encrypted. called encrypt with ``associated_data`` you must pass the same ``associated_data`` in decrypt or the integrity check will fail. - :param bytes nonce: A 12 byte value. **NEVER REUSE A NONCE** with a + :param nonce: A 12 byte value. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to decrypt (with tag appended). :param bytes associated_data: Additional data to authenticate. Can be ``None`` if none was passed during encryption. @@ -88,7 +90,8 @@ also support providing integrity for associated data which is not encrypted. :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` block cipher utilizing Galois Counter Mode (GCM). - :param bytes key: A 128, 192, or 256-bit key. This **must** be kept secret. + :param key: A 128, 192, or 256-bit key. This **must** be kept secret. + :type key: :term:`bytes-like` .. doctest:: @@ -123,9 +126,10 @@ also support providing integrity for associated data which is not encrypted. authenticating the ``associated_data``. The output of this can be passed directly to the ``decrypt`` method. - :param bytes nonce: NIST `recommends a 96-bit IV length`_ for best + :param nonce: NIST `recommends a 96-bit IV length`_ for best performance but it can be up to 2\ :sup:`64` - 1 :term:`bits`. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to encrypt. :param bytes associated_data: Additional data that should be authenticated with the key, but is not encrypted. Can be ``None``. @@ -139,9 +143,10 @@ also support providing integrity for associated data which is not encrypted. called encrypt with ``associated_data`` you must pass the same ``associated_data`` in decrypt or the integrity check will fail. - :param bytes nonce: NIST `recommends a 96-bit IV length`_ for best + :param nonce: NIST `recommends a 96-bit IV length`_ for best performance but it can be up to 2\ :sup:`64` - 1 :term:`bits`. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to decrypt (with tag appended). :param bytes associated_data: Additional data to authenticate. Can be ``None`` if none was passed during encryption. @@ -165,7 +170,8 @@ also support providing integrity for associated data which is not encrypted. :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` block cipher utilizing Counter with CBC-MAC (CCM) (specified in :rfc:`3610`). - :param bytes key: A 128, 192, or 256-bit key. This **must** be kept secret. + :param key: A 128, 192, or 256-bit key. This **must** be kept secret. + :type key: :term:`bytes-like` :param int tag_length: The length of the authentication tag. This defaults to 16 bytes and it is **strongly** recommended that you do not make it shorter unless absolutely necessary. Valid tag @@ -207,11 +213,12 @@ also support providing integrity for associated data which is not encrypted. authenticating the ``associated_data``. The output of this can be passed directly to the ``decrypt`` method. - :param bytes nonce: A value of between 7 and 13 bytes. The maximum + :param nonce: A value of between 7 and 13 bytes. The maximum length is determined by the length of the ciphertext you are encrypting and must satisfy the condition: ``len(data) < 2 ** (8 * (15 - len(nonce)))`` **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to encrypt. :param bytes associated_data: Additional data that should be authenticated with the key, but is not encrypted. Can be ``None``. @@ -225,9 +232,10 @@ also support providing integrity for associated data which is not encrypted. called encrypt with ``associated_data`` you must pass the same ``associated_data`` in decrypt or the integrity check will fail. - :param bytes nonce: A value of between 7 and 13 bytes. This + :param nonce: A value of between 7 and 13 bytes. This is the same value used when you originally called encrypt. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to decrypt (with tag appended). :param bytes associated_data: Additional data to authenticate. Can be ``None`` if none was passed during encryption. diff --git a/src/cryptography/hazmat/backends/openssl/aead.py b/src/cryptography/hazmat/backends/openssl/aead.py index 9cec3e23..73195ff3 100644 --- a/src/cryptography/hazmat/backends/openssl/aead.py +++ b/src/cryptography/hazmat/backends/openssl/aead.py @@ -54,12 +54,14 @@ def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation): ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, tag_len, backend._ffi.NULL ) + nonce_ptr = backend._ffi.from_buffer(nonce) + key_ptr = backend._ffi.from_buffer(key) res = backend._lib.EVP_CipherInit_ex( ctx, backend._ffi.NULL, backend._ffi.NULL, - key, - nonce, + key_ptr, + nonce_ptr, int(operation == _ENCRYPT) ) backend.openssl_assert(res != 0) diff --git a/src/cryptography/hazmat/primitives/ciphers/aead.py b/src/cryptography/hazmat/primitives/ciphers/aead.py index 16899d00..42e19adb 100644 --- a/src/cryptography/hazmat/primitives/ciphers/aead.py +++ b/src/cryptography/hazmat/primitives/ciphers/aead.py @@ -20,7 +20,7 @@ class ChaCha20Poly1305(object): "ChaCha20Poly1305 is not supported by this version of OpenSSL", exceptions._Reasons.UNSUPPORTED_CIPHER ) - utils._check_bytes("key", key) + utils._check_byteslike("key", key) if len(key) != 32: raise ValueError("ChaCha20Poly1305 key must be 32 bytes.") @@ -56,7 +56,7 @@ class ChaCha20Poly1305(object): ) def _check_params(self, nonce, data, associated_data): - utils._check_bytes("nonce", nonce) + utils._check_byteslike("nonce", nonce) utils._check_bytes("data", data) utils._check_bytes("associated_data", associated_data) if len(nonce) != 12: @@ -67,7 +67,7 @@ class AESCCM(object): _MAX_SIZE = 2 ** 32 def __init__(self, key, tag_length=16): - utils._check_bytes("key", key) + utils._check_byteslike("key", key) if len(key) not in (16, 24, 32): raise ValueError("AESCCM key must be 128, 192, or 256 bits.") @@ -129,7 +129,7 @@ class AESCCM(object): raise ValueError("Nonce too long for data") def _check_params(self, nonce, data, associated_data): - utils._check_bytes("nonce", nonce) + utils._check_byteslike("nonce", nonce) utils._check_bytes("data", data) utils._check_bytes("associated_data", associated_data) if not 7 <= len(nonce) <= 13: @@ -140,7 +140,7 @@ class AESGCM(object): _MAX_SIZE = 2 ** 32 def __init__(self, key): - utils._check_bytes("key", key) + utils._check_byteslike("key", key) if len(key) not in (16, 24, 32): raise ValueError("AESGCM key must be 128, 192, or 256 bits.") @@ -181,7 +181,7 @@ class AESGCM(object): ) def _check_params(self, nonce, data, associated_data): - utils._check_bytes("nonce", nonce) + utils._check_byteslike("nonce", nonce) utils._check_bytes("data", data) utils._check_bytes("associated_data", associated_data) if len(nonce) == 0: diff --git a/tests/hazmat/primitives/test_aead.py b/tests/hazmat/primitives/test_aead.py index 5a518558..e1a17a97 100644 --- a/tests/hazmat/primitives/test_aead.py +++ b/tests/hazmat/primitives/test_aead.py @@ -167,6 +167,21 @@ class TestChaCha20Poly1305(object): computed_ct = chacha.encrypt(nonce, pt, aad) assert computed_ct == ct + tag + def test_buffer_protocol(self, backend): + key = ChaCha20Poly1305.generate_key() + chacha = ChaCha20Poly1305(key) + pt = b"encrypt me" + ad = b"additional" + nonce = os.urandom(12) + ct = chacha.encrypt(nonce, pt, ad) + computed_pt = chacha.decrypt(nonce, ct, ad) + assert computed_pt == pt + chacha2 = ChaCha20Poly1305(bytearray(key)) + ct2 = chacha2.encrypt(bytearray(nonce), pt, ad) + assert ct2 == ct + computed_pt2 = chacha2.decrypt(bytearray(nonce), ct2, ad) + assert computed_pt2 == pt + @pytest.mark.skipif( _aead_supported(AESCCM), @@ -317,6 +332,21 @@ class TestAESCCM(object): with pytest.raises(InvalidTag): aesccm.decrypt(b"0" * 12, b"0", None) + def test_buffer_protocol(self, backend): + key = AESCCM.generate_key(128) + aesccm = AESCCM(key) + pt = b"encrypt me" + ad = b"additional" + nonce = os.urandom(12) + ct = aesccm.encrypt(nonce, pt, ad) + computed_pt = aesccm.decrypt(nonce, ct, ad) + assert computed_pt == pt + aesccm2 = AESCCM(bytearray(key)) + ct2 = aesccm2.encrypt(bytearray(nonce), pt, ad) + assert ct2 == ct + computed_pt2 = aesccm2.decrypt(bytearray(nonce), ct2, ad) + assert computed_pt2 == pt + def _load_gcm_vectors(): vectors = _load_all_params( @@ -413,3 +443,18 @@ class TestAESGCM(object): pt1 = aesgcm.decrypt(nonce, ct1, None) pt2 = aesgcm.decrypt(nonce, ct2, b"") assert pt1 == pt2 + + def test_buffer_protocol(self, backend): + key = AESGCM.generate_key(128) + aesgcm = AESGCM(key) + pt = b"encrypt me" + ad = b"additional" + nonce = os.urandom(12) + ct = aesgcm.encrypt(nonce, pt, ad) + computed_pt = aesgcm.decrypt(nonce, ct, ad) + assert computed_pt == pt + aesgcm2 = AESGCM(bytearray(key)) + ct2 = aesgcm2.encrypt(bytearray(nonce), pt, ad) + assert ct2 == ct + computed_pt2 = aesgcm2.decrypt(bytearray(nonce), ct2, ad) + assert computed_pt2 == pt |