Webserver+3d print

Dependents:   Nucleo

Committer:
Sergunb
Date:
Sat Feb 04 18:15:49 2017 +0000
Revision:
0:8918a71cdbe9
nothing else

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sergunb 0:8918a71cdbe9 1 /**
Sergunb 0:8918a71cdbe9 2 * @file cipher_mode_gcm.c
Sergunb 0:8918a71cdbe9 3 * @brief Galois/Counter Mode (GCM)
Sergunb 0:8918a71cdbe9 4 *
Sergunb 0:8918a71cdbe9 5 * @section License
Sergunb 0:8918a71cdbe9 6 *
Sergunb 0:8918a71cdbe9 7 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
Sergunb 0:8918a71cdbe9 8 *
Sergunb 0:8918a71cdbe9 9 * This file is part of CycloneCrypto Open.
Sergunb 0:8918a71cdbe9 10 *
Sergunb 0:8918a71cdbe9 11 * This program is free software; you can redistribute it and/or
Sergunb 0:8918a71cdbe9 12 * modify it under the terms of the GNU General Public License
Sergunb 0:8918a71cdbe9 13 * as published by the Free Software Foundation; either version 2
Sergunb 0:8918a71cdbe9 14 * of the License, or (at your option) any later version.
Sergunb 0:8918a71cdbe9 15 *
Sergunb 0:8918a71cdbe9 16 * This program is distributed in the hope that it will be useful,
Sergunb 0:8918a71cdbe9 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Sergunb 0:8918a71cdbe9 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Sergunb 0:8918a71cdbe9 19 * GNU General Public License for more details.
Sergunb 0:8918a71cdbe9 20 *
Sergunb 0:8918a71cdbe9 21 * You should have received a copy of the GNU General Public License
Sergunb 0:8918a71cdbe9 22 * along with this program; if not, write to the Free Software Foundation,
Sergunb 0:8918a71cdbe9 23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Sergunb 0:8918a71cdbe9 24 *
Sergunb 0:8918a71cdbe9 25 * @section Description
Sergunb 0:8918a71cdbe9 26 *
Sergunb 0:8918a71cdbe9 27 * The Galois/Counter Mode (GCM) is an authenticated encryption algorithm
Sergunb 0:8918a71cdbe9 28 * designed to provide both data authenticity (integrity) and confidentiality.
Sergunb 0:8918a71cdbe9 29 * Refer to SP 800-38D for more details
Sergunb 0:8918a71cdbe9 30 *
Sergunb 0:8918a71cdbe9 31 * @author Oryx Embedded SARL (www.oryx-embedded.com)
Sergunb 0:8918a71cdbe9 32 * @version 1.7.6
Sergunb 0:8918a71cdbe9 33 **/
Sergunb 0:8918a71cdbe9 34
Sergunb 0:8918a71cdbe9 35 //Switch to the appropriate trace level
Sergunb 0:8918a71cdbe9 36 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
Sergunb 0:8918a71cdbe9 37
Sergunb 0:8918a71cdbe9 38 //Dependencies
Sergunb 0:8918a71cdbe9 39 #include <string.h>
Sergunb 0:8918a71cdbe9 40 #include "crypto.h"
Sergunb 0:8918a71cdbe9 41 #include "cipher_mode_gcm.h"
Sergunb 0:8918a71cdbe9 42 #include "debug.h"
Sergunb 0:8918a71cdbe9 43
Sergunb 0:8918a71cdbe9 44 //Check crypto library configuration
Sergunb 0:8918a71cdbe9 45 #if (GCM_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 46
Sergunb 0:8918a71cdbe9 47 //Reduction table
Sergunb 0:8918a71cdbe9 48 static const uint32_t r[16] =
Sergunb 0:8918a71cdbe9 49 {
Sergunb 0:8918a71cdbe9 50 0x00000000,
Sergunb 0:8918a71cdbe9 51 0x1C200000,
Sergunb 0:8918a71cdbe9 52 0x38400000,
Sergunb 0:8918a71cdbe9 53 0x24600000,
Sergunb 0:8918a71cdbe9 54 0x70800000,
Sergunb 0:8918a71cdbe9 55 0x6CA00000,
Sergunb 0:8918a71cdbe9 56 0x48C00000,
Sergunb 0:8918a71cdbe9 57 0x54E00000,
Sergunb 0:8918a71cdbe9 58 0xE1000000,
Sergunb 0:8918a71cdbe9 59 0xFD200000,
Sergunb 0:8918a71cdbe9 60 0xD9400000,
Sergunb 0:8918a71cdbe9 61 0xC5600000,
Sergunb 0:8918a71cdbe9 62 0x91800000,
Sergunb 0:8918a71cdbe9 63 0x8DA00000,
Sergunb 0:8918a71cdbe9 64 0xA9C00000,
Sergunb 0:8918a71cdbe9 65 0xB5E00000
Sergunb 0:8918a71cdbe9 66 };
Sergunb 0:8918a71cdbe9 67
Sergunb 0:8918a71cdbe9 68
Sergunb 0:8918a71cdbe9 69 /**
Sergunb 0:8918a71cdbe9 70 * @brief Initialize GCM context
Sergunb 0:8918a71cdbe9 71 * @param[in] context Pointer to the GCM context
Sergunb 0:8918a71cdbe9 72 * @param[in] cipherAlgo Cipher algorithm
Sergunb 0:8918a71cdbe9 73 * @param[in] cipherContext Pointer to the cipher algorithm context
Sergunb 0:8918a71cdbe9 74 * @return Error code
Sergunb 0:8918a71cdbe9 75 **/
Sergunb 0:8918a71cdbe9 76
Sergunb 0:8918a71cdbe9 77 error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext)
Sergunb 0:8918a71cdbe9 78 {
Sergunb 0:8918a71cdbe9 79 uint_t i;
Sergunb 0:8918a71cdbe9 80 uint_t j;
Sergunb 0:8918a71cdbe9 81 uint8_t c;
Sergunb 0:8918a71cdbe9 82 uint32_t h[4];
Sergunb 0:8918a71cdbe9 83
Sergunb 0:8918a71cdbe9 84 //GCM supports only symmetric block ciphers whose block size is 128 bits
Sergunb 0:8918a71cdbe9 85 if(cipherAlgo->type != CIPHER_ALGO_TYPE_BLOCK || cipherAlgo->blockSize != 16)
Sergunb 0:8918a71cdbe9 86 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 87
Sergunb 0:8918a71cdbe9 88 //Save cipher algorithm context
Sergunb 0:8918a71cdbe9 89 context->cipherAlgo = cipherAlgo;
Sergunb 0:8918a71cdbe9 90 context->cipherContext = cipherContext;
Sergunb 0:8918a71cdbe9 91
Sergunb 0:8918a71cdbe9 92 //Let H = 0
Sergunb 0:8918a71cdbe9 93 h[0] = 0;
Sergunb 0:8918a71cdbe9 94 h[1] = 0;
Sergunb 0:8918a71cdbe9 95 h[2] = 0;
Sergunb 0:8918a71cdbe9 96 h[3] = 0;
Sergunb 0:8918a71cdbe9 97
Sergunb 0:8918a71cdbe9 98 //Generate the hash subkey H
Sergunb 0:8918a71cdbe9 99 context->cipherAlgo->encryptBlock(context->cipherContext,
Sergunb 0:8918a71cdbe9 100 (uint8_t *) h, (uint8_t *) h);
Sergunb 0:8918a71cdbe9 101
Sergunb 0:8918a71cdbe9 102 //Pre-compute M(0) = H * 0
Sergunb 0:8918a71cdbe9 103 j = reverseInt4(0);
Sergunb 0:8918a71cdbe9 104 context->m[j][0] = 0;
Sergunb 0:8918a71cdbe9 105 context->m[j][1] = 0;
Sergunb 0:8918a71cdbe9 106 context->m[j][2] = 0;
Sergunb 0:8918a71cdbe9 107 context->m[j][3] = 0;
Sergunb 0:8918a71cdbe9 108
Sergunb 0:8918a71cdbe9 109 //Pre-compute M(1) = H * 1
Sergunb 0:8918a71cdbe9 110 j = reverseInt4(1);
Sergunb 0:8918a71cdbe9 111 context->m[j][0] = betoh32(h[3]);
Sergunb 0:8918a71cdbe9 112 context->m[j][1] = betoh32(h[2]);
Sergunb 0:8918a71cdbe9 113 context->m[j][2] = betoh32(h[1]);
Sergunb 0:8918a71cdbe9 114 context->m[j][3] = betoh32(h[0]);
Sergunb 0:8918a71cdbe9 115
Sergunb 0:8918a71cdbe9 116 //Pre-compute all 4-bit multiples of H
Sergunb 0:8918a71cdbe9 117 for(i = 2; i < 16; i++)
Sergunb 0:8918a71cdbe9 118 {
Sergunb 0:8918a71cdbe9 119 //Odd value?
Sergunb 0:8918a71cdbe9 120 if(i & 1)
Sergunb 0:8918a71cdbe9 121 {
Sergunb 0:8918a71cdbe9 122 //Compute M(i) = M(i - 1) + H
Sergunb 0:8918a71cdbe9 123 j = reverseInt4(i - 1);
Sergunb 0:8918a71cdbe9 124 h[0] = context->m[j][0];
Sergunb 0:8918a71cdbe9 125 h[1] = context->m[j][1];
Sergunb 0:8918a71cdbe9 126 h[2] = context->m[j][2];
Sergunb 0:8918a71cdbe9 127 h[3] = context->m[j][3];
Sergunb 0:8918a71cdbe9 128
Sergunb 0:8918a71cdbe9 129 //An addition in GF(2^128) is identical to a bitwise
Sergunb 0:8918a71cdbe9 130 //exclusive-OR operation
Sergunb 0:8918a71cdbe9 131 j = reverseInt4(1);
Sergunb 0:8918a71cdbe9 132 h[0] ^= context->m[j][0];
Sergunb 0:8918a71cdbe9 133 h[1] ^= context->m[j][1];
Sergunb 0:8918a71cdbe9 134 h[2] ^= context->m[j][2];
Sergunb 0:8918a71cdbe9 135 h[3] ^= context->m[j][3];
Sergunb 0:8918a71cdbe9 136 }
Sergunb 0:8918a71cdbe9 137 //Even value?
Sergunb 0:8918a71cdbe9 138 else
Sergunb 0:8918a71cdbe9 139 {
Sergunb 0:8918a71cdbe9 140 //Compute M(i) = M(i / 2) * x
Sergunb 0:8918a71cdbe9 141 j = reverseInt4(i / 2);
Sergunb 0:8918a71cdbe9 142 h[0] = context->m[j][0];
Sergunb 0:8918a71cdbe9 143 h[1] = context->m[j][1];
Sergunb 0:8918a71cdbe9 144 h[2] = context->m[j][2];
Sergunb 0:8918a71cdbe9 145 h[3] = context->m[j][3];
Sergunb 0:8918a71cdbe9 146
Sergunb 0:8918a71cdbe9 147 //The multiplication of a polynomial by x in GF(2^128)
Sergunb 0:8918a71cdbe9 148 //corresponds to a shift of indices
Sergunb 0:8918a71cdbe9 149 c = h[0] & 0x01;
Sergunb 0:8918a71cdbe9 150 h[0] = (h[0] >> 1) | (h[1] << 31);
Sergunb 0:8918a71cdbe9 151 h[1] = (h[1] >> 1) | (h[2] << 31);
Sergunb 0:8918a71cdbe9 152 h[2] = (h[2] >> 1) | (h[3] << 31);
Sergunb 0:8918a71cdbe9 153 h[3] >>= 1;
Sergunb 0:8918a71cdbe9 154
Sergunb 0:8918a71cdbe9 155 //If the highest term of the result is equal to one,
Sergunb 0:8918a71cdbe9 156 //then perform reduction
Sergunb 0:8918a71cdbe9 157 if(c != 0)
Sergunb 0:8918a71cdbe9 158 h[3] ^= r[reverseInt4(1)];
Sergunb 0:8918a71cdbe9 159 }
Sergunb 0:8918a71cdbe9 160
Sergunb 0:8918a71cdbe9 161 //Save M(i)
Sergunb 0:8918a71cdbe9 162 j = reverseInt4(i);
Sergunb 0:8918a71cdbe9 163 context->m[j][0] = h[0];
Sergunb 0:8918a71cdbe9 164 context->m[j][1] = h[1];
Sergunb 0:8918a71cdbe9 165 context->m[j][2] = h[2];
Sergunb 0:8918a71cdbe9 166 context->m[j][3] = h[3];
Sergunb 0:8918a71cdbe9 167 }
Sergunb 0:8918a71cdbe9 168
Sergunb 0:8918a71cdbe9 169 //Successful initialization
Sergunb 0:8918a71cdbe9 170 return NO_ERROR;
Sergunb 0:8918a71cdbe9 171 }
Sergunb 0:8918a71cdbe9 172
Sergunb 0:8918a71cdbe9 173
Sergunb 0:8918a71cdbe9 174 /**
Sergunb 0:8918a71cdbe9 175 * @brief Authenticated encryption using GCM
Sergunb 0:8918a71cdbe9 176 * @param[in] context Pointer to the GCM context
Sergunb 0:8918a71cdbe9 177 * @param[in] iv Initialization vector
Sergunb 0:8918a71cdbe9 178 * @param[in] ivLen Length of the initialization vector
Sergunb 0:8918a71cdbe9 179 * @param[in] a Additional authenticated data
Sergunb 0:8918a71cdbe9 180 * @param[in] aLen Length of the additional data
Sergunb 0:8918a71cdbe9 181 * @param[in] p Plaintext to be encrypted
Sergunb 0:8918a71cdbe9 182 * @param[out] c Ciphertext resulting from the encryption
Sergunb 0:8918a71cdbe9 183 * @param[in] length Total number of data bytes to be encrypted
Sergunb 0:8918a71cdbe9 184 * @param[out] t Authentication tag
Sergunb 0:8918a71cdbe9 185 * @param[in] tLen Length of the authentication tag
Sergunb 0:8918a71cdbe9 186 * @return Error code
Sergunb 0:8918a71cdbe9 187 **/
Sergunb 0:8918a71cdbe9 188
Sergunb 0:8918a71cdbe9 189 error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a,
Sergunb 0:8918a71cdbe9 190 size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
Sergunb 0:8918a71cdbe9 191 {
Sergunb 0:8918a71cdbe9 192 size_t k;
Sergunb 0:8918a71cdbe9 193 size_t n;
Sergunb 0:8918a71cdbe9 194 uint8_t b[16];
Sergunb 0:8918a71cdbe9 195 uint8_t j[16];
Sergunb 0:8918a71cdbe9 196 uint8_t s[16];
Sergunb 0:8918a71cdbe9 197
Sergunb 0:8918a71cdbe9 198 //Make sure the GCM context is valid
Sergunb 0:8918a71cdbe9 199 if(context == NULL)
Sergunb 0:8918a71cdbe9 200 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 201
Sergunb 0:8918a71cdbe9 202 //The length of the IV shall meet SP 800-38D requirements
Sergunb 0:8918a71cdbe9 203 if(ivLen < 1)
Sergunb 0:8918a71cdbe9 204 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 205 //Check the length of the authentication tag
Sergunb 0:8918a71cdbe9 206 if(tLen < 4 || tLen > 16)
Sergunb 0:8918a71cdbe9 207 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 208
Sergunb 0:8918a71cdbe9 209 //Check whether the length of the IV is 96 bits
Sergunb 0:8918a71cdbe9 210 if(ivLen == 12)
Sergunb 0:8918a71cdbe9 211 {
Sergunb 0:8918a71cdbe9 212 //When the length of the IV is 96 bits, the padding string is
Sergunb 0:8918a71cdbe9 213 //appended to the IV to form the pre-counter block
Sergunb 0:8918a71cdbe9 214 memcpy(j, iv, 12);
Sergunb 0:8918a71cdbe9 215 STORE32BE(1, j + 12);
Sergunb 0:8918a71cdbe9 216 }
Sergunb 0:8918a71cdbe9 217 else
Sergunb 0:8918a71cdbe9 218 {
Sergunb 0:8918a71cdbe9 219 //Initialize GHASH calculation
Sergunb 0:8918a71cdbe9 220 memset(j, 0, 16);
Sergunb 0:8918a71cdbe9 221
Sergunb 0:8918a71cdbe9 222 //Length of the IV
Sergunb 0:8918a71cdbe9 223 n = ivLen;
Sergunb 0:8918a71cdbe9 224
Sergunb 0:8918a71cdbe9 225 //Process the initialization vector
Sergunb 0:8918a71cdbe9 226 while(n > 0)
Sergunb 0:8918a71cdbe9 227 {
Sergunb 0:8918a71cdbe9 228 //The IV processed in a block-by-block fashion
Sergunb 0:8918a71cdbe9 229 k = MIN(n, 16);
Sergunb 0:8918a71cdbe9 230
Sergunb 0:8918a71cdbe9 231 //Apply GHASH function
Sergunb 0:8918a71cdbe9 232 gcmXorBlock(j, j, iv, k);
Sergunb 0:8918a71cdbe9 233 gcmMul(context, j);
Sergunb 0:8918a71cdbe9 234
Sergunb 0:8918a71cdbe9 235 //Next block
Sergunb 0:8918a71cdbe9 236 iv += k;
Sergunb 0:8918a71cdbe9 237 n -= k;
Sergunb 0:8918a71cdbe9 238 }
Sergunb 0:8918a71cdbe9 239
Sergunb 0:8918a71cdbe9 240 //The string is appended with 64 additional 0 bits, followed by the
Sergunb 0:8918a71cdbe9 241 //64-bit representation of the length of the IV
Sergunb 0:8918a71cdbe9 242 memset(b, 0, 16);
Sergunb 0:8918a71cdbe9 243 STORE32BE(ivLen * 8, b + 12);
Sergunb 0:8918a71cdbe9 244
Sergunb 0:8918a71cdbe9 245 //The GHASH function is applied to the resulting string to form the
Sergunb 0:8918a71cdbe9 246 //pre-counter block
Sergunb 0:8918a71cdbe9 247 gcmXorBlock(j, j, b, 16);
Sergunb 0:8918a71cdbe9 248 gcmMul(context, j);
Sergunb 0:8918a71cdbe9 249 }
Sergunb 0:8918a71cdbe9 250
Sergunb 0:8918a71cdbe9 251 //Compute MSB(CIPH(J(0)))
Sergunb 0:8918a71cdbe9 252 context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
Sergunb 0:8918a71cdbe9 253 memcpy(t, b, tLen);
Sergunb 0:8918a71cdbe9 254
Sergunb 0:8918a71cdbe9 255 //Initialize GHASH calculation
Sergunb 0:8918a71cdbe9 256 memset(s, 0, 16);
Sergunb 0:8918a71cdbe9 257 //Length of the AAD
Sergunb 0:8918a71cdbe9 258 n = aLen;
Sergunb 0:8918a71cdbe9 259
Sergunb 0:8918a71cdbe9 260 //Process AAD
Sergunb 0:8918a71cdbe9 261 while(n > 0)
Sergunb 0:8918a71cdbe9 262 {
Sergunb 0:8918a71cdbe9 263 //Additional data are processed in a block-by-block fashion
Sergunb 0:8918a71cdbe9 264 k = MIN(n, 16);
Sergunb 0:8918a71cdbe9 265
Sergunb 0:8918a71cdbe9 266 //Apply GHASH function
Sergunb 0:8918a71cdbe9 267 gcmXorBlock(s, s, a, k);
Sergunb 0:8918a71cdbe9 268 gcmMul(context, s);
Sergunb 0:8918a71cdbe9 269
Sergunb 0:8918a71cdbe9 270 //Next block
Sergunb 0:8918a71cdbe9 271 a += k;
Sergunb 0:8918a71cdbe9 272 n -= k;
Sergunb 0:8918a71cdbe9 273 }
Sergunb 0:8918a71cdbe9 274
Sergunb 0:8918a71cdbe9 275 //Length of the plaintext
Sergunb 0:8918a71cdbe9 276 n = length;
Sergunb 0:8918a71cdbe9 277
Sergunb 0:8918a71cdbe9 278 //Process plaintext
Sergunb 0:8918a71cdbe9 279 while(n > 0)
Sergunb 0:8918a71cdbe9 280 {
Sergunb 0:8918a71cdbe9 281 //The encryption operates in a block-by-block fashion
Sergunb 0:8918a71cdbe9 282 k = MIN(n, 16);
Sergunb 0:8918a71cdbe9 283
Sergunb 0:8918a71cdbe9 284 //Increment counter
Sergunb 0:8918a71cdbe9 285 gcmIncCounter(j);
Sergunb 0:8918a71cdbe9 286
Sergunb 0:8918a71cdbe9 287 //Encrypt plaintext
Sergunb 0:8918a71cdbe9 288 context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
Sergunb 0:8918a71cdbe9 289 gcmXorBlock(c, p, b, k);
Sergunb 0:8918a71cdbe9 290
Sergunb 0:8918a71cdbe9 291 //Apply GHASH function
Sergunb 0:8918a71cdbe9 292 gcmXorBlock(s, s, c, k);
Sergunb 0:8918a71cdbe9 293 gcmMul(context, s);
Sergunb 0:8918a71cdbe9 294
Sergunb 0:8918a71cdbe9 295 //Next block
Sergunb 0:8918a71cdbe9 296 p += k;
Sergunb 0:8918a71cdbe9 297 c += k;
Sergunb 0:8918a71cdbe9 298 n -= k;
Sergunb 0:8918a71cdbe9 299 }
Sergunb 0:8918a71cdbe9 300
Sergunb 0:8918a71cdbe9 301 //Append the 64-bit representation of the length of the AAD and the ciphertext
Sergunb 0:8918a71cdbe9 302 memset(b, 0, 16);
Sergunb 0:8918a71cdbe9 303 STORE32BE(aLen * 8, b + 4);
Sergunb 0:8918a71cdbe9 304 STORE32BE(length * 8, b + 12);
Sergunb 0:8918a71cdbe9 305
Sergunb 0:8918a71cdbe9 306 //The GHASH function is applied to the result to produce a single output block S
Sergunb 0:8918a71cdbe9 307 gcmXorBlock(s, s, b, 16);
Sergunb 0:8918a71cdbe9 308 gcmMul(context, s);
Sergunb 0:8918a71cdbe9 309
Sergunb 0:8918a71cdbe9 310 //Let T = MSB(GCTR(J(0), S)
Sergunb 0:8918a71cdbe9 311 gcmXorBlock(t, t, s, tLen);
Sergunb 0:8918a71cdbe9 312
Sergunb 0:8918a71cdbe9 313 //Successful encryption
Sergunb 0:8918a71cdbe9 314 return NO_ERROR;
Sergunb 0:8918a71cdbe9 315 }
Sergunb 0:8918a71cdbe9 316
Sergunb 0:8918a71cdbe9 317
Sergunb 0:8918a71cdbe9 318 /**
Sergunb 0:8918a71cdbe9 319 * @brief Authenticated decryption using GCM
Sergunb 0:8918a71cdbe9 320 * @param[in] context Pointer to the GCM context
Sergunb 0:8918a71cdbe9 321 * @param[in] iv Initialization vector
Sergunb 0:8918a71cdbe9 322 * @param[in] ivLen Length of the initialization vector
Sergunb 0:8918a71cdbe9 323 * @param[in] a Additional authenticated data
Sergunb 0:8918a71cdbe9 324 * @param[in] aLen Length of the additional data
Sergunb 0:8918a71cdbe9 325 * @param[in] c Ciphertext to be decrypted
Sergunb 0:8918a71cdbe9 326 * @param[out] p Plaintext resulting from the decryption
Sergunb 0:8918a71cdbe9 327 * @param[in] length Total number of data bytes to be decrypted
Sergunb 0:8918a71cdbe9 328 * @param[in] t Authentication tag
Sergunb 0:8918a71cdbe9 329 * @param[in] tLen Length of the authentication tag
Sergunb 0:8918a71cdbe9 330 * @return Error code
Sergunb 0:8918a71cdbe9 331 **/
Sergunb 0:8918a71cdbe9 332
Sergunb 0:8918a71cdbe9 333 error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a,
Sergunb 0:8918a71cdbe9 334 size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
Sergunb 0:8918a71cdbe9 335 {
Sergunb 0:8918a71cdbe9 336 size_t k;
Sergunb 0:8918a71cdbe9 337 size_t n;
Sergunb 0:8918a71cdbe9 338 uint8_t b[16];
Sergunb 0:8918a71cdbe9 339 uint8_t j[16];
Sergunb 0:8918a71cdbe9 340 uint8_t r[16];
Sergunb 0:8918a71cdbe9 341 uint8_t s[16];
Sergunb 0:8918a71cdbe9 342
Sergunb 0:8918a71cdbe9 343 ///Make sure the GCM context is valid
Sergunb 0:8918a71cdbe9 344 if(context == NULL)
Sergunb 0:8918a71cdbe9 345 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 346
Sergunb 0:8918a71cdbe9 347 //The length of the IV shall meet SP 800-38D requirements
Sergunb 0:8918a71cdbe9 348 if(ivLen < 1)
Sergunb 0:8918a71cdbe9 349 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 350 //Check the length of the authentication tag
Sergunb 0:8918a71cdbe9 351 if(tLen < 4 || tLen > 16)
Sergunb 0:8918a71cdbe9 352 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 353
Sergunb 0:8918a71cdbe9 354 //Check whether the length of the IV is 96 bits
Sergunb 0:8918a71cdbe9 355 if(ivLen == 12)
Sergunb 0:8918a71cdbe9 356 {
Sergunb 0:8918a71cdbe9 357 //When the length of the IV is 96 bits, the padding string is
Sergunb 0:8918a71cdbe9 358 //appended to the IV to form the pre-counter block
Sergunb 0:8918a71cdbe9 359 memcpy(j, iv, 12);
Sergunb 0:8918a71cdbe9 360 STORE32BE(1, j + 12);
Sergunb 0:8918a71cdbe9 361 }
Sergunb 0:8918a71cdbe9 362 else
Sergunb 0:8918a71cdbe9 363 {
Sergunb 0:8918a71cdbe9 364 //Initialize GHASH calculation
Sergunb 0:8918a71cdbe9 365 memset(j, 0, 16);
Sergunb 0:8918a71cdbe9 366
Sergunb 0:8918a71cdbe9 367 //Length of the IV
Sergunb 0:8918a71cdbe9 368 n = ivLen;
Sergunb 0:8918a71cdbe9 369
Sergunb 0:8918a71cdbe9 370 //Process the initialization vector
Sergunb 0:8918a71cdbe9 371 while(n > 0)
Sergunb 0:8918a71cdbe9 372 {
Sergunb 0:8918a71cdbe9 373 //The IV processed in a block-by-block fashion
Sergunb 0:8918a71cdbe9 374 k = MIN(n, 16);
Sergunb 0:8918a71cdbe9 375
Sergunb 0:8918a71cdbe9 376 //Apply GHASH function
Sergunb 0:8918a71cdbe9 377 gcmXorBlock(j, j, iv, k);
Sergunb 0:8918a71cdbe9 378 gcmMul(context, j);
Sergunb 0:8918a71cdbe9 379
Sergunb 0:8918a71cdbe9 380 //Next block
Sergunb 0:8918a71cdbe9 381 iv += k;
Sergunb 0:8918a71cdbe9 382 n -= k;
Sergunb 0:8918a71cdbe9 383 }
Sergunb 0:8918a71cdbe9 384
Sergunb 0:8918a71cdbe9 385 //The string is appended with 64 additional 0 bits, followed by the
Sergunb 0:8918a71cdbe9 386 //64-bit representation of the length of the IV
Sergunb 0:8918a71cdbe9 387 memset(b, 0, 16);
Sergunb 0:8918a71cdbe9 388 STORE32BE(ivLen * 8, b + 12);
Sergunb 0:8918a71cdbe9 389
Sergunb 0:8918a71cdbe9 390 //The GHASH function is applied to the resulting string to form the
Sergunb 0:8918a71cdbe9 391 //pre-counter block
Sergunb 0:8918a71cdbe9 392 gcmXorBlock(j, j, b, 16);
Sergunb 0:8918a71cdbe9 393 gcmMul(context, j);
Sergunb 0:8918a71cdbe9 394 }
Sergunb 0:8918a71cdbe9 395
Sergunb 0:8918a71cdbe9 396 //Compute MSB(CIPH(J(0)))
Sergunb 0:8918a71cdbe9 397 context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
Sergunb 0:8918a71cdbe9 398 memcpy(r, b, tLen);
Sergunb 0:8918a71cdbe9 399
Sergunb 0:8918a71cdbe9 400 //Initialize GHASH calculation
Sergunb 0:8918a71cdbe9 401 memset(s, 0, 16);
Sergunb 0:8918a71cdbe9 402 //Length of the AAD
Sergunb 0:8918a71cdbe9 403 n = aLen;
Sergunb 0:8918a71cdbe9 404
Sergunb 0:8918a71cdbe9 405 //Process AAD
Sergunb 0:8918a71cdbe9 406 while(n > 0)
Sergunb 0:8918a71cdbe9 407 {
Sergunb 0:8918a71cdbe9 408 //Additional data are processed in a block-by-block fashion
Sergunb 0:8918a71cdbe9 409 k = MIN(n, 16);
Sergunb 0:8918a71cdbe9 410
Sergunb 0:8918a71cdbe9 411 //Apply GHASH function
Sergunb 0:8918a71cdbe9 412 gcmXorBlock(s, s, a, k);
Sergunb 0:8918a71cdbe9 413 gcmMul(context, s);
Sergunb 0:8918a71cdbe9 414
Sergunb 0:8918a71cdbe9 415 //Next block
Sergunb 0:8918a71cdbe9 416 a += k;
Sergunb 0:8918a71cdbe9 417 n -= k;
Sergunb 0:8918a71cdbe9 418 }
Sergunb 0:8918a71cdbe9 419
Sergunb 0:8918a71cdbe9 420 //Length of the ciphertext
Sergunb 0:8918a71cdbe9 421 n = length;
Sergunb 0:8918a71cdbe9 422
Sergunb 0:8918a71cdbe9 423 //Process ciphertext
Sergunb 0:8918a71cdbe9 424 while(n > 0)
Sergunb 0:8918a71cdbe9 425 {
Sergunb 0:8918a71cdbe9 426 //The decryption operates in a block-by-block fashion
Sergunb 0:8918a71cdbe9 427 k = MIN(n, 16);
Sergunb 0:8918a71cdbe9 428
Sergunb 0:8918a71cdbe9 429 //Apply GHASH function
Sergunb 0:8918a71cdbe9 430 gcmXorBlock(s, s, c, k);
Sergunb 0:8918a71cdbe9 431 gcmMul(context, s);
Sergunb 0:8918a71cdbe9 432
Sergunb 0:8918a71cdbe9 433 //Increment counter
Sergunb 0:8918a71cdbe9 434 gcmIncCounter(j);
Sergunb 0:8918a71cdbe9 435
Sergunb 0:8918a71cdbe9 436 //Decrypt ciphertext
Sergunb 0:8918a71cdbe9 437 context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
Sergunb 0:8918a71cdbe9 438 gcmXorBlock(p, c, b, k);
Sergunb 0:8918a71cdbe9 439
Sergunb 0:8918a71cdbe9 440 //Next block
Sergunb 0:8918a71cdbe9 441 c += k;
Sergunb 0:8918a71cdbe9 442 p += k;
Sergunb 0:8918a71cdbe9 443 n -= k;
Sergunb 0:8918a71cdbe9 444 }
Sergunb 0:8918a71cdbe9 445
Sergunb 0:8918a71cdbe9 446 //Append the 64-bit representation of the length of the AAD and the ciphertext
Sergunb 0:8918a71cdbe9 447 memset(b, 0, 16);
Sergunb 0:8918a71cdbe9 448 STORE32BE(aLen * 8, b + 4);
Sergunb 0:8918a71cdbe9 449 STORE32BE(length * 8, b + 12);
Sergunb 0:8918a71cdbe9 450
Sergunb 0:8918a71cdbe9 451 //The GHASH function is applied to the result to produce a single output block S
Sergunb 0:8918a71cdbe9 452 gcmXorBlock(s, s, b, 16);
Sergunb 0:8918a71cdbe9 453 gcmMul(context, s);
Sergunb 0:8918a71cdbe9 454
Sergunb 0:8918a71cdbe9 455 //Let R = MSB(GCTR(J(0), S)
Sergunb 0:8918a71cdbe9 456 gcmXorBlock(r, r, s, tLen);
Sergunb 0:8918a71cdbe9 457
Sergunb 0:8918a71cdbe9 458 //The calculated tag is bitwise compared to the received tag. The
Sergunb 0:8918a71cdbe9 459 //message is authenticated if and only if the tags match
Sergunb 0:8918a71cdbe9 460 if(memcmp(r, t, tLen))
Sergunb 0:8918a71cdbe9 461 return ERROR_FAILURE;
Sergunb 0:8918a71cdbe9 462
Sergunb 0:8918a71cdbe9 463 //Successful decryption
Sergunb 0:8918a71cdbe9 464 return NO_ERROR;
Sergunb 0:8918a71cdbe9 465 }
Sergunb 0:8918a71cdbe9 466
Sergunb 0:8918a71cdbe9 467
Sergunb 0:8918a71cdbe9 468 /**
Sergunb 0:8918a71cdbe9 469 * @brief Multiplication operation
Sergunb 0:8918a71cdbe9 470 * @param[in] context Pointer to the GCM context
Sergunb 0:8918a71cdbe9 471 * @param[in, out] x 16-byte block to be multiplied by H
Sergunb 0:8918a71cdbe9 472 **/
Sergunb 0:8918a71cdbe9 473
Sergunb 0:8918a71cdbe9 474 void gcmMul(GcmContext *context, uint8_t *x)
Sergunb 0:8918a71cdbe9 475 {
Sergunb 0:8918a71cdbe9 476 int_t i;
Sergunb 0:8918a71cdbe9 477 uint8_t b;
Sergunb 0:8918a71cdbe9 478 uint8_t c;
Sergunb 0:8918a71cdbe9 479 uint32_t z[4];
Sergunb 0:8918a71cdbe9 480
Sergunb 0:8918a71cdbe9 481 //Let Z = 0
Sergunb 0:8918a71cdbe9 482 z[0] = 0;
Sergunb 0:8918a71cdbe9 483 z[1] = 0;
Sergunb 0:8918a71cdbe9 484 z[2] = 0;
Sergunb 0:8918a71cdbe9 485 z[3] = 0;
Sergunb 0:8918a71cdbe9 486
Sergunb 0:8918a71cdbe9 487 //Fast table-driven implementation
Sergunb 0:8918a71cdbe9 488 for(i = 15; i >= 0; i--)
Sergunb 0:8918a71cdbe9 489 {
Sergunb 0:8918a71cdbe9 490 //Process the lower nibble
Sergunb 0:8918a71cdbe9 491 b = x[i] & 0x0F;
Sergunb 0:8918a71cdbe9 492
Sergunb 0:8918a71cdbe9 493 c = z[0] & 0x0F;
Sergunb 0:8918a71cdbe9 494 z[0] = (z[0] >> 4) | (z[1] << 28);
Sergunb 0:8918a71cdbe9 495 z[1] = (z[1] >> 4) | (z[2] << 28);
Sergunb 0:8918a71cdbe9 496 z[2] = (z[2] >> 4) | (z[3] << 28);
Sergunb 0:8918a71cdbe9 497 z[3] >>= 4;
Sergunb 0:8918a71cdbe9 498
Sergunb 0:8918a71cdbe9 499 z[3] ^= r[c];
Sergunb 0:8918a71cdbe9 500
Sergunb 0:8918a71cdbe9 501 z[0] ^= context->m[b][0];
Sergunb 0:8918a71cdbe9 502 z[1] ^= context->m[b][1];
Sergunb 0:8918a71cdbe9 503 z[2] ^= context->m[b][2];
Sergunb 0:8918a71cdbe9 504 z[3] ^= context->m[b][3];
Sergunb 0:8918a71cdbe9 505
Sergunb 0:8918a71cdbe9 506 //Process the upper nibble
Sergunb 0:8918a71cdbe9 507 b = (x[i] >> 4) & 0x0F;
Sergunb 0:8918a71cdbe9 508
Sergunb 0:8918a71cdbe9 509 c = z[0] & 0x0F;
Sergunb 0:8918a71cdbe9 510 z[0] = (z[0] >> 4) | (z[1] << 28);
Sergunb 0:8918a71cdbe9 511 z[1] = (z[1] >> 4) | (z[2] << 28);
Sergunb 0:8918a71cdbe9 512 z[2] = (z[2] >> 4) | (z[3] << 28);
Sergunb 0:8918a71cdbe9 513 z[3] >>= 4;
Sergunb 0:8918a71cdbe9 514
Sergunb 0:8918a71cdbe9 515 z[3] ^= r[c];
Sergunb 0:8918a71cdbe9 516
Sergunb 0:8918a71cdbe9 517 z[0] ^= context->m[b][0];
Sergunb 0:8918a71cdbe9 518 z[1] ^= context->m[b][1];
Sergunb 0:8918a71cdbe9 519 z[2] ^= context->m[b][2];
Sergunb 0:8918a71cdbe9 520 z[3] ^= context->m[b][3];
Sergunb 0:8918a71cdbe9 521 }
Sergunb 0:8918a71cdbe9 522
Sergunb 0:8918a71cdbe9 523 //Save the result
Sergunb 0:8918a71cdbe9 524 STORE32BE(z[3], x);
Sergunb 0:8918a71cdbe9 525 STORE32BE(z[2], x + 4);
Sergunb 0:8918a71cdbe9 526 STORE32BE(z[1], x + 8);
Sergunb 0:8918a71cdbe9 527 STORE32BE(z[0], x + 12);
Sergunb 0:8918a71cdbe9 528 }
Sergunb 0:8918a71cdbe9 529
Sergunb 0:8918a71cdbe9 530
Sergunb 0:8918a71cdbe9 531 /**
Sergunb 0:8918a71cdbe9 532 * @brief XOR operation
Sergunb 0:8918a71cdbe9 533 * @param[out] x Block resulting from the XOR operation
Sergunb 0:8918a71cdbe9 534 * @param[in] a First block
Sergunb 0:8918a71cdbe9 535 * @param[in] b Second block
Sergunb 0:8918a71cdbe9 536 * @param[in] n Size of the block
Sergunb 0:8918a71cdbe9 537 **/
Sergunb 0:8918a71cdbe9 538
Sergunb 0:8918a71cdbe9 539 void gcmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
Sergunb 0:8918a71cdbe9 540 {
Sergunb 0:8918a71cdbe9 541 size_t i;
Sergunb 0:8918a71cdbe9 542
Sergunb 0:8918a71cdbe9 543 //Perform XOR operation
Sergunb 0:8918a71cdbe9 544 for(i = 0; i < n; i++)
Sergunb 0:8918a71cdbe9 545 x[i] = a[i] ^ b[i];
Sergunb 0:8918a71cdbe9 546 }
Sergunb 0:8918a71cdbe9 547
Sergunb 0:8918a71cdbe9 548
Sergunb 0:8918a71cdbe9 549 /**
Sergunb 0:8918a71cdbe9 550 * @brief Increment counter block
Sergunb 0:8918a71cdbe9 551 * @param[in,out] x Pointer to the counter block
Sergunb 0:8918a71cdbe9 552 **/
Sergunb 0:8918a71cdbe9 553
Sergunb 0:8918a71cdbe9 554 void gcmIncCounter(uint8_t *x)
Sergunb 0:8918a71cdbe9 555 {
Sergunb 0:8918a71cdbe9 556 size_t i;
Sergunb 0:8918a71cdbe9 557
Sergunb 0:8918a71cdbe9 558 //The function increments the right-most 32 bits of the block. The remaining
Sergunb 0:8918a71cdbe9 559 //left-most 96 bits remain unchanged
Sergunb 0:8918a71cdbe9 560 for(i = 0; i < 4; i++)
Sergunb 0:8918a71cdbe9 561 {
Sergunb 0:8918a71cdbe9 562 //Increment the current byte and propagate the carry if necessary
Sergunb 0:8918a71cdbe9 563 if(++(x[15 - i]) != 0)
Sergunb 0:8918a71cdbe9 564 break;
Sergunb 0:8918a71cdbe9 565 }
Sergunb 0:8918a71cdbe9 566 }
Sergunb 0:8918a71cdbe9 567
Sergunb 0:8918a71cdbe9 568 #endif
Sergunb 0:8918a71cdbe9 569