gmac.c
Go to the documentation of this file.
1 /**
2  * @file gmac.c
3  * @brief GMAC (Galois Message Authentication Code)
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneCrypto Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @section Description
26  *
27  * GMAC is a message authentication code (MAC) based on GCM. Refer to
28  * SP 800-38D for more details
29  *
30  * @author Oryx Embedded SARL (www.oryx-embedded.com)
31  * @version 1.9.0
32  **/
33 
34 //Switch to the appropriate trace level
35 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
36 
37 //Dependencies
38 #include "core/crypto.h"
39 #include "mac/gmac.h"
40 
41 //Check crypto library configuration
42 #if (GMAC_SUPPORT == ENABLED)
43 
44 //Reduction table
45 static const uint32_t r[16] =
46 {
47  0x00000000,
48  0x1C200000,
49  0x38400000,
50  0x24600000,
51  0x70800000,
52  0x6CA00000,
53  0x48C00000,
54  0x54E00000,
55  0xE1000000,
56  0xFD200000,
57  0xD9400000,
58  0xC5600000,
59  0x91800000,
60  0x8DA00000,
61  0xA9C00000,
62  0xB5E00000
63 };
64 
65 
66 /**
67  * @brief Compute GMAC using the specified cipher algorithm
68  * @param[in] cipher Cipher algorithm used to compute GMAC
69  * @param[in] key Pointer to the secret key
70  * @param[in] keyLen Length of the secret key
71  * @param[in] iv Initialization vector
72  * @param[in] ivLen Length of the initialization vector
73  * @param[in] data Pointer to the input message
74  * @param[in] dataLen Length of the input data
75  * @param[out] mac Calculated MAC value
76  * @param[in] macLen Expected length of the MAC
77  * @return Error code
78  **/
79 
80 error_t gmacCompute(const CipherAlgo *cipher, const void *key, size_t keyLen,
81  const uint8_t *iv, size_t ivLen, const void *data, size_t dataLen,
82  uint8_t *mac, size_t macLen)
83 {
84  error_t error;
85  GmacContext *context;
86 
87  //Allocate a memory buffer to hold the GMAC context
88  context = cryptoAllocMem(sizeof(GmacContext));
89 
90  //Successful memory allocation?
91  if(context != NULL)
92  {
93  //Initialize the GMAC context
94  error = gmacInit(context, cipher, key, keyLen);
95 
96  //Check status code
97  if(!error)
98  {
99  //Reset GMAC context
100  error = gmacReset(context, iv, ivLen);
101  }
102 
103  //Check status code
104  if(!error)
105  {
106  //Digest the message
107  gmacUpdate(context, data, dataLen);
108  //Finalize the GMAC computation
109  error = gmacFinal(context, mac, macLen);
110  }
111 
112  //Free previously allocated memory
113  cryptoFreeMem(context);
114  }
115  else
116  {
117  //Failed to allocate memory
118  error = ERROR_OUT_OF_MEMORY;
119  }
120 
121  //Return status code
122  return error;
123 }
124 
125 
126 /**
127  * @brief Initialize GMAC calculation
128  * @param[in] context Pointer to the GMAC context to initialize
129  * @param[in] cipher Cipher algorithm used to compute GMAC
130  * @param[in] key Pointer to the secret key
131  * @param[in] keyLen Length of the secret key
132  * @return Error code
133  **/
134 
135 error_t gmacInit(GmacContext *context, const CipherAlgo *cipher,
136  const void *key, size_t keyLen)
137 {
138  error_t error;
139  uint_t i;
140  uint_t j;
141  uint32_t c;
142  uint32_t h[4];
143 
144  //GMAC supports only symmetric block ciphers whose block size is 128 bits
145  if(cipher->type != CIPHER_ALGO_TYPE_BLOCK || cipher->blockSize != 16)
147 
148  //Cipher algorithm used to compute GMAC
149  context->cipher = cipher;
150 
151  //Initialize cipher context
152  error = cipher->init(context->cipherContext, key, keyLen);
153  //Any error to report?
154  if(error)
155  return error;
156 
157  //Let H = 0
158  h[0] = 0;
159  h[1] = 0;
160  h[2] = 0;
161  h[3] = 0;
162 
163  //Generate the hash subkey H
164  context->cipher->encryptBlock(context->cipherContext,
165  (uint8_t *) h, (uint8_t *) h);
166 
167  //Pre-compute M(0) = H * 0
168  j = reverseInt4(0);
169  context->m[j][0] = 0;
170  context->m[j][1] = 0;
171  context->m[j][2] = 0;
172  context->m[j][3] = 0;
173 
174  //Pre-compute M(1) = H * 1
175  j = reverseInt4(1);
176  context->m[j][0] = betoh32(h[3]);
177  context->m[j][1] = betoh32(h[2]);
178  context->m[j][2] = betoh32(h[1]);
179  context->m[j][3] = betoh32(h[0]);
180 
181  //Pre-compute all 4-bit multiples of H
182  for(i = 2; i < 16; i++)
183  {
184  //Odd value?
185  if(i & 1)
186  {
187  //Compute M(i) = M(i - 1) + H
188  j = reverseInt4(i - 1);
189  h[0] = context->m[j][0];
190  h[1] = context->m[j][1];
191  h[2] = context->m[j][2];
192  h[3] = context->m[j][3];
193 
194  //An addition in GF(2^128) is identical to a bitwise
195  //exclusive-OR operation
196  j = reverseInt4(1);
197  h[0] ^= context->m[j][0];
198  h[1] ^= context->m[j][1];
199  h[2] ^= context->m[j][2];
200  h[3] ^= context->m[j][3];
201  }
202  //Even value?
203  else
204  {
205  //Compute M(i) = M(i / 2) * x
206  j = reverseInt4(i / 2);
207  h[0] = context->m[j][0];
208  h[1] = context->m[j][1];
209  h[2] = context->m[j][2];
210  h[3] = context->m[j][3];
211 
212  //The multiplication of a polynomial by x in GF(2^128) corresponds
213  //to a shift of indices
214  c = h[0] & 0x01;
215  h[0] = (h[0] >> 1) | (h[1] << 31);
216  h[1] = (h[1] >> 1) | (h[2] << 31);
217  h[2] = (h[2] >> 1) | (h[3] << 31);
218  h[3] >>= 1;
219 
220  //If the highest term of the result is equal to one, then perform
221  //reduction
222  h[3] ^= r[reverseInt4(1)] & ~(c - 1);
223  }
224 
225  //Save M(i)
226  j = reverseInt4(i);
227  context->m[j][0] = h[0];
228  context->m[j][1] = h[1];
229  context->m[j][2] = h[2];
230  context->m[j][3] = h[3];
231  }
232 
233  //Clear input buffer
234  cryptoMemset(context->buffer, 0, context->cipher->blockSize);
235  //Number of bytes in the buffer
236  context->bufferLength = 0;
237  //Total number of bytes
238  context->totalLength = 0;
239 
240  //Initialize MAC value
241  cryptoMemset(context->mac, 0, context->cipher->blockSize);
242 
243  //Successful initialization
244  return NO_ERROR;
245 }
246 
247 
248 /**
249  * @brief Reset GMAC context
250  * @param[in] context Pointer to the GMAC context
251  * @param[in] iv Initialization vector
252  * @param[in] ivLen Length of the initialization vector
253  * @return Error code
254  **/
255 
256 error_t gmacReset(GmacContext *context, const uint8_t *iv, size_t ivLen)
257 {
258  size_t k;
259  size_t n;
260  uint8_t b[16];
261  uint8_t j[16];
262 
263  //The length of the IV shall meet SP 800-38D requirements
264  if(ivLen < 1)
266 
267  //Check whether the length of the IV is 96 bits
268  if(ivLen == 12)
269  {
270  //When the length of the IV is 96 bits, the padding string is
271  //appended to the IV to form the pre-counter block
272  cryptoMemcpy(j, iv, 12);
273  STORE32BE(1, j + 12);
274  }
275  else
276  {
277  //Initialize GHASH calculation
278  cryptoMemset(j, 0, 16);
279 
280  //Length of the IV
281  n = ivLen;
282 
283  //Process the initialization vector
284  while(n > 0)
285  {
286  //The IV processed in a block-by-block fashion
287  k = MIN(n, 16);
288 
289  //Apply GHASH function
290  gmacXorBlock(j, j, iv, k);
291  gmacMul(context, j);
292 
293  //Next block
294  iv += k;
295  n -= k;
296  }
297 
298  //The string is appended with 64 additional 0 bits, followed by the
299  //64-bit representation of the length of the IV
300  cryptoMemset(b, 0, 8);
301  STORE64BE(ivLen * 8, b + 8);
302 
303  //The GHASH function is applied to the resulting string to form the
304  //pre-counter block
305  gmacXorBlock(j, j, b, 16);
306  gmacMul(context, j);
307  }
308 
309  //Compute MSB(CIPH(J(0)))
310  context->cipher->encryptBlock(context->cipherContext, j, b);
311  cryptoMemcpy(context->mac, b, 16);
312 
313  //Initialize GHASH calculation
314  cryptoMemset(context->s, 0, 16);
315 
316  //Clear input buffer
317  cryptoMemset(context->buffer, 0, context->cipher->blockSize);
318  //Number of bytes in the buffer
319  context->bufferLength = 0;
320 
321  //Successful processing
322  return NO_ERROR;
323 }
324 
325 
326 /**
327  * @brief Update the GMAC context with a portion of the message being hashed
328  * @param[in] context Pointer to the GMAC context
329  * @param[in] data Pointer to the input data
330  * @param[in] dataLen Length of the buffer
331  **/
332 
333 void gmacUpdate(GmacContext *context, const void *data, size_t dataLen)
334 {
335  size_t n;
336 
337  //Process the incoming data
338  while(dataLen > 0)
339  {
340  //The message is partitioned into complete blocks
341  n = MIN(dataLen, 16 - context->bufferLength);
342 
343  //Copy the data to the buffer
344  cryptoMemcpy(context->buffer + context->bufferLength, data, n);
345  //Update the length of the buffer
346  context->bufferLength += n;
347  //Update the total number of bytes
348  context->totalLength += n;
349 
350  //Advance the data pointer
351  data = (uint8_t *) data + n;
352  //Remaining bytes to process
353  dataLen -= n;
354 
355  //Process message block by block
356  if(context->bufferLength == 16)
357  {
358  //Apply GHASH function
359  gmacXorBlock(context->s, context->s, context->buffer, 16);
360  gmacMul(context, context->s);
361 
362  //Empty the buffer
363  context->bufferLength = 0;
364  }
365  }
366 }
367 
368 
369 /**
370  * @brief Finish the GMAC calculation
371  * @param[in] context Pointer to the GMAC context
372  * @param[out] mac Calculated MAC value
373  * @param[in] macLen Expected length of the MAC
374  **/
375 
376 error_t gmacFinal(GmacContext *context, uint8_t *mac, size_t macLen)
377 {
378  //Check the length of the MAC
379  if(macLen < 4 || macLen > 16)
381 
382  //Process the last block of the message
383  if(context->bufferLength > 0)
384  {
385  //Apply GHASH function
386  gmacXorBlock(context->s, context->s, context->buffer, context->bufferLength);
387  gmacMul(context, context->s);
388  }
389 
390  //Append the 64-bit representation of the length of the message followed
391  //by 64 additional 0 bits
392  STORE64BE(context->totalLength * 8, context->buffer);
393  cryptoMemset(context->buffer + 8, 0, 8);
394 
395  //The GHASH function is applied to the result to produce a single output block S
396  gmacXorBlock(context->s, context->s, context->buffer, 16);
397  gmacMul(context, context->s);
398 
399  //Let T = GCTR(J(0), S)
400  gmacXorBlock(context->mac, context->mac, context->s, 16);
401 
402  //Copy the resulting MAC value
403  if(mac != NULL)
404  {
405  //Output MSB(T)
406  cryptoMemcpy(mac, context->mac, macLen);
407  }
408 
409  //Successful processing
410  return NO_ERROR;
411 }
412 
413 
414 /**
415  * @brief Multiplication operation in GF(2^128)
416  * @param[in] context Pointer to the GMAC context
417  * @param[in, out] x 16-byte block to be multiplied by H
418  **/
419 
420 void gmacMul(GmacContext *context, uint8_t *x)
421 {
422  int_t i;
423  uint8_t b;
424  uint8_t c;
425  uint32_t z[4];
426 
427  //Let Z = 0
428  z[0] = 0;
429  z[1] = 0;
430  z[2] = 0;
431  z[3] = 0;
432 
433  //Fast table-driven implementation
434  for(i = 15; i >= 0; i--)
435  {
436  //Get the lower nibble
437  b = x[i] & 0x0F;
438 
439  //Multiply 4 bits at a time
440  c = z[0] & 0x0F;
441  z[0] = (z[0] >> 4) | (z[1] << 28);
442  z[1] = (z[1] >> 4) | (z[2] << 28);
443  z[2] = (z[2] >> 4) | (z[3] << 28);
444  z[3] >>= 4;
445 
446  z[0] ^= context->m[b][0];
447  z[1] ^= context->m[b][1];
448  z[2] ^= context->m[b][2];
449  z[3] ^= context->m[b][3];
450 
451  //Perform reduction
452  z[3] ^= r[c];
453 
454  //Get the upper nibble
455  b = (x[i] >> 4) & 0x0F;
456 
457  //Multiply 4 bits at a time
458  c = z[0] & 0x0F;
459  z[0] = (z[0] >> 4) | (z[1] << 28);
460  z[1] = (z[1] >> 4) | (z[2] << 28);
461  z[2] = (z[2] >> 4) | (z[3] << 28);
462  z[3] >>= 4;
463 
464  z[0] ^= context->m[b][0];
465  z[1] ^= context->m[b][1];
466  z[2] ^= context->m[b][2];
467  z[3] ^= context->m[b][3];
468 
469  //Perform reduction
470  z[3] ^= r[c];
471  }
472 
473  //Save the result
474  STORE32BE(z[3], x);
475  STORE32BE(z[2], x + 4);
476  STORE32BE(z[1], x + 8);
477  STORE32BE(z[0], x + 12);
478 }
479 
480 
481 /**
482  * @brief XOR operation
483  * @param[out] x Block resulting from the XOR operation
484  * @param[in] a First block
485  * @param[in] b Second block
486  * @param[in] n Size of the block
487  **/
488 
489 void gmacXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
490 {
491  size_t i;
492 
493  //Perform XOR operation
494  for(i = 0; i < n; i++)
495  {
496  x[i] = a[i] ^ b[i];
497  }
498 }
499 
500 
501 /**
502  * @brief Increment counter block
503  * @param[in,out] x Pointer to the counter block
504  **/
505 
506 void gmacIncCounter(uint8_t *x)
507 {
508  size_t i;
509 
510  //The function increments the right-most 32 bits of the block. The remaining
511  //left-most 96 bits remain unchanged
512  for(i = 0; i < 4; i++)
513  {
514  //Increment the current byte and propagate the carry if necessary
515  if(++(x[15 - i]) != 0)
516  {
517  break;
518  }
519  }
520 }
521 
522 #endif
#define STORE64BE(a, p)
Definition: cpu_endian.h:304
uint8_t buffer[16]
Definition: gmac.h:101
uint8_t c
Definition: ndp.h:510
#define cryptoMemcpy(dest, src, length)
Definition: crypto.h:590
#define cryptoFreeMem(p)
Definition: crypto.h:578
uint32_t m[16][4]
Definition: gmac.h:99
GMAC algorithm context.
Definition: gmac.h:95
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1082
#define cryptoAllocMem(size)
Definition: crypto.h:573
General definitions for cryptographic algorithms.
Invalid parameter.
Definition: error.h:45
GMAC (Galois Message Authentication Code)
Common interface for encryption algorithms.
Definition: crypto.h:1073
error_t gmacFinal(GmacContext *context, uint8_t *mac, size_t macLen)
Finish the GMAC calculation.
Definition: gmac.c:376
uint16_t z
Definition: dns_common.h:173
#define betoh32(value)
Definition: cpu_endian.h:428
uint8_t a
Definition: ndp.h:407
size_t blockSize
Definition: crypto.h:1078
CipherAlgoInit init
Definition: crypto.h:1079
uint8_t mac[16]
Definition: gmac.h:104
#define STORE32BE(a, p)
Definition: cpu_endian.h:268
signed int int_t
Definition: compiler_port.h:42
void gmacXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
XOR operation.
Definition: gmac.c:489
void gmacMul(GmacContext *context, uint8_t *x)
Multiplication operation in GF(2^128)
Definition: gmac.c:420
uint8_t cipherContext[MAX_CIPHER_CONTEXT_SIZE]
Definition: gmac.h:98
#define MIN(a, b)
Definition: os_port.h:60
uint64_t totalLength
Definition: gmac.h:103
Success.
Definition: error.h:42
error_t
Error codes.
Definition: error.h:40
error_t gmacReset(GmacContext *context, const uint8_t *iv, size_t ivLen)
Reset GMAC context.
Definition: gmac.c:256
void gmacIncCounter(uint8_t *x)
Increment counter block.
Definition: gmac.c:506
size_t bufferLength
Definition: gmac.h:102
unsigned int uint_t
Definition: compiler_port.h:43
error_t gmacCompute(const CipherAlgo *cipher, const void *key, size_t keyLen, const uint8_t *iv, size_t ivLen, const void *data, size_t dataLen, uint8_t *mac, size_t macLen)
Compute GMAC using the specified cipher algorithm.
Definition: gmac.c:80
uint8_t data[]
Definition: dtls_misc.h:167
uint32_t r
Definition: ndp.h:342
uint8_t reverseInt4(uint8_t value)
Reverse bit order in a 4-bit word.
Definition: cpu_endian.c:73
const CipherAlgo * cipher
Definition: gmac.h:97
CipherAlgoType type
Definition: crypto.h:1077
#define cryptoMemset(p, value, length)
Definition: crypto.h:584
uint8_t n
uint8_t h
Definition: ndp.h:297
uint8_t s[16]
Definition: gmac.h:100
void gmacUpdate(GmacContext *context, const void *data, size_t dataLen)
Update the GMAC context with a portion of the message being hashed.
Definition: gmac.c:333
uint8_t b[6]
Definition: dtls_misc.h:130
error_t gmacInit(GmacContext *context, const CipherAlgo *cipher, const void *key, size_t keyLen)
Initialize GMAC calculation.
Definition: gmac.c:135