Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
cipher_mode_gcm.c
Go to the documentation of this file.
00001 /** 00002 * @file cipher_mode_gcm.c 00003 * @brief Galois/Counter Mode (GCM) 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 * The Galois/Counter Mode (GCM) is an authenticated encryption algorithm 00028 * designed to provide both data authenticity (integrity) and confidentiality. 00029 * Refer to SP 800-38D for more details 00030 * 00031 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00032 * @version 1.7.6 00033 **/ 00034 00035 //Switch to the appropriate trace level 00036 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL 00037 00038 //Dependencies 00039 #include <string.h> 00040 #include "crypto.h" 00041 #include "cipher_mode_gcm.h" 00042 #include "debug.h" 00043 00044 //Check crypto library configuration 00045 #if (GCM_SUPPORT == ENABLED) 00046 00047 //Reduction table 00048 static const uint32_t r[16] = 00049 { 00050 0x00000000, 00051 0x1C200000, 00052 0x38400000, 00053 0x24600000, 00054 0x70800000, 00055 0x6CA00000, 00056 0x48C00000, 00057 0x54E00000, 00058 0xE1000000, 00059 0xFD200000, 00060 0xD9400000, 00061 0xC5600000, 00062 0x91800000, 00063 0x8DA00000, 00064 0xA9C00000, 00065 0xB5E00000 00066 }; 00067 00068 00069 /** 00070 * @brief Initialize GCM context 00071 * @param[in] context Pointer to the GCM context 00072 * @param[in] cipherAlgo Cipher algorithm 00073 * @param[in] cipherContext Pointer to the cipher algorithm context 00074 * @return Error code 00075 **/ 00076 00077 error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext) 00078 { 00079 uint_t i; 00080 uint_t j; 00081 uint8_t c; 00082 uint32_t h[4]; 00083 00084 //GCM supports only symmetric block ciphers whose block size is 128 bits 00085 if(cipherAlgo->type != CIPHER_ALGO_TYPE_BLOCK || cipherAlgo->blockSize != 16) 00086 return ERROR_INVALID_PARAMETER; 00087 00088 //Save cipher algorithm context 00089 context->cipherAlgo = cipherAlgo; 00090 context->cipherContext = cipherContext; 00091 00092 //Let H = 0 00093 h[0] = 0; 00094 h[1] = 0; 00095 h[2] = 0; 00096 h[3] = 0; 00097 00098 //Generate the hash subkey H 00099 context->cipherAlgo->encryptBlock(context->cipherContext, 00100 (uint8_t *) h, (uint8_t *) h); 00101 00102 //Pre-compute M(0) = H * 0 00103 j = reverseInt4(0); 00104 context->m[j][0] = 0; 00105 context->m[j][1] = 0; 00106 context->m[j][2] = 0; 00107 context->m[j][3] = 0; 00108 00109 //Pre-compute M(1) = H * 1 00110 j = reverseInt4(1); 00111 context->m[j][0] = betoh32(h[3]); 00112 context->m[j][1] = betoh32(h[2]); 00113 context->m[j][2] = betoh32(h[1]); 00114 context->m[j][3] = betoh32(h[0]); 00115 00116 //Pre-compute all 4-bit multiples of H 00117 for(i = 2; i < 16; i++) 00118 { 00119 //Odd value? 00120 if(i & 1) 00121 { 00122 //Compute M(i) = M(i - 1) + H 00123 j = reverseInt4(i - 1); 00124 h[0] = context->m[j][0]; 00125 h[1] = context->m[j][1]; 00126 h[2] = context->m[j][2]; 00127 h[3] = context->m[j][3]; 00128 00129 //An addition in GF(2^128) is identical to a bitwise 00130 //exclusive-OR operation 00131 j = reverseInt4(1); 00132 h[0] ^= context->m[j][0]; 00133 h[1] ^= context->m[j][1]; 00134 h[2] ^= context->m[j][2]; 00135 h[3] ^= context->m[j][3]; 00136 } 00137 //Even value? 00138 else 00139 { 00140 //Compute M(i) = M(i / 2) * x 00141 j = reverseInt4(i / 2); 00142 h[0] = context->m[j][0]; 00143 h[1] = context->m[j][1]; 00144 h[2] = context->m[j][2]; 00145 h[3] = context->m[j][3]; 00146 00147 //The multiplication of a polynomial by x in GF(2^128) 00148 //corresponds to a shift of indices 00149 c = h[0] & 0x01; 00150 h[0] = (h[0] >> 1) | (h[1] << 31); 00151 h[1] = (h[1] >> 1) | (h[2] << 31); 00152 h[2] = (h[2] >> 1) | (h[3] << 31); 00153 h[3] >>= 1; 00154 00155 //If the highest term of the result is equal to one, 00156 //then perform reduction 00157 if(c != 0) 00158 h[3] ^= r[reverseInt4(1)]; 00159 } 00160 00161 //Save M(i) 00162 j = reverseInt4(i); 00163 context->m[j][0] = h[0]; 00164 context->m[j][1] = h[1]; 00165 context->m[j][2] = h[2]; 00166 context->m[j][3] = h[3]; 00167 } 00168 00169 //Successful initialization 00170 return NO_ERROR; 00171 } 00172 00173 00174 /** 00175 * @brief Authenticated encryption using GCM 00176 * @param[in] context Pointer to the GCM context 00177 * @param[in] iv Initialization vector 00178 * @param[in] ivLen Length of the initialization vector 00179 * @param[in] a Additional authenticated data 00180 * @param[in] aLen Length of the additional data 00181 * @param[in] p Plaintext to be encrypted 00182 * @param[out] c Ciphertext resulting from the encryption 00183 * @param[in] length Total number of data bytes to be encrypted 00184 * @param[out] t Authentication tag 00185 * @param[in] tLen Length of the authentication tag 00186 * @return Error code 00187 **/ 00188 00189 error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, 00190 size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen) 00191 { 00192 size_t k; 00193 size_t n; 00194 uint8_t b[16]; 00195 uint8_t j[16]; 00196 uint8_t s[16]; 00197 00198 //Make sure the GCM context is valid 00199 if(context == NULL) 00200 return ERROR_INVALID_PARAMETER; 00201 00202 //The length of the IV shall meet SP 800-38D requirements 00203 if(ivLen < 1) 00204 return ERROR_INVALID_PARAMETER; 00205 //Check the length of the authentication tag 00206 if(tLen < 4 || tLen > 16) 00207 return ERROR_INVALID_PARAMETER; 00208 00209 //Check whether the length of the IV is 96 bits 00210 if(ivLen == 12) 00211 { 00212 //When the length of the IV is 96 bits, the padding string is 00213 //appended to the IV to form the pre-counter block 00214 memcpy(j, iv, 12); 00215 STORE32BE(1, j + 12); 00216 } 00217 else 00218 { 00219 //Initialize GHASH calculation 00220 memset(j, 0, 16); 00221 00222 //Length of the IV 00223 n = ivLen; 00224 00225 //Process the initialization vector 00226 while(n > 0) 00227 { 00228 //The IV processed in a block-by-block fashion 00229 k = MIN(n, 16); 00230 00231 //Apply GHASH function 00232 gcmXorBlock(j, j, iv, k); 00233 gcmMul(context, j); 00234 00235 //Next block 00236 iv += k; 00237 n -= k; 00238 } 00239 00240 //The string is appended with 64 additional 0 bits, followed by the 00241 //64-bit representation of the length of the IV 00242 memset(b, 0, 16); 00243 STORE32BE(ivLen * 8, b + 12); 00244 00245 //The GHASH function is applied to the resulting string to form the 00246 //pre-counter block 00247 gcmXorBlock(j, j, b, 16); 00248 gcmMul(context, j); 00249 } 00250 00251 //Compute MSB(CIPH(J(0))) 00252 context->cipherAlgo->encryptBlock(context->cipherContext, j, b); 00253 memcpy(t, b, tLen); 00254 00255 //Initialize GHASH calculation 00256 memset(s, 0, 16); 00257 //Length of the AAD 00258 n = aLen; 00259 00260 //Process AAD 00261 while(n > 0) 00262 { 00263 //Additional data are processed in a block-by-block fashion 00264 k = MIN(n, 16); 00265 00266 //Apply GHASH function 00267 gcmXorBlock(s, s, a, k); 00268 gcmMul(context, s); 00269 00270 //Next block 00271 a += k; 00272 n -= k; 00273 } 00274 00275 //Length of the plaintext 00276 n = length; 00277 00278 //Process plaintext 00279 while(n > 0) 00280 { 00281 //The encryption operates in a block-by-block fashion 00282 k = MIN(n, 16); 00283 00284 //Increment counter 00285 gcmIncCounter(j); 00286 00287 //Encrypt plaintext 00288 context->cipherAlgo->encryptBlock(context->cipherContext, j, b); 00289 gcmXorBlock(c, p, b, k); 00290 00291 //Apply GHASH function 00292 gcmXorBlock(s, s, c, k); 00293 gcmMul(context, s); 00294 00295 //Next block 00296 p += k; 00297 c += k; 00298 n -= k; 00299 } 00300 00301 //Append the 64-bit representation of the length of the AAD and the ciphertext 00302 memset(b, 0, 16); 00303 STORE32BE(aLen * 8, b + 4); 00304 STORE32BE(length * 8, b + 12); 00305 00306 //The GHASH function is applied to the result to produce a single output block S 00307 gcmXorBlock(s, s, b, 16); 00308 gcmMul(context, s); 00309 00310 //Let T = MSB(GCTR(J(0), S) 00311 gcmXorBlock(t, t, s, tLen); 00312 00313 //Successful encryption 00314 return NO_ERROR; 00315 } 00316 00317 00318 /** 00319 * @brief Authenticated decryption using GCM 00320 * @param[in] context Pointer to the GCM context 00321 * @param[in] iv Initialization vector 00322 * @param[in] ivLen Length of the initialization vector 00323 * @param[in] a Additional authenticated data 00324 * @param[in] aLen Length of the additional data 00325 * @param[in] c Ciphertext to be decrypted 00326 * @param[out] p Plaintext resulting from the decryption 00327 * @param[in] length Total number of data bytes to be decrypted 00328 * @param[in] t Authentication tag 00329 * @param[in] tLen Length of the authentication tag 00330 * @return Error code 00331 **/ 00332 00333 error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, 00334 size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen) 00335 { 00336 size_t k; 00337 size_t n; 00338 uint8_t b[16]; 00339 uint8_t j[16]; 00340 uint8_t r[16]; 00341 uint8_t s[16]; 00342 00343 ///Make sure the GCM context is valid 00344 if(context == NULL) 00345 return ERROR_INVALID_PARAMETER; 00346 00347 //The length of the IV shall meet SP 800-38D requirements 00348 if(ivLen < 1) 00349 return ERROR_INVALID_PARAMETER; 00350 //Check the length of the authentication tag 00351 if(tLen < 4 || tLen > 16) 00352 return ERROR_INVALID_PARAMETER; 00353 00354 //Check whether the length of the IV is 96 bits 00355 if(ivLen == 12) 00356 { 00357 //When the length of the IV is 96 bits, the padding string is 00358 //appended to the IV to form the pre-counter block 00359 memcpy(j, iv, 12); 00360 STORE32BE(1, j + 12); 00361 } 00362 else 00363 { 00364 //Initialize GHASH calculation 00365 memset(j, 0, 16); 00366 00367 //Length of the IV 00368 n = ivLen; 00369 00370 //Process the initialization vector 00371 while(n > 0) 00372 { 00373 //The IV processed in a block-by-block fashion 00374 k = MIN(n, 16); 00375 00376 //Apply GHASH function 00377 gcmXorBlock(j, j, iv, k); 00378 gcmMul(context, j); 00379 00380 //Next block 00381 iv += k; 00382 n -= k; 00383 } 00384 00385 //The string is appended with 64 additional 0 bits, followed by the 00386 //64-bit representation of the length of the IV 00387 memset(b, 0, 16); 00388 STORE32BE(ivLen * 8, b + 12); 00389 00390 //The GHASH function is applied to the resulting string to form the 00391 //pre-counter block 00392 gcmXorBlock(j, j, b, 16); 00393 gcmMul(context, j); 00394 } 00395 00396 //Compute MSB(CIPH(J(0))) 00397 context->cipherAlgo->encryptBlock(context->cipherContext, j, b); 00398 memcpy(r, b, tLen); 00399 00400 //Initialize GHASH calculation 00401 memset(s, 0, 16); 00402 //Length of the AAD 00403 n = aLen; 00404 00405 //Process AAD 00406 while(n > 0) 00407 { 00408 //Additional data are processed in a block-by-block fashion 00409 k = MIN(n, 16); 00410 00411 //Apply GHASH function 00412 gcmXorBlock(s, s, a, k); 00413 gcmMul(context, s); 00414 00415 //Next block 00416 a += k; 00417 n -= k; 00418 } 00419 00420 //Length of the ciphertext 00421 n = length; 00422 00423 //Process ciphertext 00424 while(n > 0) 00425 { 00426 //The decryption operates in a block-by-block fashion 00427 k = MIN(n, 16); 00428 00429 //Apply GHASH function 00430 gcmXorBlock(s, s, c, k); 00431 gcmMul(context, s); 00432 00433 //Increment counter 00434 gcmIncCounter(j); 00435 00436 //Decrypt ciphertext 00437 context->cipherAlgo->encryptBlock(context->cipherContext, j, b); 00438 gcmXorBlock(p, c, b, k); 00439 00440 //Next block 00441 c += k; 00442 p += k; 00443 n -= k; 00444 } 00445 00446 //Append the 64-bit representation of the length of the AAD and the ciphertext 00447 memset(b, 0, 16); 00448 STORE32BE(aLen * 8, b + 4); 00449 STORE32BE(length * 8, b + 12); 00450 00451 //The GHASH function is applied to the result to produce a single output block S 00452 gcmXorBlock(s, s, b, 16); 00453 gcmMul(context, s); 00454 00455 //Let R = MSB(GCTR(J(0), S) 00456 gcmXorBlock(r, r, s, tLen); 00457 00458 //The calculated tag is bitwise compared to the received tag. The 00459 //message is authenticated if and only if the tags match 00460 if(memcmp(r, t, tLen)) 00461 return ERROR_FAILURE; 00462 00463 //Successful decryption 00464 return NO_ERROR; 00465 } 00466 00467 00468 /** 00469 * @brief Multiplication operation 00470 * @param[in] context Pointer to the GCM context 00471 * @param[in, out] x 16-byte block to be multiplied by H 00472 **/ 00473 00474 void gcmMul(GcmContext *context, uint8_t *x) 00475 { 00476 int_t i; 00477 uint8_t b; 00478 uint8_t c; 00479 uint32_t z[4]; 00480 00481 //Let Z = 0 00482 z[0] = 0; 00483 z[1] = 0; 00484 z[2] = 0; 00485 z[3] = 0; 00486 00487 //Fast table-driven implementation 00488 for(i = 15; i >= 0; i--) 00489 { 00490 //Process the lower nibble 00491 b = x[i] & 0x0F; 00492 00493 c = z[0] & 0x0F; 00494 z[0] = (z[0] >> 4) | (z[1] << 28); 00495 z[1] = (z[1] >> 4) | (z[2] << 28); 00496 z[2] = (z[2] >> 4) | (z[3] << 28); 00497 z[3] >>= 4; 00498 00499 z[3] ^= r[c]; 00500 00501 z[0] ^= context->m[b][0]; 00502 z[1] ^= context->m[b][1]; 00503 z[2] ^= context->m[b][2]; 00504 z[3] ^= context->m[b][3]; 00505 00506 //Process the upper nibble 00507 b = (x[i] >> 4) & 0x0F; 00508 00509 c = z[0] & 0x0F; 00510 z[0] = (z[0] >> 4) | (z[1] << 28); 00511 z[1] = (z[1] >> 4) | (z[2] << 28); 00512 z[2] = (z[2] >> 4) | (z[3] << 28); 00513 z[3] >>= 4; 00514 00515 z[3] ^= r[c]; 00516 00517 z[0] ^= context->m[b][0]; 00518 z[1] ^= context->m[b][1]; 00519 z[2] ^= context->m[b][2]; 00520 z[3] ^= context->m[b][3]; 00521 } 00522 00523 //Save the result 00524 STORE32BE(z[3], x); 00525 STORE32BE(z[2], x + 4); 00526 STORE32BE(z[1], x + 8); 00527 STORE32BE(z[0], x + 12); 00528 } 00529 00530 00531 /** 00532 * @brief XOR operation 00533 * @param[out] x Block resulting from the XOR operation 00534 * @param[in] a First block 00535 * @param[in] b Second block 00536 * @param[in] n Size of the block 00537 **/ 00538 00539 void gcmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n) 00540 { 00541 size_t i; 00542 00543 //Perform XOR operation 00544 for(i = 0; i < n; i++) 00545 x[i] = a[i] ^ b[i]; 00546 } 00547 00548 00549 /** 00550 * @brief Increment counter block 00551 * @param[in,out] x Pointer to the counter block 00552 **/ 00553 00554 void gcmIncCounter(uint8_t *x) 00555 { 00556 size_t i; 00557 00558 //The function increments the right-most 32 bits of the block. The remaining 00559 //left-most 96 bits remain unchanged 00560 for(i = 0; i < 4; i++) 00561 { 00562 //Increment the current byte and propagate the carry if necessary 00563 if(++(x[15 - i]) != 0) 00564 break; 00565 } 00566 } 00567 00568 #endif 00569
Generated on Tue Jul 12 2022 17:10:12 by
