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