Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
cipher_mode_ccm.c
Go to the documentation of this file.
00001 /** 00002 * @file cipher_mode_ccm.c 00003 * @brief Cipher Block Chaining-Message Authentication Code (CCM) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneCrypto Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @section Description 00026 * 00027 * CCM mode (Cipher Block Chaining-Message Authentication Code) is a mode of 00028 * operation for cryptographic block ciphers. It is an authenticated encryption 00029 * algorithm designed to provide both authentication and confidentiality. CCM 00030 * mode is only defined for block ciphers with a block length of 128 bits. 00031 * Refer to SP 800-38D for more details 00032 * 00033 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00034 * @version 1.7.6 00035 **/ 00036 00037 //Switch to the appropriate trace level 00038 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL 00039 00040 //Dependencies 00041 #include <string.h> 00042 #include "crypto.h" 00043 #include "cipher_mode_ccm.h" 00044 #include "debug.h" 00045 00046 //Check crypto library configuration 00047 #if (CCM_SUPPORT == ENABLED) 00048 00049 00050 /** 00051 * @brief Authenticated encryption using CCM 00052 * @param[in] cipher Cipher algorithm 00053 * @param[in] context Cipher algorithm context 00054 * @param[in] n Nonce 00055 * @param[in] nLen Length of the nonce 00056 * @param[in] a Additional authenticated data 00057 * @param[in] aLen Length of the additional data 00058 * @param[in] p Plaintext to be encrypted 00059 * @param[out] c Ciphertext resulting from the encryption 00060 * @param[in] length Total number of data bytes to be encrypted 00061 * @param[out] t MAC resulting from the encryption process 00062 * @param[in] tLen Length of the MAC 00063 * @return Error code 00064 **/ 00065 00066 error_t ccmEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *n, size_t nLen, 00067 const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen) 00068 { 00069 size_t m; 00070 size_t q; 00071 size_t qLen; 00072 uint8_t b[16]; 00073 uint8_t y[16]; 00074 uint8_t s[16]; 00075 00076 //Check parameters 00077 if(cipher == NULL || context == NULL) 00078 return ERROR_INVALID_PARAMETER; 00079 00080 //CCM supports only symmetric block ciphers whose block size is 128 bits 00081 if(cipher->type != CIPHER_ALGO_TYPE_BLOCK || cipher->blockSize != 16) 00082 return ERROR_INVALID_PARAMETER; 00083 00084 //Check the length of the nonce 00085 if(nLen < 7 || nLen > 13) 00086 return ERROR_INVALID_LENGTH; 00087 //Check the length of the MAC 00088 if(tLen < 4 || tLen > 16 || tLen % 2) 00089 return ERROR_INVALID_LENGTH; 00090 00091 //Q is the bit string representation of the octet length of P 00092 q = length; 00093 //Compute the octet length of Q 00094 qLen = 15 - nLen; 00095 00096 //Format the leading octet of the first block 00097 b[0] = (aLen > 0) ? 0x40 : 0x00; 00098 //Encode the octet length of T 00099 b[0] |= ((tLen - 2) / 2) << 3; 00100 //Encode the octet length of Q 00101 b[0] |= qLen - 1; 00102 00103 //Copy the nonce 00104 memcpy(b + 1, n, nLen); 00105 00106 //Encode the length field Q 00107 for(m = 0; m < qLen; m++, q >>= 8) 00108 b[15 - m] = q & 0xFF; 00109 00110 //Invalid length? 00111 if(q != 0) 00112 return ERROR_INVALID_LENGTH; 00113 00114 //Set Y(0) = CIPH(B(0)) 00115 cipher->encryptBlock(context, b, y); 00116 00117 //Any additional data? 00118 if(aLen > 0) 00119 { 00120 //Format the associated data 00121 memset(b, 0, 16); 00122 00123 //Check the length of the associated data string 00124 if(aLen < 0xFF00) 00125 { 00126 //The length is encoded as 2 octets 00127 STORE16BE(aLen, b); 00128 //Number of bytes to copy 00129 m = MIN(aLen, 16 - 2); 00130 //Concatenate the associated data A 00131 memcpy(b + 2, a, m); 00132 } 00133 else 00134 { 00135 //The length is encoded as 6 octets 00136 b[0] = 0xFF; 00137 b[1] = 0xFE; 00138 //MSB is stored first 00139 STORE32BE(aLen, b + 2); 00140 //Number of bytes to copy 00141 m = MIN(aLen, 16 - 6); 00142 //Concatenate the associated data A 00143 memcpy(b + 6, a, m); 00144 } 00145 00146 //XOR B(1) with Y(0) 00147 ccmXorBlock(y, b, y, 16); 00148 //Compute Y(1) = CIPH(B(1) ^ Y(0)) 00149 cipher->encryptBlock(context, y, y); 00150 00151 //Number of remaining data bytes 00152 aLen -= m; 00153 a += m; 00154 00155 //Process the remaining data bytes 00156 while(aLen > 0) 00157 { 00158 //Associated data are processed in a block-by-block fashion 00159 m = MIN(aLen, 16); 00160 00161 //XOR B(i) with Y(i-1) 00162 ccmXorBlock(y, a, y, m); 00163 //Compute Y(i) = CIPH(B(i) ^ Y(i-1)) 00164 cipher->encryptBlock(context, y, y); 00165 00166 //Next block 00167 aLen -= m; 00168 a += m; 00169 } 00170 } 00171 00172 //Format CTR(0) 00173 b[0] = (uint8_t) (qLen - 1); 00174 //Copy the nonce 00175 memcpy(b + 1, n, nLen); 00176 //Initialize counter value 00177 memset(b + 1 + nLen, 0, qLen); 00178 00179 //Compute S(0) = CIPH(CTR(0)) 00180 cipher->encryptBlock(context, b, s); 00181 //Save MSB(S(0)) 00182 memcpy(t, s, tLen); 00183 00184 //Encrypt plaintext 00185 while(length > 0) 00186 { 00187 //The encryption operates in a block-by-block fashion 00188 m = MIN(length, 16); 00189 00190 //XOR B(i) with Y(i-1) 00191 ccmXorBlock(y, p, y, m); 00192 //Compute Y(i) = CIPH(B(i) ^ Y(i-1)) 00193 cipher->encryptBlock(context, y, y); 00194 00195 //Increment counter 00196 ccmIncCounter(b, qLen); 00197 //Compute S(i) = CIPH(CTR(i)) 00198 cipher->encryptBlock(context, b, s); 00199 //Compute C(i) = B(i) XOR S(i) 00200 ccmXorBlock(c, p, s, m); 00201 00202 //Next block 00203 length -= m; 00204 p += m; 00205 c += m; 00206 } 00207 00208 //Compute MAC 00209 ccmXorBlock(t, t, y, tLen); 00210 00211 //Successful encryption 00212 return NO_ERROR; 00213 } 00214 00215 00216 /** 00217 * @brief Authenticated decryption using CCM 00218 * @param[in] cipher Cipher algorithm 00219 * @param[in] context Cipher algorithm context 00220 * @param[in] n Nonce 00221 * @param[in] nLen Length of the nonce 00222 * @param[in] a Additional authenticated data 00223 * @param[in] aLen Length of the additional data 00224 * @param[in] c Ciphertext to be decrypted 00225 * @param[out] p Plaintext resulting from the decryption 00226 * @param[in] length Total number of data bytes to be decrypted 00227 * @param[in] t MAC to be verified 00228 * @param[in] tLen Length of the MAC 00229 * @return Error code 00230 **/ 00231 00232 error_t ccmDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *n, size_t nLen, 00233 const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen) 00234 { 00235 size_t m; 00236 size_t q; 00237 size_t qLen; 00238 uint8_t b[16]; 00239 uint8_t y[16]; 00240 uint8_t r[16]; 00241 uint8_t s[16]; 00242 00243 //Check parameters 00244 if(cipher == NULL || context == NULL) 00245 return ERROR_INVALID_PARAMETER; 00246 00247 //CCM supports only symmetric block ciphers whose block size is 128 bits 00248 if(cipher->type != CIPHER_ALGO_TYPE_BLOCK || cipher->blockSize != 16) 00249 return ERROR_INVALID_PARAMETER; 00250 00251 //Check the length of the nonce 00252 if(nLen < 7 || nLen > 13) 00253 return ERROR_INVALID_LENGTH; 00254 //Check the length of the MAC 00255 if(tLen < 4 || tLen > 16 || tLen % 2) 00256 return ERROR_INVALID_LENGTH; 00257 00258 //Q is the bit string representation of the octet length of C 00259 q = length; 00260 //Compute the octet length of Q 00261 qLen = 15 - nLen; 00262 00263 //Format the leading octet of the first block 00264 b[0] = (aLen > 0) ? 0x40 : 0x00; 00265 //Encode the octet length of T 00266 b[0] |= ((tLen - 2) / 2) << 3; 00267 //Encode the octet length of Q 00268 b[0] |= qLen - 1; 00269 00270 //Copy the nonce 00271 memcpy(b + 1, n, nLen); 00272 00273 //Encode the length field Q 00274 for(m = 0; m < qLen; m++, q >>= 8) 00275 b[15 - m] = q & 0xFF; 00276 00277 //Invalid length? 00278 if(q != 0) 00279 return ERROR_INVALID_LENGTH; 00280 00281 //Set Y(0) = CIPH(B(0)) 00282 cipher->encryptBlock(context, b, y); 00283 00284 //Any additional data? 00285 if(aLen > 0) 00286 { 00287 //Format the associated data 00288 memset(b, 0, 16); 00289 00290 //Check the length of the associated data string 00291 if(aLen < 0xFF00) 00292 { 00293 //The length is encoded as 2 octets 00294 STORE16BE(aLen, b); 00295 //Number of bytes to copy 00296 m = MIN(aLen, 16 - 2); 00297 //Concatenate the associated data A 00298 memcpy(b + 2, a, m); 00299 } 00300 else 00301 { 00302 //The length is encoded as 6 octets 00303 b[0] = 0xFF; 00304 b[1] = 0xFE; 00305 //MSB is stored first 00306 STORE32BE(aLen, b + 2); 00307 //Number of bytes to copy 00308 m = MIN(aLen, 16 - 6); 00309 //Concatenate the associated data A 00310 memcpy(b + 6, a, m); 00311 } 00312 00313 //XOR B(1) with Y(0) 00314 ccmXorBlock(y, b, y, 16); 00315 //Compute Y(1) = CIPH(B(1) ^ Y(0)) 00316 cipher->encryptBlock(context, y, y); 00317 00318 //Number of remaining data bytes 00319 aLen -= m; 00320 a += m; 00321 00322 //Process the remaining data bytes 00323 while(aLen > 0) 00324 { 00325 //Associated data are processed in a block-by-block fashion 00326 m = MIN(aLen, 16); 00327 00328 //XOR B(i) with Y(i-1) 00329 ccmXorBlock(y, a, y, m); 00330 //Compute Y(i) = CIPH(B(i) ^ Y(i-1)) 00331 cipher->encryptBlock(context, y, y); 00332 00333 //Next block 00334 aLen -= m; 00335 a += m; 00336 } 00337 } 00338 00339 //Format CTR(0) 00340 b[0] = (uint8_t) (qLen - 1); 00341 //Copy the nonce 00342 memcpy(b + 1, n, nLen); 00343 //Initialize counter value 00344 memset(b + 1 + nLen, 0, qLen); 00345 00346 //Compute S(0) = CIPH(CTR(0)) 00347 cipher->encryptBlock(context, b, s); 00348 //Save MSB(S(0)) 00349 memcpy(r, s, tLen); 00350 00351 //Decrypt ciphertext 00352 while(length > 0) 00353 { 00354 //The decryption operates in a block-by-block fashion 00355 m = MIN(length, 16); 00356 00357 //Increment counter 00358 ccmIncCounter(b, qLen); 00359 //Compute S(i) = CIPH(CTR(i)) 00360 cipher->encryptBlock(context, b, s); 00361 //Compute B(i) = C(i) XOR S(i) 00362 ccmXorBlock(p, c, s, m); 00363 00364 //XOR B(i) with Y(i-1) 00365 ccmXorBlock(y, p, y, m); 00366 //Compute Y(i) = CIPH(B(i) ^ Y(i-1)) 00367 cipher->encryptBlock(context, y, y); 00368 00369 //Next block 00370 length -= m; 00371 c += m; 00372 p += m; 00373 } 00374 00375 //Compute MAC 00376 ccmXorBlock(r, r, y, tLen); 00377 00378 //The calculated tag is bitwise compared to the received tag. The 00379 //message is authenticated if and only if the tags match 00380 if(memcmp(r, t, tLen)) 00381 return ERROR_FAILURE; 00382 00383 //Successful decryption 00384 return NO_ERROR; 00385 } 00386 00387 00388 /** 00389 * @brief XOR operation 00390 * @param[out] x Block resulting from the XOR operation 00391 * @param[in] a First block 00392 * @param[in] b Second block 00393 * @param[in] n Size of the block 00394 **/ 00395 00396 void ccmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n) 00397 { 00398 size_t i; 00399 00400 //Perform XOR operation 00401 for(i = 0; i < n; i++) 00402 x[i] = a[i] ^ b[i]; 00403 } 00404 00405 00406 /** 00407 * @brief Increment counter block 00408 * @param[in,out] x Pointer to the counter block 00409 * @param[in] n Size in bytes of the specific part of the block to be incremented 00410 **/ 00411 00412 void ccmIncCounter(uint8_t *x, size_t n) 00413 { 00414 size_t i; 00415 00416 //The function increments the right-most bytes of the block. The remaining 00417 //left-most bytes remain unchanged 00418 for(i = 0; i < n; i++) 00419 { 00420 //Increment the current byte and propagate the carry if necessary 00421 if(++(x[15 - i]) != 0) 00422 break; 00423 } 00424 } 00425 00426 #endif 00427
Generated on Tue Jul 12 2022 17:10:12 by
