• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import absolute_import, division, print_function
6
7import binascii
8
9import pytest
10
11from cryptography.exceptions import InvalidTag
12from cryptography.hazmat.backends.interfaces import CipherBackend
13from cryptography.hazmat.primitives import padding
14from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
15from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESGCM
16
17from ..hazmat.primitives.test_aead import _aead_supported
18
19
20@pytest.mark.requires_backend_interface(interface=CipherBackend)
21@pytest.mark.wycheproof_tests("aes_cbc_pkcs5_test.json")
22def test_aes_cbc_pkcs5(backend, wycheproof):
23    key = binascii.unhexlify(wycheproof.testcase["key"])
24    iv = binascii.unhexlify(wycheproof.testcase["iv"])
25    msg = binascii.unhexlify(wycheproof.testcase["msg"])
26    ct = binascii.unhexlify(wycheproof.testcase["ct"])
27
28    padder = padding.PKCS7(128).padder()
29
30    cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend)
31    enc = cipher.encryptor()
32    computed_ct = (
33        enc.update(padder.update(msg) + padder.finalize()) + enc.finalize()
34    )
35    dec = cipher.decryptor()
36    padded_msg = dec.update(ct) + dec.finalize()
37    unpadder = padding.PKCS7(128).unpadder()
38    if wycheproof.valid or wycheproof.acceptable:
39        assert computed_ct == ct
40        computed_msg = unpadder.update(padded_msg) + unpadder.finalize()
41        assert computed_msg == msg
42    else:
43        assert computed_ct != ct
44        with pytest.raises(ValueError):
45            unpadder.update(padded_msg) + unpadder.finalize()
46
47
48@pytest.mark.requires_backend_interface(interface=CipherBackend)
49@pytest.mark.wycheproof_tests("aes_gcm_test.json")
50def test_aes_gcm(backend, wycheproof):
51    key = binascii.unhexlify(wycheproof.testcase["key"])
52    iv = binascii.unhexlify(wycheproof.testcase["iv"])
53    aad = binascii.unhexlify(wycheproof.testcase["aad"])
54    msg = binascii.unhexlify(wycheproof.testcase["msg"])
55    ct = binascii.unhexlify(wycheproof.testcase["ct"])
56    tag = binascii.unhexlify(wycheproof.testcase["tag"])
57    if len(iv) < 8 or len(iv) > 128:
58        pytest.skip(
59            "Less than 64-bit IVs (and greater than 1024-bit) are no longer "
60            "supported"
61        )
62    if backend._fips_enabled and len(iv) != 12:
63        # Red Hat disables non-96-bit IV support as part of its FIPS
64        # patches.
65        pytest.skip("Non-96-bit IVs unsupported in FIPS mode.")
66    if wycheproof.valid or wycheproof.acceptable:
67        enc = Cipher(algorithms.AES(key), modes.GCM(iv), backend).encryptor()
68        enc.authenticate_additional_data(aad)
69        computed_ct = enc.update(msg) + enc.finalize()
70        computed_tag = enc.tag
71        assert computed_ct == ct
72        assert computed_tag == tag
73        dec = Cipher(
74            algorithms.AES(key),
75            modes.GCM(iv, tag, min_tag_length=len(tag)),
76            backend,
77        ).decryptor()
78        dec.authenticate_additional_data(aad)
79        computed_msg = dec.update(ct) + dec.finalize()
80        assert computed_msg == msg
81    else:
82        dec = Cipher(
83            algorithms.AES(key),
84            modes.GCM(iv, tag, min_tag_length=len(tag)),
85            backend,
86        ).decryptor()
87        dec.authenticate_additional_data(aad)
88        dec.update(ct)
89        with pytest.raises(InvalidTag):
90            dec.finalize()
91
92
93@pytest.mark.requires_backend_interface(interface=CipherBackend)
94@pytest.mark.wycheproof_tests("aes_gcm_test.json")
95def test_aes_gcm_aead_api(backend, wycheproof):
96    key = binascii.unhexlify(wycheproof.testcase["key"])
97    iv = binascii.unhexlify(wycheproof.testcase["iv"])
98    aad = binascii.unhexlify(wycheproof.testcase["aad"])
99    msg = binascii.unhexlify(wycheproof.testcase["msg"])
100    ct = binascii.unhexlify(wycheproof.testcase["ct"])
101    tag = binascii.unhexlify(wycheproof.testcase["tag"])
102    if len(iv) < 8 or len(iv) > 128:
103        pytest.skip(
104            "Less than 64-bit IVs (and greater than 1024-bit) are no longer "
105            "supported"
106        )
107
108    if backend._fips_enabled and len(iv) != 12:
109        # Red Hat disables non-96-bit IV support as part of its FIPS
110        # patches.
111        pytest.skip("Non-96-bit IVs unsupported in FIPS mode.")
112    aesgcm = AESGCM(key)
113    if wycheproof.valid or wycheproof.acceptable:
114        computed_ct = aesgcm.encrypt(iv, msg, aad)
115        assert computed_ct == ct + tag
116        computed_msg = aesgcm.decrypt(iv, ct + tag, aad)
117        assert computed_msg == msg
118    else:
119        with pytest.raises(InvalidTag):
120            aesgcm.decrypt(iv, ct + tag, aad)
121
122
123@pytest.mark.skipif(
124    not _aead_supported(AESCCM),
125    reason="Requires OpenSSL with AES-CCM support",
126)
127@pytest.mark.requires_backend_interface(interface=CipherBackend)
128@pytest.mark.wycheproof_tests("aes_ccm_test.json")
129def test_aes_ccm_aead_api(backend, wycheproof):
130    key = binascii.unhexlify(wycheproof.testcase["key"])
131    iv = binascii.unhexlify(wycheproof.testcase["iv"])
132    aad = binascii.unhexlify(wycheproof.testcase["aad"])
133    msg = binascii.unhexlify(wycheproof.testcase["msg"])
134    ct = binascii.unhexlify(wycheproof.testcase["ct"])
135    tag = binascii.unhexlify(wycheproof.testcase["tag"])
136
137    if (
138        wycheproof.invalid
139        and wycheproof.testcase["comment"] == "Invalid tag size"
140    ):
141        with pytest.raises(ValueError):
142            AESCCM(key, tag_length=wycheproof.testgroup["tagSize"] // 8)
143        return
144
145    aesccm = AESCCM(key, tag_length=wycheproof.testgroup["tagSize"] // 8)
146    if wycheproof.valid or wycheproof.acceptable:
147        computed_ct = aesccm.encrypt(iv, msg, aad)
148        assert computed_ct == ct + tag
149        computed_msg = aesccm.decrypt(iv, ct + tag, aad)
150        assert computed_msg == msg
151    elif not 7 <= len(iv) <= 13:
152        with pytest.raises(ValueError):
153            aesccm.decrypt(iv, ct + tag, aad)
154    else:
155        with pytest.raises(InvalidTag):
156            aesccm.decrypt(iv, ct + tag, aad)
157