2 * NIST SP800-38C compliant CCM implementation
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
23 * RFC 3610 "Counter with CBC-MAC (CCM)"
26 * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
31 #if defined(MBEDTLS_CCM_C)
33 #include "mbedtls/ccm.h"
34 #include "mbedtls/platform_util.h"
35 #include "mbedtls/error.h"
39 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
40 #if defined(MBEDTLS_PLATFORM_C)
41 #include "mbedtls/platform.h"
44 #define mbedtls_printf printf
45 #endif /* MBEDTLS_PLATFORM_C */
46 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
48 #if !defined(MBEDTLS_CCM_ALT)
50 #define CCM_VALIDATE_RET( cond ) \
51 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CCM_BAD_INPUT )
52 #define CCM_VALIDATE( cond ) \
53 MBEDTLS_INTERNAL_VALIDATE( cond )
61 void mbedtls_ccm_init(mbedtls_ccm_context
*ctx
) {
62 CCM_VALIDATE(ctx
!= NULL
);
63 memset(ctx
, 0, sizeof(mbedtls_ccm_context
));
66 int mbedtls_ccm_setkey(mbedtls_ccm_context
*ctx
,
67 mbedtls_cipher_id_t cipher
,
68 const unsigned char *key
,
69 unsigned int keybits
) {
70 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
71 const mbedtls_cipher_info_t
*cipher_info
;
73 CCM_VALIDATE_RET(ctx
!= NULL
);
74 CCM_VALIDATE_RET(key
!= NULL
);
76 cipher_info
= mbedtls_cipher_info_from_values(cipher
, keybits
,
78 if (cipher_info
== NULL
)
79 return (MBEDTLS_ERR_CCM_BAD_INPUT
);
81 if (cipher_info
->block_size
!= 16)
82 return (MBEDTLS_ERR_CCM_BAD_INPUT
);
84 mbedtls_cipher_free(&ctx
->cipher_ctx
);
86 if ((ret
= mbedtls_cipher_setup(&ctx
->cipher_ctx
, cipher_info
)) != 0)
89 if ((ret
= mbedtls_cipher_setkey(&ctx
->cipher_ctx
, key
, keybits
,
90 MBEDTLS_ENCRYPT
)) != 0) {
100 void mbedtls_ccm_free(mbedtls_ccm_context
*ctx
) {
103 mbedtls_cipher_free(&ctx
->cipher_ctx
);
104 mbedtls_platform_zeroize(ctx
, sizeof(mbedtls_ccm_context
));
108 * Macros for common operations.
109 * Results in smaller compiled code than static inline functions.
113 * Update the CBC-MAC state in y using a block in b
114 * (Always using b as the source helps the compiler optimise a bit better.)
116 #define UPDATE_CBC_MAC \
117 for( i = 0; i < 16; i++ ) \
120 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
124 * Encrypt or decrypt a partial block with CTR
125 * Warning: using b for temporary storage! src and dst must not be b!
126 * This avoids allocating one more 16 bytes buffer while allowing src == dst.
128 #define CTR_CRYPT( dst, src, len ) \
131 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, \
132 16, b, &olen ) ) != 0 ) \
137 for( i = 0; i < (len); i++ ) \
138 (dst)[i] = (src)[i] ^ b[i]; \
142 * Authenticated encryption or decryption
144 static int ccm_auth_crypt(mbedtls_ccm_context
*ctx
, int mode
, size_t length
,
145 const unsigned char *iv
, size_t iv_len
,
146 const unsigned char *add
, size_t add_len
,
147 const unsigned char *input
, unsigned char *output
,
148 unsigned char *tag
, size_t tag_len
) {
149 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
152 size_t len_left
, olen
;
155 unsigned char ctr
[16];
156 const unsigned char *src
;
160 * Check length requirements: SP800-38C A.1
161 * Additional requirement: a < 2^16 - 2^8 to simplify the code.
162 * 'length' checked later (when writing it to the first block)
164 * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
166 if (tag_len
== 2 || tag_len
> 16 || tag_len
% 2 != 0)
167 return (MBEDTLS_ERR_CCM_BAD_INPUT
);
169 /* Also implies q is within bounds */
170 if (iv_len
< 7 || iv_len
> 13)
171 return (MBEDTLS_ERR_CCM_BAD_INPUT
);
173 if (add_len
>= 0xFF00)
174 return (MBEDTLS_ERR_CCM_BAD_INPUT
);
176 q
= 16 - 1 - (unsigned char) iv_len
;
181 * 1 .. iv_len nonce (aka iv)
182 * iv_len+1 .. 15 length
184 * With flags as (bits):
191 b
[0] |= (add_len
> 0) << 6;
192 b
[0] |= ((tag_len
- 2) / 2) << 3;
195 memcpy(b
+ 1, iv
, iv_len
);
197 for (i
= 0, len_left
= length
; i
< q
; i
++, len_left
>>= 8)
198 b
[15 - i
] = (unsigned char)(len_left
& 0xFF);
201 return (MBEDTLS_ERR_CCM_BAD_INPUT
);
204 /* Start CBC-MAC with first block */
209 * If there is additional data, update CBC-MAC with
210 * add_len, add, 0 (padding to a block boundary)
218 b
[0] = (unsigned char)((add_len
>> 8) & 0xFF);
219 b
[1] = (unsigned char)((add_len
) & 0xFF);
221 use_len
= len_left
< 16 - 2 ? len_left
: 16 - 2;
222 memcpy(b
+ 2, src
, use_len
);
228 while (len_left
> 0) {
229 use_len
= len_left
> 16 ? 16 : len_left
;
232 memcpy(b
, src
, use_len
);
241 * Prepare counter block for encryption:
243 * 1 .. iv_len nonce (aka iv)
244 * iv_len+1 .. 15 counter (initially 1)
246 * With flags as (bits):
251 memcpy(ctr
+ 1, iv
, iv_len
);
252 memset(ctr
+ 1 + iv_len
, 0, q
);
256 * Authenticate and {en,de}crypt the message.
258 * The only difference between encryption and decryption is
259 * the respective order of authentication and {en,de}cryption.
265 while (len_left
> 0) {
266 size_t use_len
= len_left
> 16 ? 16 : len_left
;
268 if (mode
== CCM_ENCRYPT
) {
270 memcpy(b
, src
, use_len
);
274 CTR_CRYPT(dst
, src
, use_len
);
276 if (mode
== CCM_DECRYPT
) {
278 memcpy(b
, dst
, use_len
);
288 * No need to check for overflow thanks to the length check above.
290 for (i
= 0; i
< q
; i
++)
291 if (++ctr
[15 - i
] != 0)
296 * Authentication: reset counter and crypt/mask internal tag
298 for (i
= 0; i
< q
; i
++)
302 memcpy(tag
, y
, tag_len
);
308 * Authenticated encryption
310 int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context
*ctx
, size_t length
,
311 const unsigned char *iv
, size_t iv_len
,
312 const unsigned char *add
, size_t add_len
,
313 const unsigned char *input
, unsigned char *output
,
314 unsigned char *tag
, size_t tag_len
) {
315 CCM_VALIDATE_RET(ctx
!= NULL
);
316 CCM_VALIDATE_RET(iv
!= NULL
);
317 CCM_VALIDATE_RET(add_len
== 0 || add
!= NULL
);
318 CCM_VALIDATE_RET(length
== 0 || input
!= NULL
);
319 CCM_VALIDATE_RET(length
== 0 || output
!= NULL
);
320 CCM_VALIDATE_RET(tag_len
== 0 || tag
!= NULL
);
321 return (ccm_auth_crypt(ctx
, CCM_ENCRYPT
, length
, iv
, iv_len
,
322 add
, add_len
, input
, output
, tag
, tag_len
));
325 int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context
*ctx
, size_t length
,
326 const unsigned char *iv
, size_t iv_len
,
327 const unsigned char *add
, size_t add_len
,
328 const unsigned char *input
, unsigned char *output
,
329 unsigned char *tag
, size_t tag_len
) {
330 CCM_VALIDATE_RET(ctx
!= NULL
);
331 CCM_VALIDATE_RET(iv
!= NULL
);
332 CCM_VALIDATE_RET(add_len
== 0 || add
!= NULL
);
333 CCM_VALIDATE_RET(length
== 0 || input
!= NULL
);
334 CCM_VALIDATE_RET(length
== 0 || output
!= NULL
);
335 CCM_VALIDATE_RET(tag_len
== 0 || tag
!= NULL
);
337 return (MBEDTLS_ERR_CCM_BAD_INPUT
);
339 return (mbedtls_ccm_star_encrypt_and_tag(ctx
, length
, iv
, iv_len
, add
,
340 add_len
, input
, output
, tag
, tag_len
));
344 * Authenticated decryption
346 int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context
*ctx
, size_t length
,
347 const unsigned char *iv
, size_t iv_len
,
348 const unsigned char *add
, size_t add_len
,
349 const unsigned char *input
, unsigned char *output
,
350 const unsigned char *tag
, size_t tag_len
) {
351 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
352 unsigned char check_tag
[16];
356 CCM_VALIDATE_RET(ctx
!= NULL
);
357 CCM_VALIDATE_RET(iv
!= NULL
);
358 CCM_VALIDATE_RET(add_len
== 0 || add
!= NULL
);
359 CCM_VALIDATE_RET(length
== 0 || input
!= NULL
);
360 CCM_VALIDATE_RET(length
== 0 || output
!= NULL
);
361 CCM_VALIDATE_RET(tag_len
== 0 || tag
!= NULL
);
363 if ((ret
= ccm_auth_crypt(ctx
, CCM_DECRYPT
, length
,
364 iv
, iv_len
, add
, add_len
,
365 input
, output
, check_tag
, tag_len
)) != 0) {
369 /* Check tag in "constant-time" */
370 for (diff
= 0, i
= 0; i
< tag_len
; i
++)
371 diff
|= tag
[i
] ^ check_tag
[i
];
374 mbedtls_platform_zeroize(output
, length
);
375 return (MBEDTLS_ERR_CCM_AUTH_FAILED
);
381 int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context
*ctx
, size_t length
,
382 const unsigned char *iv
, size_t iv_len
,
383 const unsigned char *add
, size_t add_len
,
384 const unsigned char *input
, unsigned char *output
,
385 const unsigned char *tag
, size_t tag_len
) {
386 CCM_VALIDATE_RET(ctx
!= NULL
);
387 CCM_VALIDATE_RET(iv
!= NULL
);
388 CCM_VALIDATE_RET(add_len
== 0 || add
!= NULL
);
389 CCM_VALIDATE_RET(length
== 0 || input
!= NULL
);
390 CCM_VALIDATE_RET(length
== 0 || output
!= NULL
);
391 CCM_VALIDATE_RET(tag_len
== 0 || tag
!= NULL
);
394 return (MBEDTLS_ERR_CCM_BAD_INPUT
);
396 return (mbedtls_ccm_star_auth_decrypt(ctx
, length
, iv
, iv_len
, add
,
397 add_len
, input
, output
, tag
, tag_len
));
399 #endif /* !MBEDTLS_CCM_ALT */
401 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
403 * Examples 1 to 3 from SP800-38C Appendix C
407 #define CCM_SELFTEST_PT_MAX_LEN 24
408 #define CCM_SELFTEST_CT_MAX_LEN 32
410 * The data is the same for all tests, only the used length changes
412 static const unsigned char key_test_data
[] = {
413 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
414 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
417 static const unsigned char iv_test_data
[] = {
418 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
419 0x18, 0x19, 0x1a, 0x1b
422 static const unsigned char ad_test_data
[] = {
423 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
424 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
425 0x10, 0x11, 0x12, 0x13
428 static const unsigned char msg_test_data
[CCM_SELFTEST_PT_MAX_LEN
] = {
429 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
430 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
431 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
434 static const size_t iv_len_test_data
[NB_TESTS
] = { 7, 8, 12 };
435 static const size_t add_len_test_data
[NB_TESTS
] = { 8, 16, 20 };
436 static const size_t msg_len_test_data
[NB_TESTS
] = { 4, 16, 24 };
437 static const size_t tag_len_test_data
[NB_TESTS
] = { 4, 6, 8 };
439 static const unsigned char res_test_data
[NB_TESTS
][CCM_SELFTEST_CT_MAX_LEN
] = {
440 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
442 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
443 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
444 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd
447 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
448 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
449 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
450 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51
454 int mbedtls_ccm_self_test(int verbose
) {
455 mbedtls_ccm_context ctx
;
457 * Some hardware accelerators require the input and output buffers
458 * would be in RAM, because the flash is not accessible.
459 * Use buffers on the stack to hold the test vectors data.
461 unsigned char plaintext
[CCM_SELFTEST_PT_MAX_LEN
];
462 unsigned char ciphertext
[CCM_SELFTEST_CT_MAX_LEN
];
464 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
466 mbedtls_ccm_init(&ctx
);
468 if (mbedtls_ccm_setkey(&ctx
, MBEDTLS_CIPHER_ID_AES
, key_test_data
,
469 8 * sizeof key_test_data
) != 0) {
471 mbedtls_printf(" CCM: setup failed");
476 for (i
= 0; i
< NB_TESTS
; i
++) {
478 mbedtls_printf(" CCM-AES #%u: ", (unsigned int) i
+ 1);
480 memset(plaintext
, 0, CCM_SELFTEST_PT_MAX_LEN
);
481 memset(ciphertext
, 0, CCM_SELFTEST_CT_MAX_LEN
);
482 memcpy(plaintext
, msg_test_data
, msg_len_test_data
[i
]);
484 ret
= mbedtls_ccm_encrypt_and_tag(&ctx
, msg_len_test_data
[i
],
485 iv_test_data
, iv_len_test_data
[i
],
486 ad_test_data
, add_len_test_data
[i
],
487 plaintext
, ciphertext
,
488 ciphertext
+ msg_len_test_data
[i
],
489 tag_len_test_data
[i
]);
492 memcmp(ciphertext
, res_test_data
[i
],
493 msg_len_test_data
[i
] + tag_len_test_data
[i
]) != 0) {
495 mbedtls_printf("failed\n");
499 memset(plaintext
, 0, CCM_SELFTEST_PT_MAX_LEN
);
501 ret
= mbedtls_ccm_auth_decrypt(&ctx
, msg_len_test_data
[i
],
502 iv_test_data
, iv_len_test_data
[i
],
503 ad_test_data
, add_len_test_data
[i
],
504 ciphertext
, plaintext
,
505 ciphertext
+ msg_len_test_data
[i
],
506 tag_len_test_data
[i
]);
509 memcmp(plaintext
, msg_test_data
, msg_len_test_data
[i
]) != 0) {
511 mbedtls_printf("failed\n");
517 mbedtls_printf("passed\n");
520 mbedtls_ccm_free(&ctx
);
523 mbedtls_printf("\n");
528 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
530 #endif /* MBEDTLS_CCM_C */