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 if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 ) 00157 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00158 00159 /* Also implies q is within bounds */ 00160 if( iv_len < 7 || iv_len > 13 ) 00161 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00162 00163 if( add_len > 0xFF00 ) 00164 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00165 00166 q = 16 - 1 - (unsigned char) iv_len; 00167 00168 /* 00169 * First block B_0: 00170 * 0 .. 0 flags 00171 * 1 .. iv_len nonce (aka iv) 00172 * iv_len+1 .. 15 length 00173 * 00174 * With flags as (bits): 00175 * 7 0 00176 * 6 add present? 00177 * 5 .. 3 (t - 2) / 2 00178 * 2 .. 0 q - 1 00179 */ 00180 b[0] = 0; 00181 b[0] |= ( add_len > 0 ) << 6; 00182 b[0] |= ( ( tag_len - 2 ) / 2 ) << 3; 00183 b[0] |= q - 1; 00184 00185 memcpy( b + 1, iv, iv_len ); 00186 00187 for( i = 0, len_left = length; i < q; i++, len_left >>= 8 ) 00188 b[15-i] = (unsigned char)( len_left & 0xFF ); 00189 00190 if( len_left > 0 ) 00191 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00192 00193 00194 /* Start CBC-MAC with first block */ 00195 memset( y, 0, 16 ); 00196 UPDATE_CBC_MAC; 00197 00198 /* 00199 * If there is additional data, update CBC-MAC with 00200 * add_len, add, 0 (padding to a block boundary) 00201 */ 00202 if( add_len > 0 ) 00203 { 00204 size_t use_len; 00205 len_left = add_len; 00206 src = add; 00207 00208 memset( b, 0, 16 ); 00209 b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF ); 00210 b[1] = (unsigned char)( ( add_len ) & 0xFF ); 00211 00212 use_len = len_left < 16 - 2 ? len_left : 16 - 2; 00213 memcpy( b + 2, src, use_len ); 00214 len_left -= use_len; 00215 src += use_len; 00216 00217 UPDATE_CBC_MAC; 00218 00219 while( len_left > 0 ) 00220 { 00221 use_len = len_left > 16 ? 16 : len_left; 00222 00223 memset( b, 0, 16 ); 00224 memcpy( b, src, use_len ); 00225 UPDATE_CBC_MAC; 00226 00227 len_left -= use_len; 00228 src += use_len; 00229 } 00230 } 00231 00232 /* 00233 * Prepare counter block for encryption: 00234 * 0 .. 0 flags 00235 * 1 .. iv_len nonce (aka iv) 00236 * iv_len+1 .. 15 counter (initially 1) 00237 * 00238 * With flags as (bits): 00239 * 7 .. 3 0 00240 * 2 .. 0 q - 1 00241 */ 00242 ctr[0] = q - 1; 00243 memcpy( ctr + 1, iv, iv_len ); 00244 memset( ctr + 1 + iv_len, 0, q ); 00245 ctr[15] = 1; 00246 00247 /* 00248 * Authenticate and {en,de}crypt the message. 00249 * 00250 * The only difference between encryption and decryption is 00251 * the respective order of authentication and {en,de}cryption. 00252 */ 00253 len_left = length; 00254 src = input; 00255 dst = output; 00256 00257 while( len_left > 0 ) 00258 { 00259 size_t use_len = len_left > 16 ? 16 : len_left; 00260 00261 if( mode == CCM_ENCRYPT ) 00262 { 00263 memset( b, 0, 16 ); 00264 memcpy( b, src, use_len ); 00265 UPDATE_CBC_MAC; 00266 } 00267 00268 CTR_CRYPT( dst, src, use_len ); 00269 00270 if( mode == CCM_DECRYPT ) 00271 { 00272 memset( b, 0, 16 ); 00273 memcpy( b, dst, use_len ); 00274 UPDATE_CBC_MAC; 00275 } 00276 00277 dst += use_len; 00278 src += use_len; 00279 len_left -= use_len; 00280 00281 /* 00282 * Increment counter. 00283 * No need to check for overflow thanks to the length check above. 00284 */ 00285 for( i = 0; i < q; i++ ) 00286 if( ++ctr[15-i] != 0 ) 00287 break; 00288 } 00289 00290 /* 00291 * Authentication: reset counter and crypt/mask internal tag 00292 */ 00293 for( i = 0; i < q; i++ ) 00294 ctr[15-i] = 0; 00295 00296 CTR_CRYPT( y, y, 16 ); 00297 memcpy( tag, y, tag_len ); 00298 00299 return( 0 ); 00300 } 00301 00302 /* 00303 * Authenticated encryption 00304 */ 00305 int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, 00306 const unsigned char *iv, size_t iv_len, 00307 const unsigned char *add, size_t add_len, 00308 const unsigned char *input, unsigned char *output, 00309 unsigned char *tag, size_t tag_len ) 00310 { 00311 return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len, 00312 add, add_len, input, output, tag, tag_len ) ); 00313 } 00314 00315 /* 00316 * Authenticated decryption 00317 */ 00318 int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, 00319 const unsigned char *iv, size_t iv_len, 00320 const unsigned char *add, size_t add_len, 00321 const unsigned char *input, unsigned char *output, 00322 const unsigned char *tag, size_t tag_len ) 00323 { 00324 int ret; 00325 unsigned char check_tag[16]; 00326 unsigned char i; 00327 int diff; 00328 00329 if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length, 00330 iv, iv_len, add, add_len, 00331 input, output, check_tag, tag_len ) ) != 0 ) 00332 { 00333 return( ret ); 00334 } 00335 00336 /* Check tag in "constant-time" */ 00337 for( diff = 0, i = 0; i < tag_len; i++ ) 00338 diff |= tag[i] ^ check_tag[i]; 00339 00340 if( diff != 0 ) 00341 { 00342 mbedtls_platform_zeroize( output, length ); 00343 return( MBEDTLS_ERR_CCM_AUTH_FAILED ); 00344 } 00345 00346 return( 0 ); 00347 } 00348 00349 #endif /* !MBEDTLS_CCM_ALT */ 00350 00351 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) 00352 /* 00353 * Examples 1 to 3 from SP800-38C Appendix C 00354 */ 00355 00356 #define NB_TESTS 3 00357 00358 /* 00359 * The data is the same for all tests, only the used length changes 00360 */ 00361 static const unsigned char key[] = { 00362 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 00363 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f 00364 }; 00365 00366 static const unsigned char iv[] = { 00367 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 00368 0x18, 0x19, 0x1a, 0x1b 00369 }; 00370 00371 static const unsigned char ad[] = { 00372 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 00373 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 00374 0x10, 0x11, 0x12, 0x13 00375 }; 00376 00377 static const unsigned char msg[] = { 00378 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 00379 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 00380 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 00381 }; 00382 00383 static const size_t iv_len [NB_TESTS] = { 7, 8, 12 }; 00384 static const size_t add_len[NB_TESTS] = { 8, 16, 20 }; 00385 static const size_t msg_len[NB_TESTS] = { 4, 16, 24 }; 00386 static const size_t tag_len[NB_TESTS] = { 4, 6, 8 }; 00387 00388 static const unsigned char res[NB_TESTS][32] = { 00389 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, 00390 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, 00391 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, 00392 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, 00393 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 00394 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 00395 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 00396 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } 00397 }; 00398 00399 int mbedtls_ccm_self_test( int verbose ) 00400 { 00401 mbedtls_ccm_context ctx; 00402 unsigned char out[32]; 00403 size_t i; 00404 int ret; 00405 00406 mbedtls_ccm_init( &ctx ); 00407 00408 if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 ) 00409 { 00410 if( verbose != 0 ) 00411 mbedtls_printf( " CCM: setup failed" ); 00412 00413 return( 1 ); 00414 } 00415 00416 for( i = 0; i < NB_TESTS; i++ ) 00417 { 00418 if( verbose != 0 ) 00419 mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 ); 00420 00421 ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i], 00422 iv, iv_len[i], ad, add_len[i], 00423 msg, out, 00424 out + msg_len[i], tag_len[i] ); 00425 00426 if( ret != 0 || 00427 memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 ) 00428 { 00429 if( verbose != 0 ) 00430 mbedtls_printf( "failed\n" ); 00431 00432 return( 1 ); 00433 } 00434 00435 ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i], 00436 iv, iv_len[i], ad, add_len[i], 00437 res[i], out, 00438 res[i] + msg_len[i], tag_len[i] ); 00439 00440 if( ret != 0 || 00441 memcmp( out, msg, msg_len[i] ) != 0 ) 00442 { 00443 if( verbose != 0 ) 00444 mbedtls_printf( "failed\n" ); 00445 00446 return( 1 ); 00447 } 00448 00449 if( verbose != 0 ) 00450 mbedtls_printf( "passed\n" ); 00451 } 00452 00453 mbedtls_ccm_free( &ctx ); 00454 00455 if( verbose != 0 ) 00456 mbedtls_printf( "\n" ); 00457 00458 return( 0 ); 00459 } 00460 00461 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ 00462 00463 #endif /* MBEDTLS_CCM_C */
Generated on Tue Jul 12 2022 12:43:38 by
