2 * NIST SP800-38C compliant CCM implementation
\r
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
\r
5 * SPDX-License-Identifier: Apache-2.0
\r
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
\r
8 * not use this file except in compliance with the License.
\r
9 * You may obtain a copy of the License at
\r
11 * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * Unless required by applicable law or agreed to in writing, software
\r
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
\r
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * See the License for the specific language governing permissions and
\r
17 * limitations under the License.
\r
19 * This file is part of mbed TLS (https://tls.mbed.org)
\r
23 * Definition of CCM:
\r
24 * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
\r
25 * RFC 3610 "Counter with CBC-MAC (CCM)"
\r
28 * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
\r
31 #if !defined(MBEDTLS_CONFIG_FILE)
\r
32 #include "mbedtls/config.h"
\r
34 #include MBEDTLS_CONFIG_FILE
\r
37 #if defined(MBEDTLS_CCM_C)
\r
39 #include "mbedtls/ccm.h"
\r
40 #include "mbedtls/platform_util.h"
\r
44 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
\r
45 #if defined(MBEDTLS_PLATFORM_C)
\r
46 #include "mbedtls/platform.h"
\r
49 #define mbedtls_printf printf
\r
50 #endif /* MBEDTLS_PLATFORM_C */
\r
51 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
\r
53 #if !defined(MBEDTLS_CCM_ALT)
\r
55 #define CCM_VALIDATE_RET( cond ) \
\r
56 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CCM_BAD_INPUT )
\r
57 #define CCM_VALIDATE( cond ) \
\r
58 MBEDTLS_INTERNAL_VALIDATE( cond )
\r
60 #define CCM_ENCRYPT 0
\r
61 #define CCM_DECRYPT 1
\r
64 * Initialize context
\r
66 void mbedtls_ccm_init( mbedtls_ccm_context *ctx )
\r
68 CCM_VALIDATE( ctx != NULL );
\r
69 memset( ctx, 0, sizeof( mbedtls_ccm_context ) );
\r
72 int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
\r
73 mbedtls_cipher_id_t cipher,
\r
74 const unsigned char *key,
\r
75 unsigned int keybits )
\r
78 const mbedtls_cipher_info_t *cipher_info;
\r
80 CCM_VALIDATE_RET( ctx != NULL );
\r
81 CCM_VALIDATE_RET( key != NULL );
\r
83 cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
\r
85 if( cipher_info == NULL )
\r
86 return( MBEDTLS_ERR_CCM_BAD_INPUT );
\r
88 if( cipher_info->block_size != 16 )
\r
89 return( MBEDTLS_ERR_CCM_BAD_INPUT );
\r
91 mbedtls_cipher_free( &ctx->cipher_ctx );
\r
93 if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
\r
96 if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
\r
97 MBEDTLS_ENCRYPT ) ) != 0 )
\r
108 void mbedtls_ccm_free( mbedtls_ccm_context *ctx )
\r
112 mbedtls_cipher_free( &ctx->cipher_ctx );
\r
113 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ccm_context ) );
\r
117 * Macros for common operations.
\r
118 * Results in smaller compiled code than static inline functions.
\r
122 * Update the CBC-MAC state in y using a block in b
\r
123 * (Always using b as the source helps the compiler optimise a bit better.)
\r
125 #define UPDATE_CBC_MAC \
\r
126 for( i = 0; i < 16; i++ ) \
\r
129 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
\r
133 * Encrypt or decrypt a partial block with CTR
\r
134 * Warning: using b for temporary storage! src and dst must not be b!
\r
135 * This avoids allocating one more 16 bytes buffer while allowing src == dst.
\r
137 #define CTR_CRYPT( dst, src, len ) \
\r
140 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, \
\r
141 16, b, &olen ) ) != 0 ) \
\r
146 for( i = 0; i < (len); i++ ) \
\r
147 (dst)[i] = (src)[i] ^ b[i]; \
\r
151 * Authenticated encryption or decryption
\r
153 static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
\r
154 const unsigned char *iv, size_t iv_len,
\r
155 const unsigned char *add, size_t add_len,
\r
156 const unsigned char *input, unsigned char *output,
\r
157 unsigned char *tag, size_t tag_len )
\r
162 size_t len_left, olen;
\r
163 unsigned char b[16];
\r
164 unsigned char y[16];
\r
165 unsigned char ctr[16];
\r
166 const unsigned char *src;
\r
167 unsigned char *dst;
\r
170 * Check length requirements: SP800-38C A.1
\r
171 * Additional requirement: a < 2^16 - 2^8 to simplify the code.
\r
172 * 'length' checked later (when writing it to the first block)
\r
174 * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
\r
176 if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 )
\r
177 return( MBEDTLS_ERR_CCM_BAD_INPUT );
\r
179 /* Also implies q is within bounds */
\r
180 if( iv_len < 7 || iv_len > 13 )
\r
181 return( MBEDTLS_ERR_CCM_BAD_INPUT );
\r
183 if( add_len > 0xFF00 )
\r
184 return( MBEDTLS_ERR_CCM_BAD_INPUT );
\r
186 q = 16 - 1 - (unsigned char) iv_len;
\r
191 * 1 .. iv_len nonce (aka iv)
\r
192 * iv_len+1 .. 15 length
\r
194 * With flags as (bits):
\r
197 * 5 .. 3 (t - 2) / 2
\r
201 b[0] |= ( add_len > 0 ) << 6;
\r
202 b[0] |= ( ( tag_len - 2 ) / 2 ) << 3;
\r
205 memcpy( b + 1, iv, iv_len );
\r
207 for( i = 0, len_left = length; i < q; i++, len_left >>= 8 )
\r
208 b[15-i] = (unsigned char)( len_left & 0xFF );
\r
211 return( MBEDTLS_ERR_CCM_BAD_INPUT );
\r
214 /* Start CBC-MAC with first block */
\r
215 memset( y, 0, 16 );
\r
219 * If there is additional data, update CBC-MAC with
\r
220 * add_len, add, 0 (padding to a block boundary)
\r
225 len_left = add_len;
\r
228 memset( b, 0, 16 );
\r
229 b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF );
\r
230 b[1] = (unsigned char)( ( add_len ) & 0xFF );
\r
232 use_len = len_left < 16 - 2 ? len_left : 16 - 2;
\r
233 memcpy( b + 2, src, use_len );
\r
234 len_left -= use_len;
\r
239 while( len_left > 0 )
\r
241 use_len = len_left > 16 ? 16 : len_left;
\r
243 memset( b, 0, 16 );
\r
244 memcpy( b, src, use_len );
\r
247 len_left -= use_len;
\r
253 * Prepare counter block for encryption:
\r
255 * 1 .. iv_len nonce (aka iv)
\r
256 * iv_len+1 .. 15 counter (initially 1)
\r
258 * With flags as (bits):
\r
263 memcpy( ctr + 1, iv, iv_len );
\r
264 memset( ctr + 1 + iv_len, 0, q );
\r
268 * Authenticate and {en,de}crypt the message.
\r
270 * The only difference between encryption and decryption is
\r
271 * the respective order of authentication and {en,de}cryption.
\r
277 while( len_left > 0 )
\r
279 size_t use_len = len_left > 16 ? 16 : len_left;
\r
281 if( mode == CCM_ENCRYPT )
\r
283 memset( b, 0, 16 );
\r
284 memcpy( b, src, use_len );
\r
288 CTR_CRYPT( dst, src, use_len );
\r
290 if( mode == CCM_DECRYPT )
\r
292 memset( b, 0, 16 );
\r
293 memcpy( b, dst, use_len );
\r
299 len_left -= use_len;
\r
302 * Increment counter.
\r
303 * No need to check for overflow thanks to the length check above.
\r
305 for( i = 0; i < q; i++ )
\r
306 if( ++ctr[15-i] != 0 )
\r
311 * Authentication: reset counter and crypt/mask internal tag
\r
313 for( i = 0; i < q; i++ )
\r
316 CTR_CRYPT( y, y, 16 );
\r
317 memcpy( tag, y, tag_len );
\r
323 * Authenticated encryption
\r
325 int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
\r
326 const unsigned char *iv, size_t iv_len,
\r
327 const unsigned char *add, size_t add_len,
\r
328 const unsigned char *input, unsigned char *output,
\r
329 unsigned char *tag, size_t tag_len )
\r
331 CCM_VALIDATE_RET( ctx != NULL );
\r
332 CCM_VALIDATE_RET( iv != NULL );
\r
333 CCM_VALIDATE_RET( add_len == 0 || add != NULL );
\r
334 CCM_VALIDATE_RET( length == 0 || input != NULL );
\r
335 CCM_VALIDATE_RET( length == 0 || output != NULL );
\r
336 CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
\r
337 return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len,
\r
338 add, add_len, input, output, tag, tag_len ) );
\r
341 int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
\r
342 const unsigned char *iv, size_t iv_len,
\r
343 const unsigned char *add, size_t add_len,
\r
344 const unsigned char *input, unsigned char *output,
\r
345 unsigned char *tag, size_t tag_len )
\r
347 CCM_VALIDATE_RET( ctx != NULL );
\r
348 CCM_VALIDATE_RET( iv != NULL );
\r
349 CCM_VALIDATE_RET( add_len == 0 || add != NULL );
\r
350 CCM_VALIDATE_RET( length == 0 || input != NULL );
\r
351 CCM_VALIDATE_RET( length == 0 || output != NULL );
\r
352 CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
\r
354 return( MBEDTLS_ERR_CCM_BAD_INPUT );
\r
356 return( mbedtls_ccm_star_encrypt_and_tag( ctx, length, iv, iv_len, add,
\r
357 add_len, input, output, tag, tag_len ) );
\r
361 * Authenticated decryption
\r
363 int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
\r
364 const unsigned char *iv, size_t iv_len,
\r
365 const unsigned char *add, size_t add_len,
\r
366 const unsigned char *input, unsigned char *output,
\r
367 const unsigned char *tag, size_t tag_len )
\r
370 unsigned char check_tag[16];
\r
374 CCM_VALIDATE_RET( ctx != NULL );
\r
375 CCM_VALIDATE_RET( iv != NULL );
\r
376 CCM_VALIDATE_RET( add_len == 0 || add != NULL );
\r
377 CCM_VALIDATE_RET( length == 0 || input != NULL );
\r
378 CCM_VALIDATE_RET( length == 0 || output != NULL );
\r
379 CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
\r
381 if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length,
\r
382 iv, iv_len, add, add_len,
\r
383 input, output, check_tag, tag_len ) ) != 0 )
\r
388 /* Check tag in "constant-time" */
\r
389 for( diff = 0, i = 0; i < tag_len; i++ )
\r
390 diff |= tag[i] ^ check_tag[i];
\r
394 mbedtls_platform_zeroize( output, length );
\r
395 return( MBEDTLS_ERR_CCM_AUTH_FAILED );
\r
401 int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
\r
402 const unsigned char *iv, size_t iv_len,
\r
403 const unsigned char *add, size_t add_len,
\r
404 const unsigned char *input, unsigned char *output,
\r
405 const unsigned char *tag, size_t tag_len )
\r
407 CCM_VALIDATE_RET( ctx != NULL );
\r
408 CCM_VALIDATE_RET( iv != NULL );
\r
409 CCM_VALIDATE_RET( add_len == 0 || add != NULL );
\r
410 CCM_VALIDATE_RET( length == 0 || input != NULL );
\r
411 CCM_VALIDATE_RET( length == 0 || output != NULL );
\r
412 CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
\r
415 return( MBEDTLS_ERR_CCM_BAD_INPUT );
\r
417 return( mbedtls_ccm_star_auth_decrypt( ctx, length, iv, iv_len, add,
\r
418 add_len, input, output, tag, tag_len ) );
\r
420 #endif /* !MBEDTLS_CCM_ALT */
\r
422 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
\r
424 * Examples 1 to 3 from SP800-38C Appendix C
\r
428 #define CCM_SELFTEST_PT_MAX_LEN 24
\r
429 #define CCM_SELFTEST_CT_MAX_LEN 32
\r
431 * The data is the same for all tests, only the used length changes
\r
433 static const unsigned char key_test_data[] = {
\r
434 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
\r
435 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
\r
438 static const unsigned char iv_test_data[] = {
\r
439 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
\r
440 0x18, 0x19, 0x1a, 0x1b
\r
443 static const unsigned char ad_test_data[] = {
\r
444 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
\r
445 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
\r
446 0x10, 0x11, 0x12, 0x13
\r
449 static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
\r
450 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
\r
451 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
\r
452 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
\r
455 static const size_t iv_len_test_data [NB_TESTS] = { 7, 8, 12 };
\r
456 static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
\r
457 static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
\r
458 static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 };
\r
460 static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
\r
461 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
\r
462 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
\r
463 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
\r
464 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
\r
465 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
\r
466 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
\r
467 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
\r
468 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
\r
471 int mbedtls_ccm_self_test( int verbose )
\r
473 mbedtls_ccm_context ctx;
\r
475 * Some hardware accelerators require the input and output buffers
\r
476 * would be in RAM, because the flash is not accessible.
\r
477 * Use buffers on the stack to hold the test vectors data.
\r
479 unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
\r
480 unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
\r
484 mbedtls_ccm_init( &ctx );
\r
486 if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
\r
487 8 * sizeof key_test_data ) != 0 )
\r
490 mbedtls_printf( " CCM: setup failed" );
\r
495 for( i = 0; i < NB_TESTS; i++ )
\r
498 mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 );
\r
500 memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
\r
501 memset( ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN );
\r
502 memcpy( plaintext, msg_test_data, msg_len_test_data[i] );
\r
504 ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len_test_data[i],
\r
505 iv_test_data, iv_len_test_data[i],
\r
506 ad_test_data, add_len_test_data[i],
\r
507 plaintext, ciphertext,
\r
508 ciphertext + msg_len_test_data[i],
\r
509 tag_len_test_data[i] );
\r
512 memcmp( ciphertext, res_test_data[i],
\r
513 msg_len_test_data[i] + tag_len_test_data[i] ) != 0 )
\r
516 mbedtls_printf( "failed\n" );
\r
520 memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
\r
522 ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len_test_data[i],
\r
523 iv_test_data, iv_len_test_data[i],
\r
524 ad_test_data, add_len_test_data[i],
\r
525 ciphertext, plaintext,
\r
526 ciphertext + msg_len_test_data[i],
\r
527 tag_len_test_data[i] );
\r
530 memcmp( plaintext, msg_test_data, msg_len_test_data[i] ) != 0 )
\r
533 mbedtls_printf( "failed\n" );
\r
539 mbedtls_printf( "passed\n" );
\r
542 mbedtls_ccm_free( &ctx );
\r
545 mbedtls_printf( "\n" );
\r
550 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
\r
552 #endif /* MBEDTLS_CCM_C */
\r