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 OmniWheels by
ccm_security.c
00001 /* 00002 * Copyright (c) 2014-2015, 2017, 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 #ifndef CCM_USE_MUTEX 00047 #define arm_ccm_mutex_lock() 00048 #define arm_ccm_mutex_unlock() 00049 #endif 00050 00051 static ccm_globals_t ccm_globals; 00052 00053 /* CCM Library Parameters */ 00054 static uint8_t CCM_L_PARAM = 2; 00055 static uint8_t ccm_sec_level; 00056 static uint8_t CCM_ENCODE_MODE; 00057 static const uint8_t *ccm_key_ptr; 00058 00059 static void ccm_generate_A0(uint8_t *ptr); 00060 static void ccm_auth_generate_B0(uint8_t *ptr, uint16_t len); 00061 static void ccm_auth_calc_Xi(uint8_t X[static 16], uint8_t Blen, const uint8_t B[static Blen]); 00062 static uint8_t ccm_mic_len_calc(uint8_t sec_level); 00063 static void ccm_encode(uint16_t len , uint8_t *ptr); 00064 static int8_t ccm_calc_auth_MIC(const uint8_t *data_ptr, uint16_t data_len, const uint8_t *adata_ptr, uint16_t adata_len); 00065 00066 /** 00067 * \brief A function to init CCM library. 00068 * \param sec_level Used CCM security level (0-7). 00069 * \param ccm_key pointer to 128-key. 00070 * \param mode AES_CCM_ENCRYPT or AES_CCM_DECRYPT 00071 * \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)) 00072 * 00073 * \return Pointer to Global CCM paramameter buffer. 00074 * \return 0 When parameter fail or CCM is Busy. 00075 */ 00076 ccm_globals_t *ccm_sec_init(uint8_t sec_level, const uint8_t *ccm_key, uint8_t mode, uint8_t ccm_l) 00077 { 00078 ccm_globals_t *ret_val = 0; 00079 if ((ccm_l == 2 || ccm_l == 3) && (sec_level < 8)) { 00080 arm_ccm_mutex_lock(); 00081 memset(&ccm_globals, 0, sizeof(ccm_globals_t)); 00082 CCM_ENCODE_MODE = mode; 00083 ccm_sec_level = sec_level; 00084 CCM_L_PARAM = ccm_l; 00085 ccm_key_ptr = ccm_key; 00086 arm_aes_start(ccm_key); 00087 ccm_globals.mic_len = ccm_mic_len_calc(ccm_sec_level); 00088 ccm_globals.mic = 0; 00089 ret_val = &ccm_globals; 00090 } else { 00091 ccm_key_ptr = 0; 00092 } 00093 return ret_val; 00094 } 00095 00096 /** 00097 * \brief A function to init CCM library. 00098 * \param sec_level Used CCM security level (0-7). 00099 * \param ccm_key pointer to 128-key. 00100 * \param mode AES_CCM_ENCRYPT or AES_CCM_DECRYPT 00101 * \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)) 00102 * 00103 * \return 0 CCM process OK and when AES_CCM_DECRYPT mode was selectected also MIC was correct. 00104 * \return -1 Init have not called or data or adata pointers or lengths are zero. 00105 * \return -2 Null pointer given to function 00106 */ 00107 int8_t ccm_process_run(ccm_globals_t *ccm_params) 00108 { 00109 int8_t ret_val = -1; 00110 if (ccm_params == NULL) { 00111 ret_val = -2; 00112 goto END; 00113 00114 } 00115 00116 if (ccm_params->mic_len) { 00117 /* data length >= 0xff00 would require different encoding */ 00118 if (ccm_params->adata_len == 0 || ccm_params->adata_len >= 0xff00 || ccm_params->adata_ptr == NULL) { 00119 goto END; 00120 } else if (ccm_params->mic == NULL) { 00121 ret_val = -2; 00122 goto END; 00123 } 00124 } 00125 00126 if (ccm_params->data_len != 0 && ccm_params->data_ptr == NULL) { 00127 ret_val = -2; 00128 goto END; 00129 } 00130 00131 if (CCM_ENCODE_MODE == AES_CCM_ENCRYPT) { 00132 if (ccm_params->mic_len) { 00133 //Calc 00134 if (ccm_calc_auth_MIC(ccm_params->data_ptr, ccm_params->data_len, ccm_params->adata_ptr, ccm_params->adata_len)) { 00135 goto END; 00136 } 00137 } 00138 if (ccm_params->data_len) { 00139 ccm_encode(ccm_params->data_len, ccm_params->data_ptr); 00140 } 00141 ret_val = 0; 00142 } else { 00143 if (ccm_params->data_len) { 00144 ccm_encode(ccm_params->data_len, ccm_params->data_ptr); 00145 } 00146 if (ccm_params->mic_len) { 00147 if (ccm_calc_auth_MIC(ccm_params->data_ptr, ccm_params->data_len, ccm_params->adata_ptr, ccm_params->adata_len) == 0) { 00148 ret_val = 0; 00149 } 00150 } else { 00151 ret_val = 0; 00152 } 00153 } 00154 00155 END: 00156 ccm_key_ptr = 0; 00157 arm_aes_finish(); 00158 arm_ccm_mutex_unlock(); 00159 return ret_val; 00160 } 00161 00162 00163 /* Counter-mode encryption/decryption 00164 * Ci := E(Key, Ai) ^ Mi 00165 */ 00166 static void ccm_encode(uint16_t len , uint8_t *ptr) 00167 { 00168 if (!ccm_key_ptr || ccm_sec_level < AES_SECURITY_LEVEL_ENC) { 00169 return; 00170 } 00171 00172 uint8_t Ai[16], Si[16]; 00173 00174 //first, generate A0 00175 ccm_generate_A0(Ai); 00176 00177 while (len) { 00178 //increment counter in Ai - 16-bit increment enough; len is 16-bit 00179 if (++Ai[15] == 0) { 00180 ++Ai[14]; 00181 } 00182 00183 // Si := E(Key, Ai) 00184 arm_aes_encrypt(Ai, Si); 00185 00186 // output := Si ^ input 00187 for (int_fast8_t i = 0; i < 16 && len; i++, len--) { 00188 *ptr++ ^= Si[i]; 00189 } 00190 } 00191 } 00192 00193 00194 static int8_t ccm_calc_auth_MIC(const uint8_t *data_ptr, uint16_t data_len, const uint8_t *adata_ptr, uint16_t adata_len) 00195 { 00196 uint8_t Xi[16]; 00197 00198 // As a convenience, treat "data" as "adata", reflecting that "Private 00199 // Payload" is part of "a data" not "m data" for unencrypted modes. 00200 // The distinction matters because there's an "align to block" between 00201 // "a" and "m", which we don't do when it's all in "a". 00202 if (ccm_sec_level < AES_SECURITY_LEVEL_ENC && data_len != 0) { 00203 // This trick only works if data follows adata 00204 if (data_ptr == adata_ptr + adata_len) { 00205 adata_len += data_len; 00206 data_len = 0; 00207 } else { 00208 return -1; 00209 } 00210 } 00211 00212 ccm_auth_generate_B0(Xi, data_len); //Set B0 00213 00214 // Calculate X1: E(key, B0) 00215 // [Could use ccm_auth_calc_Xi - it's formally X1 := E(key, B0 ^ X0), where X0 = 0] 00216 arm_aes_encrypt(Xi, Xi); 00217 00218 //First authentication block has 2-byte length field concatenated 00219 if (adata_len) { 00220 uint8_t B1[16]; 00221 uint_fast8_t t_len = adata_len > 14 ? 14 : adata_len; 00222 00223 B1[0] = adata_len >> 8; 00224 B1[1] = adata_len; 00225 memcpy(&B1[2], adata_ptr, t_len); 00226 00227 ccm_auth_calc_Xi(Xi, 2 + t_len, B1); 00228 adata_ptr += t_len; 00229 adata_len -= t_len; 00230 } 00231 00232 while (adata_len) { 00233 uint_fast8_t t_len = adata_len > 16 ? 16 : adata_len; 00234 00235 ccm_auth_calc_Xi(Xi, t_len, adata_ptr); 00236 adata_ptr += t_len; 00237 adata_len -= t_len; 00238 } 00239 00240 while (data_len) { 00241 uint_fast8_t t_len = data_len > 16 ? 16 : data_len; 00242 00243 ccm_auth_calc_Xi(Xi, t_len, data_ptr); 00244 data_ptr += t_len; 00245 data_len -= t_len; 00246 } 00247 00248 // Authentication tag T is leftmost M octets of X[t+1] 00249 00250 // Encryption block S0 is E(Key, A0) 00251 uint8_t S0[16]; 00252 ccm_generate_A0(S0); 00253 arm_aes_encrypt(S0, S0); 00254 00255 // Encrypted authentication tag U is S0^T (leftmost M octets) 00256 if (CCM_ENCODE_MODE == AES_CCM_ENCRYPT) { 00257 for (uint_fast8_t i = 0; i < ccm_globals.mic_len; i++) { 00258 ccm_globals.mic[i] = Xi[i] ^ S0[i]; 00259 } 00260 } else { 00261 for (uint_fast8_t i = 0; i < ccm_globals.mic_len; i++) 00262 if (ccm_globals.mic[i] != (Xi[i] ^ S0[i])) { 00263 return -1; 00264 } 00265 } 00266 return 0; 00267 } 00268 00269 /** 00270 * \brief This function is used to create A0 which is actual init vector to be used to encrypt full rf message. 00271 * Ai = 8-bit FLAGS | nonce | 16/24-bit counter. 00272 * Si = E[key,Ai] 00273 * 00274 * \return none. 00275 */ 00276 static void ccm_generate_A0(uint8_t *ptr) 00277 { 00278 uint8_t n_len, flags; 00279 flags = CCM_L_PARAM - 1; 00280 n_len = 15 - CCM_L_PARAM; 00281 00282 //FLAGS = L' = L - 1; 00283 *ptr++ = flags; 00284 memcpy(ptr, ccm_globals.exp_nonce, n_len); 00285 ptr += n_len; 00286 memset(ptr, 0, CCM_L_PARAM); 00287 } 00288 00289 /* Calculate X[i+1]: X[i+1] := E(Key, X[i] ^ B[i]) */ 00290 /* Blen is <= 16; this handles zero-padding B when it is < 16 */ 00291 static void ccm_auth_calc_Xi(uint8_t X[static 16], uint8_t Blen, const uint8_t B[static Blen]) 00292 { 00293 for (uint_fast8_t i = 0; i < Blen; i++) { 00294 X[i] ^= B[i]; 00295 } 00296 arm_aes_encrypt(X, X); 00297 } 00298 00299 /* flags = reserved(1) || Adata(1) || M (3) || L (3) 00300 * where M = 0 or (ccm_mic_len-2)/2 00301 * L = CCM_L_PARAM - 1 00302 */ 00303 /* B0 := flags(1)|| Nonce(15-L) || length of message(L) */ 00304 static void ccm_auth_generate_B0(uint8_t *ptr, uint16_t len) 00305 { 00306 uint8_t flags = 0; 00307 uint8_t n_len; 00308 00309 n_len = 15 - CCM_L_PARAM; 00310 00311 if (ccm_globals.mic_len) { 00312 flags = ccm_globals.mic_len - 2; 00313 flags <<= 2; 00314 } 00315 flags |= 0x40; 00316 flags |= (CCM_L_PARAM - 1); 00317 *ptr++ = flags; 00318 memcpy(ptr, ccm_globals.exp_nonce, n_len); 00319 ptr += n_len; 00320 if (CCM_L_PARAM == 3) { 00321 *ptr++ = 0; 00322 } 00323 *ptr++ = len >> 8; 00324 *ptr = len; 00325 } 00326 00327 00328 static uint8_t ccm_mic_len_calc(uint8_t sec_level) 00329 { 00330 switch (sec_level) { 00331 case AES_SECURITY_LEVEL_ENC_MIC32: 00332 case AES_SECURITY_LEVEL_MIC32: 00333 return 4; 00334 case AES_SECURITY_LEVEL_ENC_MIC64: 00335 case AES_SECURITY_LEVEL_MIC64: 00336 return 8; 00337 case AES_SECURITY_LEVEL_ENC_MIC128: 00338 case AES_SECURITY_LEVEL_MIC128: 00339 return 16; 00340 default: 00341 return 0; 00342 00343 } 00344 } 00345
Generated on Fri Jul 22 2022 04:53:46 by
1.7.2
