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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
ccm_security.c
00001 /* 00002 * Copyright (c) 2014-2015, 2017-2018, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 /** 00019 * 00020 * \file ccm_security.c 00021 * \brief CCM Library API. 00022 * 00023 * \section ccm-api CCM Library API: 00024 * - ccm_sec_init(), A function to init CCM library. 00025 * - ccm_process_run(), A function to run configured CCM process 00026 * 00027 * \section ccm-inctuction CCM process sequency: 00028 * 1. Init CCM library by , ccm key, ccm_sec_init() 00029 * - security level 00030 * - 128-bit ccm key 00031 * - mode: AES_CCM_ENCRYPT or AES_CCM_DECRYPT 00032 * - CCM L parameter: 2 or 3 depends nonce legth (802.15.4 use 2 and TLS security use 3) 00033 * 2. Define ADATA pointer and length, if returned global structure mic_len field is > 0 00034 * 3. Set Data pointer and length 00035 * 4. Do configured CCM process ccm_process_run() 00036 * 5. Check Return value: 00037 * -If 0 Process ok 00038 * -< 0 MIC fail or parameter fail 00039 */ 00040 00041 #include <stdint.h> 00042 #include <string.h> 00043 #include "ccmLIB.h" 00044 #include "platform/arm_hal_aes.h" 00045 00046 static void ccm_generate_A0(uint8_t *ptr, ccm_globals_t *ccm_pramters); 00047 static void ccm_auth_generate_B0(uint8_t *ptr, ccm_globals_t *ccm_params); 00048 static void ccm_auth_calc_Xi(void *aes_context, uint8_t X[static 16], uint8_t Blen, const uint8_t B[static Blen]); 00049 static uint8_t ccm_mic_len_calc(uint8_t sec_level); 00050 static void ccm_encode(ccm_globals_t *ccm_params); 00051 static int8_t ccm_calc_auth_MIC(ccm_globals_t *ccm_params); 00052 00053 /** 00054 * \brief A function to init CCM library. 00055 * \param sec_level Used CCM security level (0-7). 00056 * \param ccm_key pointer to 128-key. 00057 * \param mode AES_CCM_ENCRYPT or AES_CCM_DECRYPT 00058 * \param ccm_l cuold be 2 or 3. 2 when NONCE length is 13 and 3 when length is 12. (NONCE Len= (15-ccm_l)) 00059 * 00060 * \return Pointer to Global CCM paramameter buffer. 00061 * \return 0 When parameter fail or CCM is Busy. 00062 */ 00063 bool ccm_sec_init(ccm_globals_t *ccm_context, uint8_t sec_level, const uint8_t *ccm_key, uint8_t mode, uint8_t ccm_l) 00064 { 00065 memset(ccm_context, 0, sizeof(ccm_globals_t)); 00066 00067 if ((ccm_l == 2 || ccm_l == 3) && (sec_level < 8)) { 00068 void *aes_context = arm_aes_start(ccm_key); 00069 if (!aes_context) { 00070 return false; 00071 } 00072 ccm_context->aes_context = aes_context; 00073 ccm_context->ccm_encode_mode = mode; 00074 ccm_context->ccm_sec_level = sec_level; 00075 ccm_context->ccm_l_param = ccm_l; 00076 ccm_context->key_ptr = ccm_key; 00077 ccm_context->mic_len = ccm_mic_len_calc(sec_level); 00078 return true; 00079 } 00080 return false; 00081 } 00082 00083 /** 00084 * \brief A function to init CCM library. 00085 * \param sec_level Used CCM security level (0-7). 00086 * \param ccm_key pointer to 128-key. 00087 * \param mode AES_CCM_ENCRYPT or AES_CCM_DECRYPT 00088 * \param ccm_l cuold be 2 or 3. 2 when NONCE length is 13 and 3 when length is 12. (NONCE Len= (15-ccm_l)) 00089 * 00090 * \return 0 CCM process OK and when AES_CCM_DECRYPT mode was selectected also MIC was correct. 00091 * \return -1 Init have not called or data or adata pointers or lengths are zero. 00092 * \return -2 Null pointer given to function 00093 */ 00094 int8_t ccm_process_run(ccm_globals_t *ccm_params) 00095 { 00096 int8_t ret_val = -1; 00097 if (ccm_params == NULL) { 00098 ret_val = -2; 00099 goto END; 00100 00101 } 00102 00103 if (ccm_params->mic_len) { 00104 /* data length >= 0xff00 would require different encoding */ 00105 if (ccm_params->adata_len == 0 || ccm_params->adata_len >= 0xff00 || ccm_params->adata_ptr == NULL) { 00106 goto END; 00107 } else if (ccm_params->mic == NULL) { 00108 ret_val = -2; 00109 goto END; 00110 } 00111 } 00112 00113 if (ccm_params->data_len != 0 && ccm_params->data_ptr == NULL) { 00114 ret_val = -2; 00115 goto END; 00116 } 00117 00118 if (ccm_params->ccm_encode_mode == AES_CCM_ENCRYPT) { 00119 if (ccm_params->mic_len) { 00120 //Calc 00121 if (ccm_calc_auth_MIC(ccm_params)) { 00122 goto END; 00123 } 00124 } 00125 if (ccm_params->data_len) { 00126 ccm_encode(ccm_params); 00127 } 00128 ret_val = 0; 00129 } else { 00130 if (ccm_params->data_len) { 00131 ccm_encode(ccm_params); 00132 } 00133 if (ccm_params->mic_len) { 00134 if (ccm_calc_auth_MIC(ccm_params) == 0) { 00135 ret_val = 0; 00136 } 00137 } else { 00138 ret_val = 0; 00139 } 00140 } 00141 00142 END: 00143 ccm_free(ccm_params); 00144 return ret_val; 00145 } 00146 00147 void ccm_free(ccm_globals_t *ccm_params) 00148 { 00149 if (ccm_params && ccm_params->aes_context) { 00150 arm_aes_finish(ccm_params->aes_context); 00151 } 00152 } 00153 00154 00155 /* Counter-mode encryption/decryption 00156 * Ci := E(Key, Ai) ^ Mi 00157 */ 00158 static void ccm_encode(ccm_globals_t *ccm_params) 00159 { 00160 if (!ccm_params->key_ptr || ccm_params->ccm_sec_level < AES_SECURITY_LEVEL_ENC) { 00161 return; 00162 } 00163 uint16_t len = ccm_params->data_len; 00164 uint8_t *ptr = ccm_params->data_ptr; 00165 uint8_t Ai[16], Si[16]; 00166 00167 //first, generate A0 00168 ccm_generate_A0(Ai, ccm_params); 00169 00170 while (len) { 00171 //increment counter in Ai - 16-bit increment enough; len is 16-bit 00172 if (++Ai[15] == 0) { 00173 ++Ai[14]; 00174 } 00175 00176 // Si := E(Key, Ai) 00177 arm_aes_encrypt(ccm_params->aes_context, Ai, Si); 00178 00179 // output := Si ^ input 00180 for (int_fast8_t i = 0; i < 16 && len; i++, len--) { 00181 *ptr++ ^= Si[i]; 00182 } 00183 } 00184 } 00185 00186 00187 static int8_t ccm_calc_auth_MIC(ccm_globals_t *ccm_params) 00188 { 00189 const uint8_t *data_ptr = ccm_params->data_ptr; 00190 uint16_t data_len = ccm_params->data_len; 00191 const uint8_t *adata_ptr = ccm_params->adata_ptr; 00192 uint16_t adata_len = ccm_params->adata_len; 00193 uint8_t Xi[16]; 00194 00195 // As a convenience, treat "data" as "adata", reflecting that "Private 00196 // Payload" is part of "a data" not "m data" for unencrypted modes. 00197 // The distinction matters because there's an "align to block" between 00198 // "a" and "m", which we don't do when it's all in "a". 00199 if (ccm_params->ccm_sec_level < AES_SECURITY_LEVEL_ENC && data_len != 0) { 00200 // This trick only works if data follows adata 00201 if (data_ptr == adata_ptr + adata_len) { 00202 adata_len += data_len; 00203 data_len = 0; 00204 } else { 00205 return -1; 00206 } 00207 } 00208 00209 ccm_auth_generate_B0(Xi, ccm_params); //Set B0 00210 00211 // Calculate X1: E(key, B0) 00212 // [Could use ccm_auth_calc_Xi - it's formally X1 := E(key, B0 ^ X0), where X0 = 0] 00213 arm_aes_encrypt(ccm_params->aes_context, Xi, Xi); 00214 00215 //First authentication block has 2-byte length field concatenated 00216 if (adata_len) { 00217 uint8_t B1[16]; 00218 uint_fast8_t t_len = adata_len > 14 ? 14 : adata_len; 00219 00220 B1[0] = adata_len >> 8; 00221 B1[1] = adata_len; 00222 memcpy(&B1[2], adata_ptr, t_len); 00223 00224 ccm_auth_calc_Xi(ccm_params->aes_context, Xi, 2 + t_len, B1); 00225 adata_ptr += t_len; 00226 adata_len -= t_len; 00227 } 00228 00229 while (adata_len) { 00230 uint_fast8_t t_len = adata_len > 16 ? 16 : adata_len; 00231 00232 ccm_auth_calc_Xi(ccm_params->aes_context, Xi, t_len, adata_ptr); 00233 adata_ptr += t_len; 00234 adata_len -= t_len; 00235 } 00236 00237 while (data_len) { 00238 uint_fast8_t t_len = data_len > 16 ? 16 : data_len; 00239 00240 ccm_auth_calc_Xi(ccm_params->aes_context, Xi, t_len, data_ptr); 00241 data_ptr += t_len; 00242 data_len -= t_len; 00243 } 00244 00245 // Authentication tag T is leftmost M octets of X[t+1] 00246 00247 // Encryption block S0 is E(Key, A0) 00248 uint8_t S0[16]; 00249 ccm_generate_A0(S0, ccm_params); 00250 arm_aes_encrypt(ccm_params->aes_context, S0, S0); 00251 00252 // Encrypted authentication tag U is S0^T (leftmost M octets) 00253 if (ccm_params->ccm_encode_mode == AES_CCM_ENCRYPT) { 00254 for (uint_fast8_t i = 0; i < ccm_params->mic_len; i++) { 00255 ccm_params->mic[i] = Xi[i] ^ S0[i]; 00256 } 00257 } else { 00258 for (uint_fast8_t i = 0; i < ccm_params->mic_len; i++) 00259 if (ccm_params->mic[i] != (Xi[i] ^ S0[i])) { 00260 return -1; 00261 } 00262 } 00263 return 0; 00264 } 00265 00266 /** 00267 * \brief This function is used to create A0 which is actual init vector to be used to encrypt full rf message. 00268 * Ai = 8-bit FLAGS | nonce | 16/24-bit counter. 00269 * Si = E[key,Ai] 00270 * 00271 * \return none. 00272 */ 00273 static void ccm_generate_A0(uint8_t *ptr, ccm_globals_t *ccm_pramters) 00274 { 00275 uint8_t n_len, flags; 00276 flags = ccm_pramters->ccm_l_param - 1; 00277 n_len = 15 - ccm_pramters->ccm_l_param; 00278 00279 //FLAGS = L' = L - 1; 00280 *ptr++ = flags; 00281 memcpy(ptr, ccm_pramters->exp_nonce, n_len); 00282 ptr += n_len; 00283 memset(ptr, 0, ccm_pramters->ccm_l_param); 00284 } 00285 00286 /* Calculate X[i+1]: X[i+1] := E(Key, X[i] ^ B[i]) */ 00287 /* Blen is <= 16; this handles zero-padding B when it is < 16 */ 00288 static void ccm_auth_calc_Xi(void *aes_context, uint8_t X[static 16], uint8_t Blen, const uint8_t B[static Blen]) 00289 { 00290 for (uint_fast8_t i = 0; i < Blen; i++) { 00291 X[i] ^= B[i]; 00292 } 00293 arm_aes_encrypt(aes_context, X, X); 00294 } 00295 00296 /* flags = reserved(1) || Adata(1) || M (3) || L (3) 00297 * where M = 0 or (ccm_mic_len-2)/2 00298 * L = CCM_L_PARAM - 1 00299 */ 00300 /* B0 := flags(1)|| Nonce(15-L) || length of message(L) */ 00301 static void ccm_auth_generate_B0(uint8_t *ptr, ccm_globals_t *ccm_params) 00302 { 00303 uint8_t flags = 0; 00304 uint8_t n_len; 00305 00306 n_len = 15 - ccm_params->ccm_l_param; 00307 00308 if (ccm_params->mic_len) { 00309 flags = ccm_params->mic_len - 2; 00310 flags <<= 2; 00311 } 00312 flags |= 0x40; 00313 flags |= (ccm_params->ccm_l_param - 1); 00314 *ptr++ = flags; 00315 memcpy(ptr, ccm_params->exp_nonce, n_len); 00316 ptr += n_len; 00317 if (ccm_params->ccm_l_param == 3) { 00318 *ptr++ = 0; 00319 } 00320 *ptr++ = ccm_params->data_len >> 8; 00321 *ptr = ccm_params->data_len; 00322 } 00323 00324 00325 static uint8_t ccm_mic_len_calc(uint8_t sec_level) 00326 { 00327 switch (sec_level) { 00328 case AES_SECURITY_LEVEL_ENC_MIC32: 00329 case AES_SECURITY_LEVEL_MIC32: 00330 return 4; 00331 case AES_SECURITY_LEVEL_ENC_MIC64: 00332 case AES_SECURITY_LEVEL_MIC64: 00333 return 8; 00334 case AES_SECURITY_LEVEL_ENC_MIC128: 00335 case AES_SECURITY_LEVEL_MIC128: 00336 return 16; 00337 default: 00338 return 0; 00339 00340 } 00341 } 00342
Generated on Tue Jul 12 2022 13:54:05 by
