• 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 (
12    AlreadyFinalized,
13    InvalidSignature,
14    _Reasons,
15)
16from cryptography.hazmat.backends.interfaces import CMACBackend
17from cryptography.hazmat.primitives.ciphers.algorithms import (
18    AES,
19    ARC4,
20    TripleDES,
21)
22from cryptography.hazmat.primitives.cmac import CMAC
23
24from ...utils import (
25    load_nist_vectors,
26    load_vectors_from_file,
27    raises_unsupported_algorithm,
28)
29
30
31vectors_aes128 = load_vectors_from_file(
32    "CMAC/nist-800-38b-aes128.txt", load_nist_vectors
33)
34
35vectors_aes192 = load_vectors_from_file(
36    "CMAC/nist-800-38b-aes192.txt", load_nist_vectors
37)
38
39vectors_aes256 = load_vectors_from_file(
40    "CMAC/nist-800-38b-aes256.txt", load_nist_vectors
41)
42
43vectors_aes = vectors_aes128 + vectors_aes192 + vectors_aes256
44
45vectors_3des = load_vectors_from_file(
46    "CMAC/nist-800-38b-3des.txt", load_nist_vectors
47)
48
49fake_key = b"\x00" * 16
50
51
52@pytest.mark.requires_backend_interface(interface=CMACBackend)
53class TestCMAC(object):
54    @pytest.mark.supported(
55        only_if=lambda backend: backend.cmac_algorithm_supported(
56            AES(fake_key)
57        ),
58        skip_message="Does not support CMAC.",
59    )
60    @pytest.mark.parametrize("params", vectors_aes)
61    def test_aes_generate(self, backend, params):
62        key = params["key"]
63        message = params["message"]
64        output = params["output"]
65
66        cmac = CMAC(AES(binascii.unhexlify(key)), backend)
67        cmac.update(binascii.unhexlify(message))
68        assert binascii.hexlify(cmac.finalize()) == output
69
70    @pytest.mark.supported(
71        only_if=lambda backend: backend.cmac_algorithm_supported(
72            AES(fake_key)
73        ),
74        skip_message="Does not support CMAC.",
75    )
76    @pytest.mark.parametrize("params", vectors_aes)
77    def test_aes_verify(self, backend, params):
78        key = params["key"]
79        message = params["message"]
80        output = params["output"]
81
82        cmac = CMAC(AES(binascii.unhexlify(key)), backend)
83        cmac.update(binascii.unhexlify(message))
84        assert cmac.verify(binascii.unhexlify(output)) is None
85
86    @pytest.mark.supported(
87        only_if=lambda backend: backend.cmac_algorithm_supported(
88            TripleDES(fake_key)
89        ),
90        skip_message="Does not support CMAC.",
91    )
92    @pytest.mark.parametrize("params", vectors_3des)
93    def test_3des_generate(self, backend, params):
94        key1 = params["key1"]
95        key2 = params["key2"]
96        key3 = params["key3"]
97
98        key = key1 + key2 + key3
99
100        message = params["message"]
101        output = params["output"]
102
103        cmac = CMAC(TripleDES(binascii.unhexlify(key)), backend)
104        cmac.update(binascii.unhexlify(message))
105        assert binascii.hexlify(cmac.finalize()) == output
106
107    @pytest.mark.supported(
108        only_if=lambda backend: backend.cmac_algorithm_supported(
109            TripleDES(fake_key)
110        ),
111        skip_message="Does not support CMAC.",
112    )
113    @pytest.mark.parametrize("params", vectors_3des)
114    def test_3des_verify(self, backend, params):
115        key1 = params["key1"]
116        key2 = params["key2"]
117        key3 = params["key3"]
118
119        key = key1 + key2 + key3
120
121        message = params["message"]
122        output = params["output"]
123
124        cmac = CMAC(TripleDES(binascii.unhexlify(key)), backend)
125        cmac.update(binascii.unhexlify(message))
126        assert cmac.verify(binascii.unhexlify(output)) is None
127
128    @pytest.mark.supported(
129        only_if=lambda backend: backend.cmac_algorithm_supported(
130            AES(fake_key)
131        ),
132        skip_message="Does not support CMAC.",
133    )
134    def test_invalid_verify(self, backend):
135        key = b"2b7e151628aed2a6abf7158809cf4f3c"
136        cmac = CMAC(AES(key), backend)
137        cmac.update(b"6bc1bee22e409f96e93d7e117393172a")
138
139        with pytest.raises(InvalidSignature):
140            cmac.verify(b"foobar")
141
142    @pytest.mark.supported(
143        only_if=lambda backend: backend.cipher_supported(ARC4(fake_key), None),
144        skip_message="Does not support CMAC.",
145    )
146    def test_invalid_algorithm(self, backend):
147        key = b"0102030405"
148        with pytest.raises(TypeError):
149            CMAC(ARC4(key), backend)
150
151    @pytest.mark.supported(
152        only_if=lambda backend: backend.cmac_algorithm_supported(
153            AES(fake_key)
154        ),
155        skip_message="Does not support CMAC.",
156    )
157    def test_raises_after_finalize(self, backend):
158        key = b"2b7e151628aed2a6abf7158809cf4f3c"
159        cmac = CMAC(AES(key), backend)
160        cmac.finalize()
161
162        with pytest.raises(AlreadyFinalized):
163            cmac.update(b"foo")
164
165        with pytest.raises(AlreadyFinalized):
166            cmac.copy()
167
168        with pytest.raises(AlreadyFinalized):
169            cmac.finalize()
170
171        with pytest.raises(AlreadyFinalized):
172            cmac.verify(b"")
173
174    @pytest.mark.supported(
175        only_if=lambda backend: backend.cmac_algorithm_supported(
176            AES(fake_key)
177        ),
178        skip_message="Does not support CMAC.",
179    )
180    def test_verify_reject_unicode(self, backend):
181        key = b"2b7e151628aed2a6abf7158809cf4f3c"
182        cmac = CMAC(AES(key), backend)
183
184        with pytest.raises(TypeError):
185            cmac.update(u"")
186
187        with pytest.raises(TypeError):
188            cmac.verify(u"")
189
190    @pytest.mark.supported(
191        only_if=lambda backend: backend.cmac_algorithm_supported(
192            AES(fake_key)
193        ),
194        skip_message="Does not support CMAC.",
195    )
196    def test_copy_with_backend(self, backend):
197        key = b"2b7e151628aed2a6abf7158809cf4f3c"
198        cmac = CMAC(AES(key), backend)
199        cmac.update(b"6bc1bee22e409f96e93d7e117393172a")
200        copy_cmac = cmac.copy()
201        assert cmac.finalize() == copy_cmac.finalize()
202
203    @pytest.mark.supported(
204        only_if=lambda backend: backend.cmac_algorithm_supported(
205            AES(fake_key)
206        ),
207        skip_message="Does not support CMAC.",
208    )
209    def test_buffer_protocol(self, backend):
210        key = bytearray(b"2b7e151628aed2a6abf7158809cf4f3c")
211        cmac = CMAC(AES(key), backend)
212        cmac.update(b"6bc1bee22e409f96e93d7e117393172a")
213        assert cmac.finalize() == binascii.unhexlify(
214            b"a21e6e647bfeaf5ca0a5e1bcd957dfad"
215        )
216
217
218def test_invalid_backend():
219    key = b"2b7e151628aed2a6abf7158809cf4f3c"
220    pretend_backend = object()
221
222    with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
223        CMAC(AES(key), pretend_backend)
224