2 * NIST SP800-38C compliant CCM implementation
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
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.
19 * This file is part of mbed TLS (https://tls.mbed.org)
24 * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
25 * RFC 3610 "Counter with CBC-MAC (CCM)"
28 * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
31 #if !defined(MBEDTLS_CONFIG_FILE)
32 #include "mbedtls/config.h"
34 #include MBEDTLS_CONFIG_FILE
37 #if defined(MBEDTLS_CCM_C)
39 #include "mbedtls/ccm.h"
43 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
44 #if defined(MBEDTLS_PLATFORM_C)
45 #include "mbedtls/platform.h"
48 #define mbedtls_printf printf
49 #endif /* MBEDTLS_PLATFORM_C */
50 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
52 /* Implementation that should never be optimized out by the compiler */
53 static void mbedtls_zeroize( void *v
, size_t n
) {
54 volatile unsigned char *p
= v
; while( n
-- ) *p
++ = 0;
63 void mbedtls_ccm_init( mbedtls_ccm_context
*ctx
)
65 memset( ctx
, 0, sizeof( mbedtls_ccm_context
) );
68 int mbedtls_ccm_setkey( mbedtls_ccm_context
*ctx
,
69 mbedtls_cipher_id_t cipher
,
70 const unsigned char *key
,
71 unsigned int keybits
)
74 const mbedtls_cipher_info_t
*cipher_info
;
76 cipher_info
= mbedtls_cipher_info_from_values( cipher
, keybits
, MBEDTLS_MODE_ECB
);
77 if( cipher_info
== NULL
)
78 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
80 if( cipher_info
->block_size
!= 16 )
81 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
83 mbedtls_cipher_free( &ctx
->cipher_ctx
);
85 if( ( ret
= mbedtls_cipher_setup( &ctx
->cipher_ctx
, cipher_info
) ) != 0 )
88 if( ( ret
= mbedtls_cipher_setkey( &ctx
->cipher_ctx
, key
, keybits
,
89 MBEDTLS_ENCRYPT
) ) != 0 )
100 void mbedtls_ccm_free( mbedtls_ccm_context
*ctx
)
102 mbedtls_cipher_free( &ctx
->cipher_ctx
);
103 mbedtls_zeroize( ctx
, sizeof( mbedtls_ccm_context
) );
107 * Macros for common operations.
108 * Results in smaller compiled code than static inline functions.
112 * Update the CBC-MAC state in y using a block in b
113 * (Always using b as the source helps the compiler optimise a bit better.)
115 #define UPDATE_CBC_MAC \
116 for( i = 0; i < 16; i++ ) \
119 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
123 * Encrypt or decrypt a partial block with CTR
124 * Warning: using b for temporary storage! src and dst must not be b!
125 * This avoids allocating one more 16 bytes buffer while allowing src == dst.
127 #define CTR_CRYPT( dst, src, len ) \
128 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \
131 for( i = 0; i < len; i++ ) \
132 dst[i] = src[i] ^ b[i];
135 * Authenticated encryption or decryption
137 static int ccm_auth_crypt( mbedtls_ccm_context
*ctx
, int mode
, size_t length
,
138 const unsigned char *iv
, size_t iv_len
,
139 const unsigned char *add
, size_t add_len
,
140 const unsigned char *input
, unsigned char *output
,
141 unsigned char *tag
, size_t tag_len
)
146 size_t len_left
, olen
;
149 unsigned char ctr
[16];
150 const unsigned char *src
;
154 * Check length requirements: SP800-38C A.1
155 * Additional requirement: a < 2^16 - 2^8 to simplify the code.
156 * 'length' checked later (when writing it to the first block)
158 if( tag_len
< 4 || tag_len
> 16 || tag_len
% 2 != 0 )
159 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
161 /* Also implies q is within bounds */
162 if( iv_len
< 7 || iv_len
> 13 )
163 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
165 if( add_len
> 0xFF00 )
166 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
168 q
= 16 - 1 - (unsigned char) iv_len
;
173 * 1 .. iv_len nonce (aka iv)
174 * iv_len+1 .. 15 length
176 * With flags as (bits):
183 b
[0] |= ( add_len
> 0 ) << 6;
184 b
[0] |= ( ( tag_len
- 2 ) / 2 ) << 3;
187 memcpy( b
+ 1, iv
, iv_len
);
189 for( i
= 0, len_left
= length
; i
< q
; i
++, len_left
>>= 8 )
190 b
[15-i
] = (unsigned char)( len_left
& 0xFF );
193 return( MBEDTLS_ERR_CCM_BAD_INPUT
);
196 /* Start CBC-MAC with first block */
201 * If there is additional data, update CBC-MAC with
202 * add_len, add, 0 (padding to a block boundary)
211 b
[0] = (unsigned char)( ( add_len
>> 8 ) & 0xFF );
212 b
[1] = (unsigned char)( ( add_len
) & 0xFF );
214 use_len
= len_left
< 16 - 2 ? len_left
: 16 - 2;
215 memcpy( b
+ 2, src
, use_len
);
221 while( len_left
> 0 )
223 use_len
= len_left
> 16 ? 16 : len_left
;
226 memcpy( b
, src
, use_len
);
235 * Prepare counter block for encryption:
237 * 1 .. iv_len nonce (aka iv)
238 * iv_len+1 .. 15 counter (initially 1)
240 * With flags as (bits):
245 memcpy( ctr
+ 1, iv
, iv_len
);
246 memset( ctr
+ 1 + iv_len
, 0, q
);
250 * Authenticate and {en,de}crypt the message.
252 * The only difference between encryption and decryption is
253 * the respective order of authentication and {en,de}cryption.
259 while( len_left
> 0 )
261 size_t use_len
= len_left
> 16 ? 16 : len_left
;
263 if( mode
== CCM_ENCRYPT
)
266 memcpy( b
, src
, use_len
);
270 CTR_CRYPT( dst
, src
, use_len
);
272 if( mode
== CCM_DECRYPT
)
275 memcpy( b
, dst
, use_len
);
285 * No need to check for overflow thanks to the length check above.
287 for( i
= 0; i
< q
; i
++ )
288 if( ++ctr
[15-i
] != 0 )
293 * Authentication: reset counter and crypt/mask internal tag
295 for( i
= 0; i
< q
; i
++ )
298 CTR_CRYPT( y
, y
, 16 );
299 memcpy( tag
, y
, tag_len
);
305 * Authenticated encryption
307 int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context
*ctx
, size_t length
,
308 const unsigned char *iv
, size_t iv_len
,
309 const unsigned char *add
, size_t add_len
,
310 const unsigned char *input
, unsigned char *output
,
311 unsigned char *tag
, size_t tag_len
)
313 return( ccm_auth_crypt( ctx
, CCM_ENCRYPT
, length
, iv
, iv_len
,
314 add
, add_len
, input
, output
, tag
, tag_len
) );
318 * Authenticated decryption
320 int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context
*ctx
, size_t length
,
321 const unsigned char *iv
, size_t iv_len
,
322 const unsigned char *add
, size_t add_len
,
323 const unsigned char *input
, unsigned char *output
,
324 const unsigned char *tag
, size_t tag_len
)
327 unsigned char check_tag
[16];
331 if( ( ret
= ccm_auth_crypt( ctx
, CCM_DECRYPT
, length
,
332 iv
, iv_len
, add
, add_len
,
333 input
, output
, check_tag
, tag_len
) ) != 0 )
338 /* Check tag in "constant-time" */
339 for( diff
= 0, i
= 0; i
< tag_len
; i
++ )
340 diff
|= tag
[i
] ^ check_tag
[i
];
344 mbedtls_zeroize( output
, length
);
345 return( MBEDTLS_ERR_CCM_AUTH_FAILED
);
352 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
354 * Examples 1 to 3 from SP800-38C Appendix C
360 * The data is the same for all tests, only the used length changes
362 static const unsigned char key
[] = {
363 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
364 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
367 static const unsigned char iv
[] = {
368 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
369 0x18, 0x19, 0x1a, 0x1b
372 static const unsigned char ad
[] = {
373 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
374 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
375 0x10, 0x11, 0x12, 0x13
378 static const unsigned char msg
[] = {
379 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
380 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
381 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
384 static const size_t iv_len
[NB_TESTS
] = { 7, 8, 12 };
385 static const size_t add_len
[NB_TESTS
] = { 8, 16, 20 };
386 static const size_t msg_len
[NB_TESTS
] = { 4, 16, 24 };
387 static const size_t tag_len
[NB_TESTS
] = { 4, 6, 8 };
389 static const unsigned char res
[NB_TESTS
][32] = {
390 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
391 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
392 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
393 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
394 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
395 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
396 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
397 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
400 int mbedtls_ccm_self_test( int verbose
)
402 mbedtls_ccm_context ctx
;
403 unsigned char out
[32];
407 mbedtls_ccm_init( &ctx
);
409 if( mbedtls_ccm_setkey( &ctx
, MBEDTLS_CIPHER_ID_AES
, key
, 8 * sizeof key
) != 0 )
412 mbedtls_printf( " CCM: setup failed" );
417 for( i
= 0; i
< NB_TESTS
; i
++ )
420 mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i
+ 1 );
422 ret
= mbedtls_ccm_encrypt_and_tag( &ctx
, msg_len
[i
],
423 iv
, iv_len
[i
], ad
, add_len
[i
],
425 out
+ msg_len
[i
], tag_len
[i
] );
428 memcmp( out
, res
[i
], msg_len
[i
] + tag_len
[i
] ) != 0 )
431 mbedtls_printf( "failed\n" );
436 ret
= mbedtls_ccm_auth_decrypt( &ctx
, msg_len
[i
],
437 iv
, iv_len
[i
], ad
, add_len
[i
],
439 res
[i
] + msg_len
[i
], tag_len
[i
] );
442 memcmp( out
, msg
, msg_len
[i
] ) != 0 )
445 mbedtls_printf( "failed\n" );
451 mbedtls_printf( "passed\n" );
454 mbedtls_ccm_free( &ctx
);
457 mbedtls_printf( "\n" );
462 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
464 #endif /* MBEDTLS_CCM_C */