2 * NIST SP800-38C compliant CCM implementation
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5 * SPDX-License-Identifier: GPL-2.0
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * This file is part of mbed TLS (https://tls.mbed.org)
26 * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
27 * RFC 3610 "Counter with CBC-MAC (CCM)"
30 * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
33 #if !defined(MBEDTLS_CONFIG_FILE)
34 #include "mbedtls/config.h"
36 #include MBEDTLS_CONFIG_FILE
39 #if defined(MBEDTLS_CCM_C)
41 #include "mbedtls/ccm.h"
45 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
46 #if defined(MBEDTLS_PLATFORM_C)
47 #include "mbedtls/platform.h"
50 #define mbedtls_printf printf
51 #endif /* MBEDTLS_PLATFORM_C */
52 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
54 /* Implementation that should never be optimized out by the compiler */
55 static void mbedtls_zeroize( void *v
, size_t n
) {
56 volatile unsigned char *p
= (unsigned char*)v
; while( n
-- ) *p
++ = 0;
65 void mbedtls_ccm_init( mbedtls_ccm_context
*ctx
)
67 memset( ctx
, 0, sizeof( mbedtls_ccm_context
) );
70 int mbedtls_ccm_setkey( mbedtls_ccm_context
*ctx
,
71 mbedtls_cipher_id_t cipher
,
72 const unsigned char *key
,
73 unsigned int keybits
)
76 const mbedtls_cipher_info_t
*cipher_info
;
78 cipher_info
= mbedtls_cipher_info_from_values( cipher
, keybits
, MBEDTLS_MODE_ECB
);
79 if( cipher_info
== NULL
)
80 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
82 if( cipher_info
->block_size
!= 16 )
83 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
85 mbedtls_cipher_free( &ctx
->cipher_ctx
);
87 if( ( ret
= mbedtls_cipher_setup( &ctx
->cipher_ctx
, cipher_info
) ) != 0 )
90 if( ( ret
= mbedtls_cipher_setkey( &ctx
->cipher_ctx
, key
, keybits
,
91 MBEDTLS_ENCRYPT
) ) != 0 )
102 void mbedtls_ccm_free( mbedtls_ccm_context
*ctx
)
104 mbedtls_cipher_free( &ctx
->cipher_ctx
);
105 mbedtls_zeroize( ctx
, sizeof( mbedtls_ccm_context
) );
109 * Macros for common operations.
110 * Results in smaller compiled code than static inline functions.
114 * Update the CBC-MAC state in y using a block in b
115 * (Always using b as the source helps the compiler optimise a bit better.)
117 #define UPDATE_CBC_MAC \
118 for( i = 0; i < 16; i++ ) \
121 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
125 * Encrypt or decrypt a partial block with CTR
126 * Warning: using b for temporary storage! src and dst must not be b!
127 * This avoids allocating one more 16 bytes buffer while allowing src == dst.
129 #define CTR_CRYPT( dst, src, len ) \
130 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \
133 for( i = 0; i < len; i++ ) \
134 dst[i] = src[i] ^ b[i];
137 * Authenticated encryption or decryption
139 static int ccm_auth_crypt( mbedtls_ccm_context
*ctx
, int mode
, size_t length
,
140 const unsigned char *iv
, size_t iv_len
,
141 const unsigned char *add
, size_t add_len
,
142 const unsigned char *input
, unsigned char *output
,
143 unsigned char *tag
, size_t tag_len
)
148 size_t len_left
, olen
;
151 unsigned char ctr
[16];
152 const unsigned char *src
;
156 * Check length requirements: SP800-38C A.1
157 * Additional requirement: a < 2^16 - 2^8 to simplify the code.
158 * 'length' checked later (when writing it to the first block)
160 if( tag_len
< 4 || tag_len
> 16 || tag_len
% 2 != 0 )
161 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
163 /* Also implies q is within bounds */
164 if( iv_len
< 7 || iv_len
> 13 )
165 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
167 if( add_len
> 0xFF00 )
168 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
170 q
= 16 - 1 - (unsigned char) iv_len
;
175 * 1 .. iv_len nonce (aka iv)
176 * iv_len+1 .. 15 length
178 * With flags as (bits):
185 b
[0] |= ( add_len
> 0 ) << 6;
186 b
[0] |= ( ( tag_len
- 2 ) / 2 ) << 3;
189 memcpy( b
+ 1, iv
, iv_len
);
191 for( i
= 0, len_left
= length
; i
< q
; i
++, len_left
>>= 8 )
192 b
[15-i
] = (unsigned char)( len_left
& 0xFF );
195 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
198 /* Start CBC-MAC with first block */
203 * If there is additional data, update CBC-MAC with
204 * add_len, add, 0 (padding to a block boundary)
213 b
[0] = (unsigned char)( ( add_len
>> 8 ) & 0xFF );
214 b
[1] = (unsigned char)( ( add_len
) & 0xFF );
216 use_len
= len_left
< 16 - 2 ? len_left
: 16 - 2;
217 memcpy( b
+ 2, src
, use_len
);
223 while( len_left
> 0 )
225 use_len
= len_left
> 16 ? 16 : len_left
;
228 memcpy( b
, src
, use_len
);
237 * Prepare counter block for encryption:
239 * 1 .. iv_len nonce (aka iv)
240 * iv_len+1 .. 15 counter (initially 1)
242 * With flags as (bits):
247 memcpy( ctr
+ 1, iv
, iv_len
);
248 memset( ctr
+ 1 + iv_len
, 0, q
);
252 * Authenticate and {en,de}crypt the message.
254 * The only difference between encryption and decryption is
255 * the respective order of authentication and {en,de}cryption.
261 while( len_left
> 0 )
263 size_t use_len
= len_left
> 16 ? 16 : len_left
;
265 if( mode
== CCM_ENCRYPT
)
268 memcpy( b
, src
, use_len
);
272 CTR_CRYPT( dst
, src
, use_len
);
274 if( mode
== CCM_DECRYPT
)
277 memcpy( b
, dst
, use_len
);
287 * No need to check for overflow thanks to the length check above.
289 for( i
= 0; i
< q
; i
++ )
290 if( ++ctr
[15-i
] != 0 )
295 * Authentication: reset counter and crypt/mask internal tag
297 for( i
= 0; i
< q
; i
++ )
300 CTR_CRYPT( y
, y
, 16 );
301 memcpy( tag
, y
, tag_len
);
307 * Authenticated encryption
309 int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context
*ctx
, size_t length
,
310 const unsigned char *iv
, size_t iv_len
,
311 const unsigned char *add
, size_t add_len
,
312 const unsigned char *input
, unsigned char *output
,
313 unsigned char *tag
, size_t tag_len
)
315 return( ccm_auth_crypt( ctx
, CCM_ENCRYPT
, length
, iv
, iv_len
,
316 add
, add_len
, input
, output
, tag
, tag_len
) );
320 * Authenticated decryption
322 int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context
*ctx
, size_t length
,
323 const unsigned char *iv
, size_t iv_len
,
324 const unsigned char *add
, size_t add_len
,
325 const unsigned char *input
, unsigned char *output
,
326 const unsigned char *tag
, size_t tag_len
)
329 unsigned char check_tag
[16];
333 if( ( ret
= ccm_auth_crypt( ctx
, CCM_DECRYPT
, length
,
334 iv
, iv_len
, add
, add_len
,
335 input
, output
, check_tag
, tag_len
) ) != 0 )
340 /* Check tag in "constant-time" */
341 for( diff
= 0, i
= 0; i
< tag_len
; i
++ )
342 diff
|= tag
[i
] ^ check_tag
[i
];
346 mbedtls_zeroize( output
, length
);
347 return( MBEDTLS_ERR_CCM_AUTH_FAILED
);
354 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
356 * Examples 1 to 3 from SP800-38C Appendix C
362 * The data is the same for all tests, only the used length changes
364 static const unsigned char key
[] = {
365 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
366 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
369 static const unsigned char iv
[] = {
370 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
371 0x18, 0x19, 0x1a, 0x1b
374 static const unsigned char ad
[] = {
375 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
376 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
377 0x10, 0x11, 0x12, 0x13
380 static const unsigned char msg
[] = {
381 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
382 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
383 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
386 static const size_t iv_len
[NB_TESTS
] = { 7, 8, 12 };
387 static const size_t add_len
[NB_TESTS
] = { 8, 16, 20 };
388 static const size_t msg_len
[NB_TESTS
] = { 4, 16, 24 };
389 static const size_t tag_len
[NB_TESTS
] = { 4, 6, 8 };
391 static const unsigned char res
[NB_TESTS
][32] = {
392 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
393 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
394 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
395 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
396 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
397 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
398 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
399 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
402 int mbedtls_ccm_self_test( int verbose
)
404 mbedtls_ccm_context ctx
;
405 unsigned char out
[32];
409 mbedtls_ccm_init( &ctx
);
411 if( mbedtls_ccm_setkey( &ctx
, MBEDTLS_CIPHER_ID_AES
, key
, 8 * sizeof key
) != 0 )
414 mbedtls_printf( " CCM: setup failed" );
419 for( i
= 0; i
< NB_TESTS
; i
++ )
422 mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i
+ 1 );
424 ret
= mbedtls_ccm_encrypt_and_tag( &ctx
, msg_len
[i
],
425 iv
, iv_len
[i
], ad
, add_len
[i
],
427 out
+ msg_len
[i
], tag_len
[i
] );
430 memcmp( out
, res
[i
], msg_len
[i
] + tag_len
[i
] ) != 0 )
433 mbedtls_printf( "failed\n" );
438 ret
= mbedtls_ccm_auth_decrypt( &ctx
, msg_len
[i
],
439 iv
, iv_len
[i
], ad
, add_len
[i
],
441 res
[i
] + msg_len
[i
], tag_len
[i
] );
444 memcmp( out
, msg
, msg_len
[i
] ) != 0 )
447 mbedtls_printf( "failed\n" );
453 mbedtls_printf( "passed\n" );
456 mbedtls_ccm_free( &ctx
);
459 mbedtls_printf( "\n" );
464 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
466 #endif /* MBEDTLS_CCM_C */