aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2017-02-16 22:20:38 -0600
committerAlex Gaynor <alex.gaynor@gmail.com>2017-02-16 23:20:38 -0500
commit9b34ca92c3ac061aee2301728dc1280a83890814 (patch)
tree250f7f978b69b1b933e2152a76477f0936705c0d /tests
parent83d3adee771593f3b90a74ff2c2e1a7a2d98b668 (diff)
downloadcryptography-9b34ca92c3ac061aee2301728dc1280a83890814.tar.gz
cryptography-9b34ca92c3ac061aee2301728dc1280a83890814.tar.bz2
cryptography-9b34ca92c3ac061aee2301728dc1280a83890814.zip
add support for update_into on CipherContext (#3190)
* add support for update_into on CipherContext This allows you to provide your own buffer (like recv_into) to improve performance when repeatedly calling encrypt/decrypt on large payloads. * another skip_if * more skip_if complexity * maybe do this right * correct number of args * coverage for the coverage gods * add a cffi minimum test tox target and travis builder This tests against macOS so we capture some commoncrypto branches * extra arg * need to actually install py35 * fix * coverage for GCM decrypt in CC * no longer relevant * 1.8 now * pep8 * dramatically simplify * update docs * remove unneeded test * changelog entry * test improvements * coverage fix * add some comments to example * move the comments to their own line * fix and move comment
Diffstat (limited to 'tests')
-rw-r--r--tests/hazmat/primitives/test_block.py20
-rw-r--r--tests/hazmat/primitives/test_ciphers.py153
2 files changed, 170 insertions, 3 deletions
diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py
index eb0a2c3b..11a70195 100644
--- a/tests/hazmat/primitives/test_block.py
+++ b/tests/hazmat/primitives/test_block.py
@@ -6,6 +6,8 @@ from __future__ import absolute_import, division, print_function
import binascii
+import cffi
+
import pytest
from cryptography.exceptions import (
@@ -15,6 +17,7 @@ from cryptography.hazmat.backends.interfaces import CipherBackend
from cryptography.hazmat.primitives.ciphers import (
Cipher, algorithms, base, modes
)
+from cryptography.utils import _version_check
from .utils import (
generate_aead_exception_test, generate_aead_tag_exception_test
@@ -70,6 +73,23 @@ class TestCipherContext(object):
with pytest.raises(AlreadyFinalized):
decryptor.finalize()
+ @pytest.mark.skipif(
+ not _version_check(cffi.__version__, '1.7'),
+ reason="cffi version too old"
+ )
+ def test_use_update_into_after_finalize(self, backend):
+ cipher = Cipher(
+ algorithms.AES(binascii.unhexlify(b"0" * 32)),
+ modes.CBC(binascii.unhexlify(b"0" * 32)),
+ backend
+ )
+ encryptor = cipher.encryptor()
+ encryptor.update(b"a" * 16)
+ encryptor.finalize()
+ with pytest.raises(AlreadyFinalized):
+ buf = bytearray(31)
+ encryptor.update_into(b"b" * 16, buf)
+
def test_unaligned_block_encryption(self, backend):
cipher = Cipher(
algorithms.AES(binascii.unhexlify(b"0" * 32)),
diff --git a/tests/hazmat/primitives/test_ciphers.py b/tests/hazmat/primitives/test_ciphers.py
index d9a07ff6..83952a87 100644
--- a/tests/hazmat/primitives/test_ciphers.py
+++ b/tests/hazmat/primitives/test_ciphers.py
@@ -5,17 +5,24 @@
from __future__ import absolute_import, division, print_function
import binascii
+import os
+
+import cffi
import pytest
from cryptography.exceptions import _Reasons
+from cryptography.hazmat.backends.interfaces import CipherBackend
from cryptography.hazmat.primitives import ciphers
+from cryptography.hazmat.primitives.ciphers import modes
from cryptography.hazmat.primitives.ciphers.algorithms import (
AES, ARC4, Blowfish, CAST5, Camellia, IDEA, SEED, TripleDES
)
-from cryptography.hazmat.primitives.ciphers.modes import ECB
+from cryptography.utils import _version_check
-from ...utils import raises_unsupported_algorithm
+from ...utils import (
+ load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm
+)
class TestAES(object):
@@ -132,4 +139,144 @@ def test_invalid_backend():
pretend_backend = object()
with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
- ciphers.Cipher(AES(b"AAAAAAAAAAAAAAAA"), ECB, pretend_backend)
+ ciphers.Cipher(AES(b"AAAAAAAAAAAAAAAA"), modes.ECB, pretend_backend)
+
+
+@pytest.mark.skipif(
+ not _version_check(cffi.__version__, '1.7'),
+ reason="cffi version too old"
+)
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ AES(b"\x00" * 16), modes.ECB()
+ ),
+ skip_message="Does not support AES ECB",
+)
+@pytest.mark.requires_backend_interface(interface=CipherBackend)
+class TestCipherUpdateInto(object):
+ @pytest.mark.parametrize(
+ "params",
+ load_vectors_from_file(
+ os.path.join("ciphers", "AES", "ECB", "ECBGFSbox128.rsp"),
+ load_nist_vectors
+ )
+ )
+ def test_update_into(self, params, backend):
+ key = binascii.unhexlify(params["key"])
+ pt = binascii.unhexlify(params["plaintext"])
+ ct = binascii.unhexlify(params["ciphertext"])
+ c = ciphers.Cipher(AES(key), modes.ECB(), backend)
+ encryptor = c.encryptor()
+ buf = bytearray(len(pt) + 15)
+ res = encryptor.update_into(pt, buf)
+ assert res == len(pt)
+ assert bytes(buf)[:res] == ct
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ AES(b"\x00" * 16), modes.GCM(b"0" * 12)
+ ),
+ skip_message="Does not support AES GCM",
+ )
+ def test_update_into_gcm(self, backend):
+ key = binascii.unhexlify(b"e98b72a9881a84ca6b76e0f43e68647a")
+ iv = binascii.unhexlify(b"8b23299fde174053f3d652ba")
+ ct = binascii.unhexlify(b"5a3c1cf1985dbb8bed818036fdd5ab42")
+ pt = binascii.unhexlify(b"28286a321293253c3e0aa2704a278032")
+ c = ciphers.Cipher(AES(key), modes.GCM(iv), backend)
+ encryptor = c.encryptor()
+ buf = bytearray(len(pt) + 15)
+ res = encryptor.update_into(pt, buf)
+ assert res == len(pt)
+ assert bytes(buf)[:res] == ct
+ encryptor.finalize()
+ c = ciphers.Cipher(AES(key), modes.GCM(iv, encryptor.tag), backend)
+ decryptor = c.decryptor()
+ res = decryptor.update_into(ct, buf)
+ decryptor.finalize()
+ assert res == len(pt)
+ assert bytes(buf)[:res] == pt
+
+ @pytest.mark.parametrize(
+ "params",
+ load_vectors_from_file(
+ os.path.join("ciphers", "AES", "ECB", "ECBGFSbox128.rsp"),
+ load_nist_vectors
+ )
+ )
+ def test_update_into_multiple_calls(self, params, backend):
+ key = binascii.unhexlify(params["key"])
+ pt = binascii.unhexlify(params["plaintext"])
+ ct = binascii.unhexlify(params["ciphertext"])
+ c = ciphers.Cipher(AES(key), modes.ECB(), backend)
+ encryptor = c.encryptor()
+ buf = bytearray(len(pt) + 15)
+ res = encryptor.update_into(pt[:3], buf)
+ assert res == 0
+ res = encryptor.update_into(pt[3:], buf)
+ assert res == len(pt)
+ assert bytes(buf)[:res] == ct
+
+ def test_update_into_buffer_too_small(self, backend):
+ key = b"\x00" * 16
+ c = ciphers.Cipher(AES(key), modes.ECB(), backend)
+ encryptor = c.encryptor()
+ buf = bytearray(16)
+ with pytest.raises(ValueError):
+ encryptor.update_into(b"testing", buf)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ AES(b"\x00" * 16), modes.GCM(b"\x00" * 12)
+ ),
+ skip_message="Does not support AES GCM",
+ )
+ def test_update_into_buffer_too_small_gcm(self, backend):
+ key = b"\x00" * 16
+ c = ciphers.Cipher(AES(key), modes.GCM(b"\x00" * 12), backend)
+ encryptor = c.encryptor()
+ buf = bytearray(5)
+ with pytest.raises(ValueError):
+ encryptor.update_into(b"testing", buf)
+
+
+@pytest.mark.skipif(
+ _version_check(cffi.__version__, '1.7'),
+ reason="cffi version too new"
+)
+@pytest.mark.requires_backend_interface(interface=CipherBackend)
+class TestCipherUpdateIntoUnsupported(object):
+ def _too_old(self, mode, backend):
+ key = b"\x00" * 16
+ c = ciphers.Cipher(AES(key), mode, backend)
+ encryptor = c.encryptor()
+ buf = bytearray(32)
+ with pytest.raises(NotImplementedError):
+ encryptor.update_into(b"\x00" * 16, buf)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ AES(b"\x00" * 16), modes.ECB()
+ ),
+ skip_message="Does not support AES ECB",
+ )
+ def test_cffi_too_old_ecb(self, backend):
+ self._too_old(modes.ECB(), backend)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ AES(b"\x00" * 16), modes.CTR(b"0" * 16)
+ ),
+ skip_message="Does not support AES CTR",
+ )
+ def test_cffi_too_old_ctr(self, backend):
+ self._too_old(modes.CTR(b"0" * 16), backend)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ AES(b"\x00" * 16), modes.GCM(b"0" * 16)
+ ),
+ skip_message="Does not support AES GCM",
+ )
+ def test_cffi_too_old_gcm(self, backend):
+ self._too_old(modes.GCM(b"0" * 16), backend)