# This file is dual licensed under the terms of the Apache License, Version # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. import binascii import os import pytest from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, base, modes from .utils import generate_aead_test from ...utils import load_nist_vectors @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( 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( load_nist_vectors, os.path.join("ciphers", "AES", "GCM"), [ "gcmDecrypt128.rsp", "gcmDecrypt192.rsp", "gcmDecrypt256.rsp", "gcmEncryptExtIV128.rsp", "gcmEncryptExtIV192.rsp", "gcmEncryptExtIV256.rsp", ], algorithms.AES, modes.GCM, ) def test_gcm_tag_with_only_aad(self, backend): key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3") iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d") aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193") tag = binascii.unhexlify(b"0f247e7f9c2505de374006738018493b") cipher = base.Cipher( algorithms.AES(key), modes.GCM(iv), backend=backend ) encryptor = cipher.encryptor() encryptor.authenticate_additional_data(aad) encryptor.finalize() assert encryptor.tag == tag def test_gcm_ciphertext_with_no_aad(self, backend): key = binascii.unhexlify(b"e98b72a9881a84ca6b76e0f43e68647a") iv = binascii.unhexlify(b"8b23299fde174053f3d652ba") ct = binascii.unhexlify(b"5a3c1cf1985dbb8bed818036fdd5ab42") tag = binascii.unhexlify(b"23c7ab0f952b7091cd324835043b5eb5") pt = binascii.unhexlify(b"28286a321293253c3e0aa2704a278032") cipher = base.Cipher( algorithms.AES(key), modes.GCM(iv), backend=backend ) encryptor = cipher.encryptor() 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("size", [8, 128]) def test_gcm_min_max_iv(self, size, backend): if backend._fips_enabled: # Red Hat disables non-96-bit IV support as part of its FIPS # patches. pytest.skip("Non-96-bit IVs unsupported in FIPS mode.") key = os.urandom(16) iv = b"\x00" * size payload = b"data" encryptor = base.Cipher(algorithms.AES(key), modes.GCM(iv)).encryptor() ct = encryptor.update(payload) encryptor.finalize() tag = encryptor.tag decryptor = base.Cipher(algorithms.AES(key), modes.GCM(iv)).decryptor() pt = decryptor.update(ct) decryptor.finalize_with_tag(tag) assert pt == payload