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 #include "mbedtls/platform_util.h" 00041 00042 #include <string.h> 00043 00044 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) 00045 #if defined(MBEDTLS_PLATFORM_C) 00046 #include "mbedtls/platform.h" 00047 #else 00048 #include <stdio.h> 00049 #define mbedtls_printf printf 00050 #endif /* MBEDTLS_PLATFORM_C */ 00051 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ 00052 00053 #if !defined(MBEDTLS_CCM_ALT) 00054 00055 #define CCM_ENCRYPT 0 00056 #define CCM_DECRYPT 1 00057 00058 /* 00059 * Initialize context 00060 */ 00061 void mbedtls_ccm_init( mbedtls_ccm_context *ctx ) 00062 { 00063 memset( ctx, 0, sizeof( mbedtls_ccm_context ) ); 00064 } 00065 00066 int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, 00067 mbedtls_cipher_id_t cipher, 00068 const unsigned char *key, 00069 unsigned int keybits ) 00070 { 00071 int ret; 00072 const mbedtls_cipher_info_t *cipher_info; 00073 00074 cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); 00075 if( cipher_info == NULL ) 00076 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00077 00078 if( cipher_info->block_size != 16 ) 00079 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00080 00081 mbedtls_cipher_free( &ctx->cipher_ctx ); 00082 00083 if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx , cipher_info ) ) != 0 ) 00084 return( ret ); 00085 00086 if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx , key, keybits, 00087 MBEDTLS_ENCRYPT ) ) != 0 ) 00088 { 00089 return( ret ); 00090 } 00091 00092 return( 0 ); 00093 } 00094 00095 /* 00096 * Free context 00097 */ 00098 void mbedtls_ccm_free( mbedtls_ccm_context *ctx ) 00099 { 00100 mbedtls_cipher_free( &ctx->cipher_ctx ); 00101 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ccm_context ) ); 00102 } 00103 00104 /* 00105 * Macros for common operations. 00106 * Results in smaller compiled code than static inline functions. 00107 */ 00108 00109 /* 00110 * Update the CBC-MAC state in y using a block in b 00111 * (Always using b as the source helps the compiler optimise a bit better.) 00112 */ 00113 #define UPDATE_CBC_MAC \ 00114 for( i = 0; i < 16; i++ ) \ 00115 y[i] ^= b[i]; \ 00116 \ 00117 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \ 00118 return( ret ); 00119 00120 /* 00121 * Encrypt or decrypt a partial block with CTR 00122 * Warning: using b for temporary storage! src and dst must not be b! 00123 * This avoids allocating one more 16 bytes buffer while allowing src == dst. 00124 */ 00125 #define CTR_CRYPT( dst, src, len ) \ 00126 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \ 00127 return( ret ); \ 00128 \ 00129 for( i = 0; i < len; i++ ) \ 00130 dst[i] = src[i] ^ b[i]; 00131 00132 /* 00133 * Authenticated encryption or decryption 00134 */ 00135 static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length, 00136 const unsigned char *iv, size_t iv_len, 00137 const unsigned char *add, size_t add_len, 00138 const unsigned char *input, unsigned char *output, 00139 unsigned char *tag, size_t tag_len ) 00140 { 00141 int ret; 00142 unsigned char i; 00143 unsigned char q; 00144 size_t len_left, olen; 00145 unsigned char b[16]; 00146 unsigned char y[16]; 00147 unsigned char ctr[16]; 00148 const unsigned char *src; 00149 unsigned char *dst; 00150 00151 /* 00152 * Check length requirements: SP800-38C A.1 00153 * Additional requirement: a < 2^16 - 2^8 to simplify the code. 00154 * 'length' checked later (when writing it to the first block) 00155 * 00156 * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4). 00157 */ 00158 if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 ) 00159 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00160 00161 /* Also implies q is within bounds */ 00162 if( iv_len < 7 || iv_len > 13 ) 00163 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00164 00165 if( add_len > 0xFF00 ) 00166 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00167 00168 q = 16 - 1 - (unsigned char) iv_len; 00169 00170 /* 00171 * First block B_0: 00172 * 0 .. 0 flags 00173 * 1 .. iv_len nonce (aka iv) 00174 * iv_len+1 .. 15 length 00175 * 00176 * With flags as (bits): 00177 * 7 0 00178 * 6 add present? 00179 * 5 .. 3 (t - 2) / 2 00180 * 2 .. 0 q - 1 00181 */ 00182 b[0] = 0; 00183 b[0] |= ( add_len > 0 ) << 6; 00184 b[0] |= ( ( tag_len - 2 ) / 2 ) << 3; 00185 b[0] |= q - 1; 00186 00187 memcpy( b + 1, iv, iv_len ); 00188 00189 for( i = 0, len_left = length; i < q; i++, len_left >>= 8 ) 00190 b[15-i] = (unsigned char)( len_left & 0xFF ); 00191 00192 if( len_left > 0 ) 00193 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00194 00195 00196 /* Start CBC-MAC with first block */ 00197 memset( y, 0, 16 ); 00198 UPDATE_CBC_MAC; 00199 00200 /* 00201 * If there is additional data, update CBC-MAC with 00202 * add_len, add, 0 (padding to a block boundary) 00203 */ 00204 if( add_len > 0 ) 00205 { 00206 size_t use_len; 00207 len_left = add_len; 00208 src = add; 00209 00210 memset( b, 0, 16 ); 00211 b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF ); 00212 b[1] = (unsigned char)( ( add_len ) & 0xFF ); 00213 00214 use_len = len_left < 16 - 2 ? len_left : 16 - 2; 00215 memcpy( b + 2, src, use_len ); 00216 len_left -= use_len; 00217 src += use_len; 00218 00219 UPDATE_CBC_MAC; 00220 00221 while( len_left > 0 ) 00222 { 00223 use_len = len_left > 16 ? 16 : len_left; 00224 00225 memset( b, 0, 16 ); 00226 memcpy( b, src, use_len ); 00227 UPDATE_CBC_MAC; 00228 00229 len_left -= use_len; 00230 src += use_len; 00231 } 00232 } 00233 00234 /* 00235 * Prepare counter block for encryption: 00236 * 0 .. 0 flags 00237 * 1 .. iv_len nonce (aka iv) 00238 * iv_len+1 .. 15 counter (initially 1) 00239 * 00240 * With flags as (bits): 00241 * 7 .. 3 0 00242 * 2 .. 0 q - 1 00243 */ 00244 ctr[0] = q - 1; 00245 memcpy( ctr + 1, iv, iv_len ); 00246 memset( ctr + 1 + iv_len, 0, q ); 00247 ctr[15] = 1; 00248 00249 /* 00250 * Authenticate and {en,de}crypt the message. 00251 * 00252 * The only difference between encryption and decryption is 00253 * the respective order of authentication and {en,de}cryption. 00254 */ 00255 len_left = length; 00256 src = input; 00257 dst = output; 00258 00259 while( len_left > 0 ) 00260 { 00261 size_t use_len = len_left > 16 ? 16 : len_left; 00262 00263 if( mode == CCM_ENCRYPT ) 00264 { 00265 memset( b, 0, 16 ); 00266 memcpy( b, src, use_len ); 00267 UPDATE_CBC_MAC; 00268 } 00269 00270 CTR_CRYPT( dst, src, use_len ); 00271 00272 if( mode == CCM_DECRYPT ) 00273 { 00274 memset( b, 0, 16 ); 00275 memcpy( b, dst, use_len ); 00276 UPDATE_CBC_MAC; 00277 } 00278 00279 dst += use_len; 00280 src += use_len; 00281 len_left -= use_len; 00282 00283 /* 00284 * Increment counter. 00285 * No need to check for overflow thanks to the length check above. 00286 */ 00287 for( i = 0; i < q; i++ ) 00288 if( ++ctr[15-i] != 0 ) 00289 break; 00290 } 00291 00292 /* 00293 * Authentication: reset counter and crypt/mask internal tag 00294 */ 00295 for( i = 0; i < q; i++ ) 00296 ctr[15-i] = 0; 00297 00298 CTR_CRYPT( y, y, 16 ); 00299 memcpy( tag, y, tag_len ); 00300 00301 return( 0 ); 00302 } 00303 00304 /* 00305 * Authenticated encryption 00306 */ 00307 int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, 00308 const unsigned char *iv, size_t iv_len, 00309 const unsigned char *add, size_t add_len, 00310 const unsigned char *input, unsigned char *output, 00311 unsigned char *tag, size_t tag_len ) 00312 { 00313 return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len, 00314 add, add_len, input, output, tag, tag_len ) ); 00315 } 00316 00317 int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, 00318 const unsigned char *iv, size_t iv_len, 00319 const unsigned char *add, size_t add_len, 00320 const unsigned char *input, unsigned char *output, 00321 unsigned char *tag, size_t tag_len ) 00322 { 00323 if( tag_len == 0 ) 00324 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00325 00326 return( mbedtls_ccm_star_encrypt_and_tag( ctx, length, iv, iv_len, add, 00327 add_len, input, output, tag, tag_len ) ); 00328 } 00329 00330 /* 00331 * Authenticated decryption 00332 */ 00333 int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, 00334 const unsigned char *iv, size_t iv_len, 00335 const unsigned char *add, size_t add_len, 00336 const unsigned char *input, unsigned char *output, 00337 const unsigned char *tag, size_t tag_len ) 00338 { 00339 int ret; 00340 unsigned char check_tag[16]; 00341 unsigned char i; 00342 int diff; 00343 00344 if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length, 00345 iv, iv_len, add, add_len, 00346 input, output, check_tag, tag_len ) ) != 0 ) 00347 { 00348 return( ret ); 00349 } 00350 00351 /* Check tag in "constant-time" */ 00352 for( diff = 0, i = 0; i < tag_len; i++ ) 00353 diff |= tag[i] ^ check_tag[i]; 00354 00355 if( diff != 0 ) 00356 { 00357 mbedtls_platform_zeroize( output, length ); 00358 return( MBEDTLS_ERR_CCM_AUTH_FAILED ); 00359 } 00360 00361 return( 0 ); 00362 } 00363 00364 int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, 00365 const unsigned char *iv, size_t iv_len, 00366 const unsigned char *add, size_t add_len, 00367 const unsigned char *input, unsigned char *output, 00368 const unsigned char *tag, size_t tag_len ) 00369 { 00370 if( tag_len == 0 ) 00371 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00372 00373 return( mbedtls_ccm_star_auth_decrypt( ctx, length, iv, iv_len, add, 00374 add_len, input, output, tag, tag_len ) ); 00375 } 00376 #endif /* !MBEDTLS_CCM_ALT */ 00377 00378 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) 00379 /* 00380 * Examples 1 to 3 from SP800-38C Appendix C 00381 */ 00382 00383 #define NB_TESTS 3 00384 #define CCM_SELFTEST_PT_MAX_LEN 24 00385 #define CCM_SELFTEST_CT_MAX_LEN 32 00386 /* 00387 * The data is the same for all tests, only the used length changes 00388 */ 00389 static const unsigned char key[] = { 00390 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 00391 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f 00392 }; 00393 00394 static const unsigned char iv[] = { 00395 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 00396 0x18, 0x19, 0x1a, 0x1b 00397 }; 00398 00399 static const unsigned char ad[] = { 00400 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 00401 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 00402 0x10, 0x11, 0x12, 0x13 00403 }; 00404 00405 static const unsigned char msg[CCM_SELFTEST_PT_MAX_LEN] = { 00406 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 00407 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 00408 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 00409 }; 00410 00411 static const size_t iv_len [NB_TESTS] = { 7, 8, 12 }; 00412 static const size_t add_len[NB_TESTS] = { 8, 16, 20 }; 00413 static const size_t msg_len[NB_TESTS] = { 4, 16, 24 }; 00414 static const size_t tag_len[NB_TESTS] = { 4, 6, 8 }; 00415 00416 static const unsigned char res[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = { 00417 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, 00418 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, 00419 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, 00420 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, 00421 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 00422 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 00423 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 00424 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } 00425 }; 00426 00427 int mbedtls_ccm_self_test( int verbose ) 00428 { 00429 mbedtls_ccm_context ctx; 00430 /* 00431 * Some hardware accelerators require the input and output buffers 00432 * would be in RAM, because the flash is not accessible. 00433 * Use buffers on the stack to hold the test vectors data. 00434 */ 00435 unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN]; 00436 unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN]; 00437 size_t i; 00438 int ret; 00439 00440 mbedtls_ccm_init( &ctx ); 00441 00442 if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 ) 00443 { 00444 if( verbose != 0 ) 00445 mbedtls_printf( " CCM: setup failed" ); 00446 00447 return( 1 ); 00448 } 00449 00450 for( i = 0; i < NB_TESTS; i++ ) 00451 { 00452 if( verbose != 0 ) 00453 mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 ); 00454 00455 memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN ); 00456 memset( ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN ); 00457 memcpy( plaintext, msg, msg_len[i] ); 00458 00459 ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i], 00460 iv, iv_len[i], ad, add_len[i], 00461 plaintext, ciphertext, 00462 ciphertext + msg_len[i], tag_len[i] ); 00463 00464 if( ret != 0 || 00465 memcmp( ciphertext, res[i], msg_len[i] + tag_len[i] ) != 0 ) 00466 { 00467 if( verbose != 0 ) 00468 mbedtls_printf( "failed\n" ); 00469 00470 return( 1 ); 00471 } 00472 memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN ); 00473 00474 ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i], 00475 iv, iv_len[i], ad, add_len[i], 00476 ciphertext, plaintext, 00477 ciphertext + msg_len[i], tag_len[i] ); 00478 00479 if( ret != 0 || 00480 memcmp( plaintext, msg, msg_len[i] ) != 0 ) 00481 { 00482 if( verbose != 0 ) 00483 mbedtls_printf( "failed\n" ); 00484 00485 return( 1 ); 00486 } 00487 00488 if( verbose != 0 ) 00489 mbedtls_printf( "passed\n" ); 00490 } 00491 00492 mbedtls_ccm_free( &ctx ); 00493 00494 if( verbose != 0 ) 00495 mbedtls_printf( "\n" ); 00496 00497 return( 0 ); 00498 } 00499 00500 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ 00501 00502 #endif /* MBEDTLS_CCM_C */
Generated on Tue Aug 9 2022 00:37:03 by
1.7.2