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.
Fork of mbedtls by
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 /* Implementation that should never be optimized out by the compiler */ 00053 static void mbedtls_zeroize( void *v, size_t n ) { 00054 volatile unsigned char *p = v; while( n-- ) *p++ = 0; 00055 } 00056 00057 #define CCM_ENCRYPT 0 00058 #define CCM_DECRYPT 1 00059 00060 /* 00061 * Initialize context 00062 */ 00063 void mbedtls_ccm_init( mbedtls_ccm_context *ctx ) 00064 { 00065 memset( ctx, 0, sizeof( mbedtls_ccm_context ) ); 00066 } 00067 00068 int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, 00069 mbedtls_cipher_id_t cipher, 00070 const unsigned char *key, 00071 unsigned int keybits ) 00072 { 00073 int ret; 00074 const mbedtls_cipher_info_t *cipher_info; 00075 00076 cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); 00077 if( cipher_info == NULL ) 00078 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00079 00080 if( cipher_info->block_size != 16 ) 00081 return( MBEDTLS_ERR_CCM_BAD_INPUT ); 00082 00083 mbedtls_cipher_free( &ctx->cipher_ctx ); 00084 00085 if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx , cipher_info ) ) != 0 ) 00086 return( ret ); 00087 00088 if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx , key, keybits, 00089 MBEDTLS_ENCRYPT ) ) != 0 ) 00090 { 00091 return( ret ); 00092 } 00093 00094 return( 0 ); 00095 } 00096 00097 /* 00098 * Free context 00099 */ 00100 void mbedtls_ccm_free( mbedtls_ccm_context *ctx ) 00101 { 00102 mbedtls_cipher_free( &ctx->cipher_ctx ); 00103 mbedtls_zeroize( ctx, sizeof( mbedtls_ccm_context ) ); 00104 } 00105 00106 /* 00107 * Macros for common operations. 00108 * Results in smaller compiled code than static inline functions. 00109 */ 00110 00111 /* 00112 * Update the CBC-MAC state in y using a block in b 00113 * (Always using b as the source helps the compiler optimise a bit better.) 00114 */ 00115 #define UPDATE_CBC_MAC \ 00116 for( i = 0; i < 16; i++ ) \ 00117 y[i] ^= b[i]; \ 00118 \ 00119 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \ 00120 return( ret ); 00121 00122 /* 00123 * Encrypt or decrypt a partial block with CTR 00124 * Warning: using b for temporary storage! src and dst must not be b! 00125 * This avoids allocating one more 16 bytes buffer while allowing src == dst. 00126 */ 00127 #define CTR_CRYPT( dst, src, len ) \ 00128 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \ 00129 return( ret ); \ 00130 \ 00131 for( i = 0; i < len; i++ ) \ 00132 dst[i] = src[i] ^ b[i]; 00133 00134 /* 00135 * Authenticated encryption or decryption 00136 */ 00137 static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length, 00138 const unsigned char *iv, size_t iv_len, 00139 const unsigned char *add, size_t add_len, 00140 const unsigned char *input, unsigned char *output, 00141 unsigned char *tag, size_t tag_len ) 00142 { 00143 int ret; 00144 unsigned char i; 00145 unsigned char q; 00146 size_t len_left, olen; 00147 unsigned char b[16]; 00148 unsigned char y[16]; 00149 unsigned char ctr[16]; 00150 const unsigned char *src; 00151 unsigned char *dst; 00152 00153 /* 00154 * Check length requirements: SP800-38C A.1 00155 * Additional requirement: a < 2^16 - 2^8 to simplify the code. 00156 * 'length' checked later (when writing it to the first block) 00157 */ 00158 if( tag_len < 4 || 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_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 /* 00318 * Authenticated decryption 00319 */ 00320 int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, 00321 const unsigned char *iv, size_t iv_len, 00322 const unsigned char *add, size_t add_len, 00323 const unsigned char *input, unsigned char *output, 00324 const unsigned char *tag, size_t tag_len ) 00325 { 00326 int ret; 00327 unsigned char check_tag[16]; 00328 unsigned char i; 00329 int diff; 00330 00331 if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length, 00332 iv, iv_len, add, add_len, 00333 input, output, check_tag, tag_len ) ) != 0 ) 00334 { 00335 return( ret ); 00336 } 00337 00338 /* Check tag in "constant-time" */ 00339 for( diff = 0, i = 0; i < tag_len; i++ ) 00340 diff |= tag[i] ^ check_tag[i]; 00341 00342 if( diff != 0 ) 00343 { 00344 mbedtls_zeroize( output, length ); 00345 return( MBEDTLS_ERR_CCM_AUTH_FAILED ); 00346 } 00347 00348 return( 0 ); 00349 } 00350 00351 00352 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) 00353 /* 00354 * Examples 1 to 3 from SP800-38C Appendix C 00355 */ 00356 00357 #define NB_TESTS 3 00358 00359 /* 00360 * The data is the same for all tests, only the used length changes 00361 */ 00362 static const unsigned char key[] = { 00363 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 00364 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f 00365 }; 00366 00367 static const unsigned char iv[] = { 00368 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 00369 0x18, 0x19, 0x1a, 0x1b 00370 }; 00371 00372 static const unsigned char ad[] = { 00373 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 00374 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 00375 0x10, 0x11, 0x12, 0x13 00376 }; 00377 00378 static const unsigned char msg[] = { 00379 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 00380 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 00381 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 00382 }; 00383 00384 static const size_t iv_len [NB_TESTS] = { 7, 8, 12 }; 00385 static const size_t add_len[NB_TESTS] = { 8, 16, 20 }; 00386 static const size_t msg_len[NB_TESTS] = { 4, 16, 24 }; 00387 static const size_t tag_len[NB_TESTS] = { 4, 6, 8 }; 00388 00389 static const unsigned char res[NB_TESTS][32] = { 00390 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, 00391 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, 00392 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, 00393 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, 00394 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 00395 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 00396 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 00397 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } 00398 }; 00399 00400 int mbedtls_ccm_self_test( int verbose ) 00401 { 00402 mbedtls_ccm_context ctx; 00403 unsigned char out[32]; 00404 size_t i; 00405 int ret; 00406 00407 mbedtls_ccm_init( &ctx ); 00408 00409 if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 ) 00410 { 00411 if( verbose != 0 ) 00412 mbedtls_printf( " CCM: setup failed" ); 00413 00414 return( 1 ); 00415 } 00416 00417 for( i = 0; i < NB_TESTS; i++ ) 00418 { 00419 if( verbose != 0 ) 00420 mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 ); 00421 00422 ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i], 00423 iv, iv_len[i], ad, add_len[i], 00424 msg, out, 00425 out + msg_len[i], tag_len[i] ); 00426 00427 if( ret != 0 || 00428 memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 ) 00429 { 00430 if( verbose != 0 ) 00431 mbedtls_printf( "failed\n" ); 00432 00433 return( 1 ); 00434 } 00435 00436 ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i], 00437 iv, iv_len[i], ad, add_len[i], 00438 res[i], out, 00439 res[i] + msg_len[i], tag_len[i] ); 00440 00441 if( ret != 0 || 00442 memcmp( out, msg, msg_len[i] ) != 0 ) 00443 { 00444 if( verbose != 0 ) 00445 mbedtls_printf( "failed\n" ); 00446 00447 return( 1 ); 00448 } 00449 00450 if( verbose != 0 ) 00451 mbedtls_printf( "passed\n" ); 00452 } 00453 00454 mbedtls_ccm_free( &ctx ); 00455 00456 if( verbose != 0 ) 00457 mbedtls_printf( "\n" ); 00458 00459 return( 0 ); 00460 } 00461 00462 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ 00463 00464 #endif /* MBEDTLS_CCM_C */
Generated on Tue Jul 12 2022 12:52:41 by
