Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ccm.c
00001 /* 00002 * NIST SP800-38C compliant CCM implementation 00003 * 00004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 00005 * SPDX-License-Identifier: Apache-2.0 00006 * 00007 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00008 * not use this file except in compliance with the License. 00009 * You may obtain a copy of the License at 00010 * 00011 * http://www.apache.org/licenses/LICENSE-2.0 00012 * 00013 * Unless required by applicable law or agreed to in writing, software 00014 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00015 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00016 * See the License for the specific language governing permissions and 00017 * limitations under the License. 00018 * 00019 * This file is part of mbed TLS (https://tls.mbed.org) 00020 */ 00021 00022 /* 00023 * Definition of CCM: 00024 * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf 00025 * RFC 3610 "Counter with CBC-MAC (CCM)" 00026 * 00027 * Related: 00028 * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" 00029 */ 00030 00031 #if !defined(MBEDTLS_CONFIG_FILE) 00032 #include "mbedtls/config.h" 00033 #else 00034 #include MBEDTLS_CONFIG_FILE 00035 #endif 00036 00037 #if defined(MBEDTLS_CCM_C) 00038 00039 #include "mbedtls/ccm.h" 00040 00041 #include <string.h> 00042 00043 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) 00044 #if defined(MBEDTLS_PLATFORM_C) 00045 #include "mbedtls/platform.h" 00046 #else 00047 #include <stdio.h> 00048 #define mbedtls_printf printf 00049 #endif /* MBEDTLS_PLATFORM_C */ 00050 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ 00051 00052 #if !defined(MBEDTLS_CCM_ALT) 00053 00054 /* Implementation that should never be optimized out by the compiler */ 00055 static void mbedtls_zeroize( void *v, size_t n ) { 00056 volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; 00057 } 00058 00059 #define CCM_ENCRYPT 0 00060 #define CCM_DECRYPT 1 00061 00062 /* 00063 * Initialize context 00064 */ 00065 void mbedtls_ccm_init( mbedtls_ccm_context *ctx ) 00066 { 00067 memset( ctx, 0, sizeof( mbedtls_ccm_context ) ); 00068 } 00069 00070 int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, 00071 mbedtls_cipher_id_t cipher, 00072 const unsigned char *key, 00073 unsigned int keybits ) 00074 { 00075 int ret; 00076 const mbedtls_cipher_info_t *cipher_info; 00077 00078 cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); 00079 if( cipher_info == NULL ) 00080 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00081 00082 if( cipher_info->block_size != 16 ) 00083 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00084 00085 mbedtls_cipher_free( &ctx->cipher_ctx ); 00086 00087 if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx , cipher_info ) ) != 0 ) 00088 return( ret ); 00089 00090 if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx , key, keybits, 00091 MBEDTLS_ENCRYPT ) ) != 0 ) 00092 { 00093 return( ret ); 00094 } 00095 00096 return( 0 ); 00097 } 00098 00099 /* 00100 * Free context 00101 */ 00102 void mbedtls_ccm_free( mbedtls_ccm_context *ctx ) 00103 { 00104 mbedtls_cipher_free( &ctx->cipher_ctx ); 00105 mbedtls_zeroize( ctx, sizeof( mbedtls_ccm_context ) ); 00106 } 00107 00108 /* 00109 * Macros for common operations. 00110 * Results in smaller compiled code than static inline functions. 00111 */ 00112 00113 /* 00114 * Update the CBC-MAC state in y using a block in b 00115 * (Always using b as the source helps the compiler optimise a bit better.) 00116 */ 00117 #define UPDATE_CBC_MAC \ 00118 for( i = 0; i < 16; i++ ) \ 00119 y[i] ^= b[i]; \ 00120 \ 00121 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \ 00122 return( ret ); 00123 00124 /* 00125 * Encrypt or decrypt a partial block with CTR 00126 * Warning: using b for temporary storage! src and dst must not be b! 00127 * This avoids allocating one more 16 bytes buffer while allowing src == dst. 00128 */ 00129 #define CTR_CRYPT( dst, src, len ) \ 00130 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \ 00131 return( ret ); \ 00132 \ 00133 for( i = 0; i < len; i++ ) \ 00134 dst[i] = src[i] ^ b[i]; 00135 00136 /* 00137 * Authenticated encryption or decryption 00138 */ 00139 static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length, 00140 const unsigned char *iv, size_t iv_len, 00141 const unsigned char *add, size_t add_len, 00142 const unsigned char *input, unsigned char *output, 00143 unsigned char *tag, size_t tag_len ) 00144 { 00145 int ret; 00146 unsigned char i; 00147 unsigned char q; 00148 size_t len_left, olen; 00149 unsigned char b[16]; 00150 unsigned char y[16]; 00151 unsigned char ctr[16]; 00152 const unsigned char *src; 00153 unsigned char *dst; 00154 00155 /* 00156 * Check length requirements: SP800-38C A.1 00157 * Additional requirement: a < 2^16 - 2^8 to simplify the code. 00158 * 'length' checked later (when writing it to the first block) 00159 */ 00160 if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 ) 00161 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00162 00163 /* Also implies q is within bounds */ 00164 if( iv_len < 7 || iv_len > 13 ) 00165 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00166 00167 if( add_len > 0xFF00 ) 00168 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00169 00170 q = 16 - 1 - (unsigned char) iv_len; 00171 00172 /* 00173 * First block B_0: 00174 * 0 .. 0 flags 00175 * 1 .. iv_len nonce (aka iv) 00176 * iv_len+1 .. 15 length 00177 * 00178 * With flags as (bits): 00179 * 7 0 00180 * 6 add present? 00181 * 5 .. 3 (t - 2) / 2 00182 * 2 .. 0 q - 1 00183 */ 00184 b[0] = 0; 00185 b[0] |= ( add_len > 0 ) << 6; 00186 b[0] |= ( ( tag_len - 2 ) / 2 ) << 3; 00187 b[0] |= q - 1; 00188 00189 memcpy( b + 1, iv, iv_len ); 00190 00191 for( i = 0, len_left = length; i < q; i++, len_left >>= 8 ) 00192 b[15-i] = (unsigned char)( len_left & 0xFF ); 00193 00194 if( len_left > 0 ) 00195 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00196 00197 00198 /* Start CBC-MAC with first block */ 00199 memset( y, 0, 16 ); 00200 UPDATE_CBC_MAC; 00201 00202 /* 00203 * If there is additional data, update CBC-MAC with 00204 * add_len, add, 0 (padding to a block boundary) 00205 */ 00206 if( add_len > 0 ) 00207 { 00208 size_t use_len; 00209 len_left = add_len; 00210 src = add; 00211 00212 memset( b, 0, 16 ); 00213 b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF ); 00214 b[1] = (unsigned char)( ( add_len ) & 0xFF ); 00215 00216 use_len = len_left < 16 - 2 ? len_left : 16 - 2; 00217 memcpy( b + 2, src, use_len ); 00218 len_left -= use_len; 00219 src += use_len; 00220 00221 UPDATE_CBC_MAC; 00222 00223 while( len_left > 0 ) 00224 { 00225 use_len = len_left > 16 ? 16 : len_left; 00226 00227 memset( b, 0, 16 ); 00228 memcpy( b, src, use_len ); 00229 UPDATE_CBC_MAC; 00230 00231 len_left -= use_len; 00232 src += use_len; 00233 } 00234 } 00235 00236 /* 00237 * Prepare counter block for encryption: 00238 * 0 .. 0 flags 00239 * 1 .. iv_len nonce (aka iv) 00240 * iv_len+1 .. 15 counter (initially 1) 00241 * 00242 * With flags as (bits): 00243 * 7 .. 3 0 00244 * 2 .. 0 q - 1 00245 */ 00246 ctr[0] = q - 1; 00247 memcpy( ctr + 1, iv, iv_len ); 00248 memset( ctr + 1 + iv_len, 0, q ); 00249 ctr[15] = 1; 00250 00251 /* 00252 * Authenticate and {en,de}crypt the message. 00253 * 00254 * The only difference between encryption and decryption is 00255 * the respective order of authentication and {en,de}cryption. 00256 */ 00257 len_left = length; 00258 src = input; 00259 dst = output; 00260 00261 while( len_left > 0 ) 00262 { 00263 size_t use_len = len_left > 16 ? 16 : len_left; 00264 00265 if( mode == CCM_ENCRYPT ) 00266 { 00267 memset( b, 0, 16 ); 00268 memcpy( b, src, use_len ); 00269 UPDATE_CBC_MAC; 00270 } 00271 00272 CTR_CRYPT( dst, src, use_len ); 00273 00274 if( mode == CCM_DECRYPT ) 00275 { 00276 memset( b, 0, 16 ); 00277 memcpy( b, dst, use_len ); 00278 UPDATE_CBC_MAC; 00279 } 00280 00281 dst += use_len; 00282 src += use_len; 00283 len_left -= use_len; 00284 00285 /* 00286 * Increment counter. 00287 * No need to check for overflow thanks to the length check above. 00288 */ 00289 for( i = 0; i < q; i++ ) 00290 if( ++ctr[15-i] != 0 ) 00291 break; 00292 } 00293 00294 /* 00295 * Authentication: reset counter and crypt/mask internal tag 00296 */ 00297 for( i = 0; i < q; i++ ) 00298 ctr[15-i] = 0; 00299 00300 CTR_CRYPT( y, y, 16 ); 00301 memcpy( tag, y, tag_len ); 00302 00303 return( 0 ); 00304 } 00305 00306 /* 00307 * Authenticated encryption 00308 */ 00309 int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, 00310 const unsigned char *iv, size_t iv_len, 00311 const unsigned char *add, size_t add_len, 00312 const unsigned char *input, unsigned char *output, 00313 unsigned char *tag, size_t tag_len ) 00314 { 00315 return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len, 00316 add, add_len, input, output, tag, tag_len ) ); 00317 } 00318 00319 /* 00320 * Authenticated decryption 00321 */ 00322 int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, 00323 const unsigned char *iv, size_t iv_len, 00324 const unsigned char *add, size_t add_len, 00325 const unsigned char *input, unsigned char *output, 00326 const unsigned char *tag, size_t tag_len ) 00327 { 00328 int ret; 00329 unsigned char check_tag[16]; 00330 unsigned char i; 00331 int diff; 00332 00333 if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length, 00334 iv, iv_len, add, add_len, 00335 input, output, check_tag, tag_len ) ) != 0 ) 00336 { 00337 return( ret ); 00338 } 00339 00340 /* Check tag in "constant-time" */ 00341 for( diff = 0, i = 0; i < tag_len; i++ ) 00342 diff |= tag[i] ^ check_tag[i]; 00343 00344 if( diff != 0 ) 00345 { 00346 mbedtls_zeroize( output, length ); 00347 return( MBEDTLS_ERR_CCM_AUTH_FAILED ); 00348 } 00349 00350 return( 0 ); 00351 } 00352 00353 #endif /* !MBEDTLS_CCM_ALT */ 00354 00355 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) 00356 /* 00357 * Examples 1 to 3 from SP800-38C Appendix C 00358 */ 00359 00360 #define NB_TESTS 3 00361 00362 /* 00363 * The data is the same for all tests, only the used length changes 00364 */ 00365 static const unsigned char key[] = { 00366 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 00367 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f 00368 }; 00369 00370 static const unsigned char iv[] = { 00371 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 00372 0x18, 0x19, 0x1a, 0x1b 00373 }; 00374 00375 static const unsigned char ad[] = { 00376 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 00377 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 00378 0x10, 0x11, 0x12, 0x13 00379 }; 00380 00381 static const unsigned char msg[] = { 00382 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 00383 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 00384 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 00385 }; 00386 00387 static const size_t iv_len [NB_TESTS] = { 7, 8, 12 }; 00388 static const size_t add_len[NB_TESTS] = { 8, 16, 20 }; 00389 static const size_t msg_len[NB_TESTS] = { 4, 16, 24 }; 00390 static const size_t tag_len[NB_TESTS] = { 4, 6, 8 }; 00391 00392 static const unsigned char res[NB_TESTS][32] = { 00393 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, 00394 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, 00395 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, 00396 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, 00397 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 00398 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 00399 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 00400 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } 00401 }; 00402 00403 int mbedtls_ccm_self_test( int verbose ) 00404 { 00405 mbedtls_ccm_context ctx; 00406 unsigned char out[32]; 00407 size_t i; 00408 int ret; 00409 00410 mbedtls_ccm_init( &ctx ); 00411 00412 if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 ) 00413 { 00414 if( verbose != 0 ) 00415 mbedtls_printf( " CCM: setup failed" ); 00416 00417 return( 1 ); 00418 } 00419 00420 for( i = 0; i < NB_TESTS; i++ ) 00421 { 00422 if( verbose != 0 ) 00423 mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 ); 00424 00425 ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i], 00426 iv, iv_len[i], ad, add_len[i], 00427 msg, out, 00428 out + msg_len[i], tag_len[i] ); 00429 00430 if( ret != 0 || 00431 memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 ) 00432 { 00433 if( verbose != 0 ) 00434 mbedtls_printf( "failed\n" ); 00435 00436 return( 1 ); 00437 } 00438 00439 ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i], 00440 iv, iv_len[i], ad, add_len[i], 00441 res[i], out, 00442 res[i] + msg_len[i], tag_len[i] ); 00443 00444 if( ret != 0 || 00445 memcmp( out, msg, msg_len[i] ) != 0 ) 00446 { 00447 if( verbose != 0 ) 00448 mbedtls_printf( "failed\n" ); 00449 00450 return( 1 ); 00451 } 00452 00453 if( verbose != 0 ) 00454 mbedtls_printf( "passed\n" ); 00455 } 00456 00457 mbedtls_ccm_free( &ctx ); 00458 00459 if( verbose != 0 ) 00460 mbedtls_printf( "\n" ); 00461 00462 return( 0 ); 00463 } 00464 00465 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ 00466 00467 #endif /* MBEDTLS_CCM_C */
Generated on Tue Jul 12 2022 12:21:45 by
