Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cipher_mode_gcm.c Source File

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