aboutsummaryrefslogtreecommitdiffstats
path: root/tests/hazmat/primitives/test_aes.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/hazmat/primitives/test_aes.py')
-rw-r--r--tests/hazmat/primitives/test_aes.py236
1 files changed, 221 insertions, 15 deletions
diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py
index 4d48e8ad..d99ba406 100644
--- a/tests/hazmat/primitives/test_aes.py
+++ b/tests/hazmat/primitives/test_aes.py
@@ -12,19 +12,54 @@ import pytest
from cryptography.hazmat.backends.interfaces import CipherBackend
from cryptography.hazmat.primitives.ciphers import algorithms, base, modes
-from .utils import generate_aead_test, generate_encrypt_test
+from .utils import _load_all_params, generate_aead_test, generate_encrypt_test
+from ...doubles import DummyMode
from ...utils import load_nist_vectors
@pytest.mark.supported(
only_if=lambda backend: backend.cipher_supported(
- algorithms.AES("\x00" * 16), modes.CBC("\x00" * 16)
+ algorithms.AES(b"\x00" * 32), modes.XTS(b"\x00" * 16)
+ ),
+ skip_message="Does not support AES XTS",
+)
+@pytest.mark.requires_backend_interface(interface=CipherBackend)
+class TestAESModeXTS(object):
+ @pytest.mark.parametrize(
+ "vector",
+ # This list comprehension excludes any vector that does not have a
+ # data unit length that is divisible by 8. The NIST vectors include
+ # tests for implementations that support encryption of data that is
+ # not divisible modulo 8, but OpenSSL is not such an implementation.
+ [x for x in _load_all_params(
+ os.path.join("ciphers", "AES", "XTS", "tweak-128hexstr"),
+ ["XTSGenAES128.rsp", "XTSGenAES256.rsp"],
+ load_nist_vectors
+ ) if int(x["dataunitlen"]) / 8.0 == int(x["dataunitlen"]) // 8]
+ )
+ def test_xts_vectors(self, vector, backend):
+ key = binascii.unhexlify(vector["key"])
+ tweak = binascii.unhexlify(vector["i"])
+ pt = binascii.unhexlify(vector["pt"])
+ ct = binascii.unhexlify(vector["ct"])
+ cipher = base.Cipher(algorithms.AES(key), modes.XTS(tweak), backend)
+ enc = cipher.encryptor()
+ computed_ct = enc.update(pt) + enc.finalize()
+ assert computed_ct == ct
+ dec = cipher.decryptor()
+ computed_pt = dec.update(ct) + dec.finalize()
+ assert computed_pt == pt
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.AES(b"\x00" * 16), modes.CBC(b"\x00" * 16)
),
skip_message="Does not support AES CBC",
)
@pytest.mark.requires_backend_interface(interface=CipherBackend)
class TestAESModeCBC(object):
- test_CBC = generate_encrypt_test(
+ test_cbc = generate_encrypt_test(
load_nist_vectors,
os.path.join("ciphers", "AES", "CBC"),
[
@@ -51,13 +86,13 @@ class TestAESModeCBC(object):
@pytest.mark.supported(
only_if=lambda backend: backend.cipher_supported(
- algorithms.AES("\x00" * 16), modes.ECB()
+ algorithms.AES(b"\x00" * 16), modes.ECB()
),
skip_message="Does not support AES ECB",
)
@pytest.mark.requires_backend_interface(interface=CipherBackend)
class TestAESModeECB(object):
- test_ECB = generate_encrypt_test(
+ test_ecb = generate_encrypt_test(
load_nist_vectors,
os.path.join("ciphers", "AES", "ECB"),
[
@@ -84,13 +119,13 @@ class TestAESModeECB(object):
@pytest.mark.supported(
only_if=lambda backend: backend.cipher_supported(
- algorithms.AES("\x00" * 16), modes.OFB("\x00" * 16)
+ algorithms.AES(b"\x00" * 16), modes.OFB(b"\x00" * 16)
),
skip_message="Does not support AES OFB",
)
@pytest.mark.requires_backend_interface(interface=CipherBackend)
class TestAESModeOFB(object):
- test_OFB = generate_encrypt_test(
+ test_ofb = generate_encrypt_test(
load_nist_vectors,
os.path.join("ciphers", "AES", "OFB"),
[
@@ -117,13 +152,13 @@ class TestAESModeOFB(object):
@pytest.mark.supported(
only_if=lambda backend: backend.cipher_supported(
- algorithms.AES("\x00" * 16), modes.CFB("\x00" * 16)
+ algorithms.AES(b"\x00" * 16), modes.CFB(b"\x00" * 16)
),
skip_message="Does not support AES CFB",
)
@pytest.mark.requires_backend_interface(interface=CipherBackend)
class TestAESModeCFB(object):
- test_CFB = generate_encrypt_test(
+ test_cfb = generate_encrypt_test(
load_nist_vectors,
os.path.join("ciphers", "AES", "CFB"),
[
@@ -150,13 +185,13 @@ class TestAESModeCFB(object):
@pytest.mark.supported(
only_if=lambda backend: backend.cipher_supported(
- algorithms.AES("\x00" * 16), modes.CFB8("\x00" * 16)
+ algorithms.AES(b"\x00" * 16), modes.CFB8(b"\x00" * 16)
),
skip_message="Does not support AES CFB8",
)
@pytest.mark.requires_backend_interface(interface=CipherBackend)
class TestAESModeCFB8(object):
- test_CFB8 = generate_encrypt_test(
+ test_cfb8 = generate_encrypt_test(
load_nist_vectors,
os.path.join("ciphers", "AES", "CFB"),
[
@@ -183,13 +218,13 @@ class TestAESModeCFB8(object):
@pytest.mark.supported(
only_if=lambda backend: backend.cipher_supported(
- algorithms.AES("\x00" * 16), modes.CTR("\x00" * 16)
+ algorithms.AES(b"\x00" * 16), modes.CTR(b"\x00" * 16)
),
skip_message="Does not support AES CTR",
)
@pytest.mark.requires_backend_interface(interface=CipherBackend)
class TestAESModeCTR(object):
- test_CTR = generate_encrypt_test(
+ test_ctr = generate_encrypt_test(
load_nist_vectors,
os.path.join("ciphers", "AES", "CTR"),
["aes-128-ctr.txt", "aes-192-ctr.txt", "aes-256-ctr.txt"],
@@ -200,13 +235,13 @@ class TestAESModeCTR(object):
@pytest.mark.supported(
only_if=lambda backend: backend.cipher_supported(
- algorithms.AES("\x00" * 16), modes.GCM("\x00" * 12)
+ algorithms.AES(b"\x00" * 16), modes.GCM(b"\x00" * 12)
),
skip_message="Does not support AES GCM",
)
@pytest.mark.requires_backend_interface(interface=CipherBackend)
class TestAESModeGCM(object):
- test_GCM = generate_aead_test(
+ test_gcm = generate_aead_test(
load_nist_vectors,
os.path.join("ciphers", "AES", "GCM"),
[
@@ -253,3 +288,174 @@ class TestAESModeGCM(object):
computed_ct = encryptor.update(pt) + encryptor.finalize()
assert computed_ct == ct
assert encryptor.tag == tag
+
+ def test_gcm_ciphertext_limit(self, backend):
+ encryptor = base.Cipher(
+ algorithms.AES(b"\x00" * 16),
+ modes.GCM(b"\x01" * 16),
+ backend=backend
+ ).encryptor()
+ encryptor._bytes_processed = modes.GCM._MAX_ENCRYPTED_BYTES - 16
+ encryptor.update(b"0" * 16)
+ assert (
+ encryptor._bytes_processed == modes.GCM._MAX_ENCRYPTED_BYTES
+ )
+ with pytest.raises(ValueError):
+ encryptor.update(b"0")
+
+ def test_gcm_aad_limit(self, backend):
+ encryptor = base.Cipher(
+ algorithms.AES(b"\x00" * 16),
+ modes.GCM(b"\x01" * 16),
+ backend=backend
+ ).encryptor()
+ encryptor._aad_bytes_processed = modes.GCM._MAX_AAD_BYTES - 16
+ encryptor.authenticate_additional_data(b"0" * 16)
+ assert encryptor._aad_bytes_processed == modes.GCM._MAX_AAD_BYTES
+ with pytest.raises(ValueError):
+ encryptor.authenticate_additional_data(b"0")
+
+ def test_gcm_ciphertext_increments(self, backend):
+ encryptor = base.Cipher(
+ algorithms.AES(b"\x00" * 16),
+ modes.GCM(b"\x01" * 16),
+ backend=backend
+ ).encryptor()
+ encryptor.update(b"0" * 8)
+ assert encryptor._bytes_processed == 8
+ encryptor.update(b"0" * 7)
+ assert encryptor._bytes_processed == 15
+ encryptor.update(b"0" * 18)
+ assert encryptor._bytes_processed == 33
+
+ def test_gcm_aad_increments(self, backend):
+ encryptor = base.Cipher(
+ algorithms.AES(b"\x00" * 16),
+ modes.GCM(b"\x01" * 16),
+ backend=backend
+ ).encryptor()
+ encryptor.authenticate_additional_data(b"0" * 8)
+ assert encryptor._aad_bytes_processed == 8
+ encryptor.authenticate_additional_data(b"0" * 18)
+ assert encryptor._aad_bytes_processed == 26
+
+ def test_gcm_tag_decrypt_none(self, backend):
+ key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3")
+ iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d")
+ aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193")
+
+ encryptor = base.Cipher(
+ algorithms.AES(key),
+ modes.GCM(iv),
+ backend=backend
+ ).encryptor()
+ encryptor.authenticate_additional_data(aad)
+ encryptor.finalize()
+
+ decryptor = base.Cipher(
+ algorithms.AES(key),
+ modes.GCM(iv),
+ backend=backend
+ ).decryptor()
+ decryptor.authenticate_additional_data(aad)
+ with pytest.raises(ValueError):
+ decryptor.finalize()
+
+ def test_gcm_tag_decrypt_mode(self, backend):
+ key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3")
+ iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d")
+ aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193")
+
+ encryptor = base.Cipher(
+ algorithms.AES(key),
+ modes.GCM(iv),
+ backend=backend
+ ).encryptor()
+ encryptor.authenticate_additional_data(aad)
+ encryptor.finalize()
+ tag = encryptor.tag
+
+ decryptor = base.Cipher(
+ algorithms.AES(key),
+ modes.GCM(iv, tag),
+ backend=backend
+ ).decryptor()
+ decryptor.authenticate_additional_data(aad)
+ decryptor.finalize()
+
+ def test_gcm_tag_decrypt_finalize(self, backend):
+ key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3")
+ iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d")
+ aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193")
+
+ encryptor = base.Cipher(
+ algorithms.AES(key),
+ modes.GCM(iv),
+ backend=backend
+ ).encryptor()
+ encryptor.authenticate_additional_data(aad)
+ encryptor.finalize()
+ tag = encryptor.tag
+
+ decryptor = base.Cipher(
+ algorithms.AES(key),
+ modes.GCM(iv),
+ backend=backend
+ ).decryptor()
+ decryptor.authenticate_additional_data(aad)
+
+ decryptor.finalize_with_tag(tag)
+
+ def test_gcm_tag_decrypt_finalize_tag_length(self, backend):
+ decryptor = base.Cipher(
+ algorithms.AES(b"0" * 16),
+ modes.GCM(b"0" * 12),
+ backend=backend
+ ).decryptor()
+ with pytest.raises(ValueError):
+ decryptor.finalize_with_tag(b"tagtooshort")
+
+ def test_buffer_protocol(self, backend):
+ data = bytearray(b"helloworld")
+ enc = base.Cipher(
+ algorithms.AES(bytearray(b"\x00" * 16)),
+ modes.GCM(bytearray(b"\x00" * 12)),
+ backend
+ ).encryptor()
+ enc.authenticate_additional_data(bytearray(b"foo"))
+ ct = enc.update(data) + enc.finalize()
+ dec = base.Cipher(
+ algorithms.AES(bytearray(b"\x00" * 16)),
+ modes.GCM(bytearray(b"\x00" * 12), enc.tag),
+ backend
+ ).decryptor()
+ dec.authenticate_additional_data(bytearray(b"foo"))
+ pt = dec.update(ct) + dec.finalize()
+ assert pt == data
+
+
+@pytest.mark.parametrize(
+ "mode",
+ [
+ modes.CBC(bytearray(b"\x00" * 16)),
+ modes.CTR(bytearray(b"\x00" * 16)),
+ modes.OFB(bytearray(b"\x00" * 16)),
+ modes.CFB(bytearray(b"\x00" * 16)),
+ modes.CFB8(bytearray(b"\x00" * 16)),
+ modes.XTS(bytearray(b"\x00" * 16)),
+ # Add a dummy mode for coverage of the cipher_supported check.
+ DummyMode(),
+ ]
+)
+@pytest.mark.requires_backend_interface(interface=CipherBackend)
+def test_buffer_protocol_alternate_modes(mode, backend):
+ data = bytearray(b"sixteen_byte_msg")
+ key = algorithms.AES(bytearray(os.urandom(32)))
+ if not backend.cipher_supported(key, mode):
+ pytest.skip("AES in {} mode not supported".format(mode.name))
+ cipher = base.Cipher(key, mode, backend)
+ enc = cipher.encryptor()
+ ct = enc.update(data) + enc.finalize()
+ dec = cipher.decryptor()
+ pt = dec.update(ct) + dec.finalize()
+ assert pt == data