cmac.c
Go to the documentation of this file.
1 /**
2  * @file cmac.c
3  * @brief CMAC (Cipher-based 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  * CMAC is a block cipher-based MAC algorithm specified in NIST SP 800-38B
28  *
29  * @author Oryx Embedded SARL (www.oryx-embedded.com)
30  * @version 1.9.0
31  **/
32 
33 //Switch to the appropriate trace level
34 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
35 
36 //Dependencies
37 #include "core/crypto.h"
38 #include "mac/cmac.h"
39 
40 //Check crypto library configuration
41 #if (CMAC_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Compute CMAC using the specified cipher algorithm
46  * @param[in] cipher Cipher algorithm used to compute CMAC
47  * @param[in] key Pointer to the secret key
48  * @param[in] keyLen Length of the secret key
49  * @param[in] data Pointer to the input message
50  * @param[in] dataLen Length of the input data
51  * @param[out] mac Calculated MAC value
52  * @param[in] macLen Expected length of the MAC
53  * @return Error code
54  **/
55 
56 error_t cmacCompute(const CipherAlgo *cipher, const void *key, size_t keyLen,
57  const void *data, size_t dataLen, uint8_t *mac, size_t macLen)
58 {
59  error_t error;
60  CmacContext *context;
61 
62  //Allocate a memory buffer to hold the CMAC context
63  context = cryptoAllocMem(sizeof(CmacContext));
64 
65  //Successful memory allocation?
66  if(context != NULL)
67  {
68  //Initialize the CMAC context
69  error = cmacInit(context, cipher, key, keyLen);
70 
71  //Check status code
72  if(!error)
73  {
74  //Digest the message
75  cmacUpdate(context, data, dataLen);
76  //Finalize the CMAC computation
77  error = cmacFinal(context, mac, macLen);
78  }
79 
80  //Free previously allocated memory
81  cryptoFreeMem(context);
82  }
83  else
84  {
85  //Failed to allocate memory
86  error = ERROR_OUT_OF_MEMORY;
87  }
88 
89  //Return status code
90  return error;
91 }
92 
93 
94 /**
95  * @brief Initialize CMAC calculation
96  * @param[in] context Pointer to the CMAC context to initialize
97  * @param[in] cipher Cipher algorithm used to compute CMAC
98  * @param[in] key Pointer to the secret key
99  * @param[in] keyLen Length of the secret key
100  * @return Error code
101  **/
102 
103 error_t cmacInit(CmacContext *context, const CipherAlgo *cipher,
104  const void *key, size_t keyLen)
105 {
106  error_t error;
107  uint8_t rb;
108 
109  //CMAC supports only block ciphers whose block size is 64 or 128 bits
110  if(cipher->type != CIPHER_ALGO_TYPE_BLOCK)
112 
113  //Rb is completely determined by the number of bits in a block
114  if(cipher->blockSize == 8)
115  {
116  //If b = 64, then Rb = 11011
117  rb = 0x1B;
118  }
119  else if(cipher->blockSize == 16)
120  {
121  //If b = 128, then Rb = 10000111
122  rb = 0x87;
123  }
124  else
125  {
126  //Invalid block size
128  }
129 
130  //Cipher algorithm used to compute CMAC
131  context->cipher = cipher;
132 
133  //Initialize cipher context
134  error = cipher->init(context->cipherContext, key, keyLen);
135  //Any error to report?
136  if(error)
137  return error;
138 
139  //Let L = 0
140  cryptoMemset(context->buffer, 0, cipher->blockSize);
141  //Compute L = CIPH(L)
142  cipher->encryptBlock(context->cipherContext, context->buffer, context->buffer);
143 
144  //The subkey K1 is obtained by multiplying L by x in GF(2^b)
145  cmacMul(context->k1, context->buffer, cipher->blockSize, rb);
146  //The subkey K2 is obtained by multiplying L by x^2 in GF(2^b)
147  cmacMul(context->k2, context->k1, cipher->blockSize, rb);
148 
149  //Reset CMAC context
150  cmacReset(context);
151 
152  //Successful initialization
153  return NO_ERROR;
154 }
155 
156 
157 /**
158  * @brief Reset CMAC context
159  * @param[in] context Pointer to the CMAC context
160  **/
161 
162 void cmacReset(CmacContext *context)
163 {
164  //Clear input buffer
165  cryptoMemset(context->buffer, 0, context->cipher->blockSize);
166  //Number of bytes in the buffer
167  context->bufferLength = 0;
168 
169  //Initialize MAC value
170  cryptoMemset(context->mac, 0, context->cipher->blockSize);
171 }
172 
173 
174 /**
175  * @brief Update the CMAC context with a portion of the message being hashed
176  * @param[in] context Pointer to the CMAC context
177  * @param[in] data Pointer to the input data
178  * @param[in] dataLen Length of the buffer
179  **/
180 
181 void cmacUpdate(CmacContext *context, const void *data, size_t dataLen)
182 {
183  size_t n;
184 
185  //Process the incoming data
186  while(dataLen > 0)
187  {
188  //Process message block by block
189  if(context->bufferLength == context->cipher->blockSize)
190  {
191  //XOR M(i) with C(i-1)
192  cmacXorBlock(context->buffer, context->buffer, context->mac,
193  context->cipher->blockSize);
194 
195  //Compute C(i) = CIPH(M(i) ^ C(i-1))
196  context->cipher->encryptBlock(context->cipherContext, context->buffer,
197  context->mac);
198 
199  //Empty the buffer
200  context->bufferLength = 0;
201  }
202 
203  //The message is partitioned into complete blocks
204  n = MIN(dataLen, context->cipher->blockSize - context->bufferLength);
205 
206  //Copy the data to the buffer
207  cryptoMemcpy(context->buffer + context->bufferLength, data, n);
208  //Update the length of the buffer
209  context->bufferLength += n;
210 
211  //Advance the data pointer
212  data = (uint8_t *) data + n;
213  //Remaining bytes to process
214  dataLen -= n;
215  }
216 }
217 
218 
219 /**
220  * @brief Finish the CMAC calculation
221  * @param[in] context Pointer to the CMAC context
222  * @param[out] mac Calculated MAC value
223  * @param[in] macLen Expected length of the MAC
224  * @return Error code
225  **/
226 
227 error_t cmacFinal(CmacContext *context, uint8_t *mac, size_t macLen)
228 {
229  //Check the length of the MAC
230  if(macLen < 1 || macLen > context->cipher->blockSize)
232 
233  //Check whether the last block Mn is complete
234  if(context->bufferLength >= context->cipher->blockSize)
235  {
236  //The final block M(n) is XOR-ed with the first subkey K1
237  cmacXorBlock(context->buffer, context->buffer, context->k1,
238  context->cipher->blockSize);
239  }
240  else
241  {
242  //Append padding string
243  context->buffer[context->bufferLength++] = 0x80;
244 
245  //Append the minimum number of zeroes to form a complete block
246  while(context->bufferLength < context->cipher->blockSize)
247  context->buffer[context->bufferLength++] = 0x00;
248 
249  //The final block M(n) is XOR-ed with the second subkey K2
250  cmacXorBlock(context->buffer, context->buffer, context->k2,
251  context->cipher->blockSize);
252  }
253 
254  //XOR M(n) with C(n-1)
255  cmacXorBlock(context->buffer, context->buffer, context->mac,
256  context->cipher->blockSize);
257 
258  //Compute T = CIPH(M(n) ^ C(n-1))
259  context->cipher->encryptBlock(context->cipherContext, context->buffer,
260  context->mac);
261 
262  //Copy the resulting MAC value
263  if(mac != NULL)
264  {
265  //It is possible to truncate the MAC. The result of the truncation
266  //should be taken in most significant bits first order
267  cryptoMemcpy(mac, context->mac, macLen);
268  }
269 
270  //Successful processing
271  return NO_ERROR;
272 }
273 
274 
275 /**
276  * @brief Multiplication by x in GF(2^128)
277  * @param[out] x Pointer to the output block
278  * @param[out] a Pointer to the input block
279  * @param[in] n Size of the block, in bytes
280  * @param[in] rb Representation of the irreducible binary polynomial
281  **/
282 
283 void cmacMul(uint8_t *x, const uint8_t *a, size_t n, uint8_t rb)
284 {
285  size_t i;
286  uint8_t c;
287 
288  //Save the value of the most significant bit
289  c = a[0] >> 7;
290 
291  //The multiplication of a polynomial by x in GF(2^128) corresponds to a
292  //shift of indices
293  for(i = 0; i < (n - 1); i++)
294  {
295  x[i] = (a[i] << 1) | (a[i + 1] >> 7);
296  }
297 
298  //Shift the last byte of the block to the left
299  x[i] = a[i] << 1;
300 
301  //If the highest term of the result is equal to one, then perform reduction
302  x[i] ^= rb & ~(c - 1);
303 }
304 
305 
306 /**
307  * @brief XOR operation
308  * @param[out] x Block resulting from the XOR operation
309  * @param[in] a First input block
310  * @param[in] b Second input block
311  * @param[in] n Size of the block, in bytes
312  **/
313 
314 void cmacXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
315 {
316  size_t i;
317 
318  //Perform XOR operation
319  for(i = 0; i < n; i++)
320  {
321  x[i] = a[i] ^ b[i];
322  }
323 }
324 
325 #endif
uint8_t k2[MAX_CIPHER_BLOCK_SIZE]
Definition: cmac.h:100
uint8_t mac[MAX_CIPHER_BLOCK_SIZE]
Definition: cmac.h:103
uint8_t c
Definition: ndp.h:510
#define cryptoMemcpy(dest, src, length)
Definition: crypto.h:590
#define cryptoFreeMem(p)
Definition: crypto.h:578
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1082
#define cryptoAllocMem(size)
Definition: crypto.h:573
General definitions for cryptographic algorithms.
Invalid parameter.
Definition: error.h:45
Common interface for encryption algorithms.
Definition: crypto.h:1073
void cmacXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
XOR operation.
Definition: cmac.c:314
error_t cmacCompute(const CipherAlgo *cipher, const void *key, size_t keyLen, const void *data, size_t dataLen, uint8_t *mac, size_t macLen)
Compute CMAC using the specified cipher algorithm.
Definition: cmac.c:56
uint8_t a
Definition: ndp.h:407
CMAC (Cipher-based Message Authentication Code)
size_t blockSize
Definition: crypto.h:1078
CipherAlgoInit init
Definition: crypto.h:1079
void cmacReset(CmacContext *context)
Reset CMAC context.
Definition: cmac.c:162
#define MIN(a, b)
Definition: os_port.h:60
void cmacUpdate(CmacContext *context, const void *data, size_t dataLen)
Update the CMAC context with a portion of the message being hashed.
Definition: cmac.c:181
uint8_t cipherContext[MAX_CIPHER_CONTEXT_SIZE]
Definition: cmac.h:98
Success.
Definition: error.h:42
error_t
Error codes.
Definition: error.h:40
uint8_t data[]
Definition: dtls_misc.h:167
error_t cmacFinal(CmacContext *context, uint8_t *mac, size_t macLen)
Finish the CMAC calculation.
Definition: cmac.c:227
size_t bufferLength
Definition: cmac.h:102
void cmacMul(uint8_t *x, const uint8_t *a, size_t n, uint8_t rb)
Multiplication by x in GF(2^128)
Definition: cmac.c:283
uint8_t buffer[MAX_CIPHER_BLOCK_SIZE]
Definition: cmac.h:101
CipherAlgoType type
Definition: crypto.h:1077
#define cryptoMemset(p, value, length)
Definition: crypto.h:584
uint8_t n
const CipherAlgo * cipher
Definition: cmac.h:97
error_t cmacInit(CmacContext *context, const CipherAlgo *cipher, const void *key, size_t keyLen)
Initialize CMAC calculation.
Definition: cmac.c:103
CMAC algorithm context.
Definition: cmac.h:95
uint8_t b[6]
Definition: dtls_misc.h:130
uint8_t k1[MAX_CIPHER_BLOCK_SIZE]
Definition: cmac.h:99