xcbc_mac.c
Go to the documentation of this file.
1 /**
2  * @file xcbc_mac.c
3  * @brief XCBC-MAC message authentication code
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * XCBC-MAC is a block cipher-based MAC algorithm specified in NIST SP 800-38B
30  *
31  * @author Oryx Embedded SARL (www.oryx-embedded.com)
32  * @version 2.4.4
33  **/
34 
35 //Switch to the appropriate trace level
36 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
37 
38 //Dependencies
39 #include "core/crypto.h"
40 #include "mac/xcbc_mac.h"
41 
42 //Check crypto library configuration
43 #if (XCBC_MAC_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Compute XCBC-MAC using the specified cipher algorithm
48  * @param[in] cipher Cipher algorithm used to compute XCBC-MAC
49  * @param[in] key Pointer to the secret key
50  * @param[in] keyLen Length of the secret key
51  * @param[in] data Pointer to the input message
52  * @param[in] dataLen Length of the input data
53  * @param[out] mac Calculated MAC value
54  * @param[in] macLen Expected length of the MAC
55  * @return Error code
56  **/
57 
58 error_t xcbcMacCompute(const CipherAlgo *cipher, const void *key, size_t keyLen,
59  const void *data, size_t dataLen, uint8_t *mac, size_t macLen)
60 {
61  error_t error;
62 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
63  XcbcMacContext *context;
64 #else
65  XcbcMacContext context[1];
66 #endif
67 
68 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
69  //Allocate a memory buffer to hold the XCBC-MAC context
70  context = cryptoAllocMem(sizeof(XcbcMacContext));
71  //Failed to allocate memory?
72  if(context == NULL)
73  return ERROR_OUT_OF_MEMORY;
74 #endif
75 
76  //Initialize the XCBC-MAC context
77  error = xcbcMacInit(context, cipher, key, keyLen);
78 
79  //Check status code
80  if(!error)
81  {
82  //Digest the message
83  xcbcMacUpdate(context, data, dataLen);
84  //Finalize the XCBC-MAC computation
85  error = xcbcMacFinal(context, mac, macLen);
86  }
87 
88 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
89  //Free previously allocated memory
90  cryptoFreeMem(context);
91 #endif
92 
93  //Return status code
94  return error;
95 }
96 
97 
98 /**
99  * @brief Initialize XCBC-MAC calculation
100  * @param[in] context Pointer to the XCBC-MAC context to initialize
101  * @param[in] cipher Cipher algorithm used to compute XCBC-MAC
102  * @param[in] key Pointer to the secret key
103  * @param[in] keyLen Length of the secret key
104  * @return Error code
105  **/
106 
108  const void *key, size_t keyLen)
109 {
110  error_t error;
111 
112  //Check parameters
113  if(context == NULL || cipher == NULL)
115 
116  //XCBC-MAC uses a block cipher for encryption
117  if(cipher->type != CIPHER_ALGO_TYPE_BLOCK)
119 
120  //Cipher algorithm used to compute XCBC-MAC
121  context->cipher = cipher;
122 
123  //Load the 128-bit secret K
124  error = cipher->init(&context->cipherContext, key, keyLen);
125  //Any error to report?
126  if(error)
127  return error;
128 
129  //Derive three 128-bit keys (K1, K2 and K3) from the 128-bit secret key K
130  osMemset(context->k1, 0x01, cipher->blockSize);
131  osMemset(context->k2, 0x02, cipher->blockSize);
132  osMemset(context->k3, 0x03, cipher->blockSize);
133 
134  //Let K1 = 0x01010101010101010101010101010101 encrypted with key K
135  cipher->encryptBlock(&context->cipherContext, context->k1, context->k1);
136  //Let K2 = 0x02020202020202020202020202020202 encrypted with key K
137  cipher->encryptBlock(&context->cipherContext, context->k2, context->k2);
138  //Let K3 = 0x03030303030303030303030303030303 encrypted with key K
139  cipher->encryptBlock(&context->cipherContext, context->k3, context->k3);
140 
141  //Release cipher context
142  cipher->deinit(&context->cipherContext);
143 
144  //Load the 128-bit secret K1
145  error = cipher->init(&context->cipherContext, context->k1,
146  cipher->blockSize);
147  //Any error to report?
148  if(error)
149  return error;
150 
151  //Reset XCBC-MAC context
152  xcbcMacReset(context);
153 
154  //Successful initialization
155  return NO_ERROR;
156 }
157 
158 
159 /**
160  * @brief Reset XCBC-MAC context
161  * @param[in] context Pointer to the XCBC-MAC context
162  **/
163 
165 {
166  //Clear input buffer
167  osMemset(context->buffer, 0, context->cipher->blockSize);
168  //Number of bytes in the buffer
169  context->bufferLength = 0;
170 
171  //Define E[0] = 0x00000000000000000000000000000000
172  osMemset(context->mac, 0, context->cipher->blockSize);
173 }
174 
175 
176 /**
177  * @brief Update the XCBC-MAC context with a portion of the message being hashed
178  * @param[in] context Pointer to the XCBC-MAC context
179  * @param[in] data Pointer to the input data
180  * @param[in] dataLen Length of the buffer
181  **/
182 
183 void xcbcMacUpdate(XcbcMacContext *context, const void *data, size_t dataLen)
184 {
185  size_t n;
186 
187  //Process the incoming data
188  while(dataLen > 0)
189  {
190  //Process message block by block
191  if(context->bufferLength == context->cipher->blockSize)
192  {
193  //XOR M[i] with E[i-1]
194  xcbcMacXorBlock(context->buffer, context->buffer, context->mac,
195  context->cipher->blockSize);
196 
197  //Then encrypt the result with key K1, yielding E[i]
198  context->cipher->encryptBlock(&context->cipherContext, context->buffer,
199  context->mac);
200 
201  //Empty the buffer
202  context->bufferLength = 0;
203  }
204 
205  //The message is partitioned into complete blocks
206  n = MIN(dataLen, context->cipher->blockSize - context->bufferLength);
207 
208  //Copy the data to the buffer
209  osMemcpy(context->buffer + context->bufferLength, data, n);
210  //Update the length of the buffer
211  context->bufferLength += n;
212 
213  //Advance the data pointer
214  data = (uint8_t *) data + n;
215  //Remaining bytes to process
216  dataLen -= n;
217  }
218 }
219 
220 
221 /**
222  * @brief Finish the XCBC-MAC calculation
223  * @param[in] context Pointer to the XCBC-MAC context
224  * @param[out] mac Calculated MAC value (optional parameter)
225  * @param[in] macLen Expected length of the MAC
226  * @return Error code
227  **/
228 
229 error_t xcbcMacFinal(XcbcMacContext *context, uint8_t *mac, size_t macLen)
230 {
231  //Make sure the XCBC-MAC context is valid
232  if(context == NULL)
234 
235  //Check the length of the MAC
236  if(macLen < 1 || macLen > context->cipher->blockSize)
238 
239  //Check whether the block size of M[n] is 128 bits
240  if(context->bufferLength >= context->cipher->blockSize)
241  {
242  //XOR M[n] with E[n-1] and key K2
243  xcbcMacXorBlock(context->buffer, context->buffer, context->mac,
244  context->cipher->blockSize);
245 
246  xcbcMacXorBlock(context->buffer, context->buffer, context->k2,
247  context->cipher->blockSize);
248 
249  //Then encrypt the result with key K1, yielding E[n]
250  context->cipher->encryptBlock(&context->cipherContext, context->buffer,
251  context->mac);
252  }
253  else
254  {
255  //Pad M[n] with a single "1" bit
256  context->buffer[context->bufferLength++] = 0x80;
257 
258  //Append the number of "0" bits (possibly none) required to increase
259  //M[n]'s block size to 128 bits
260  while(context->bufferLength < context->cipher->blockSize)
261  {
262  context->buffer[context->bufferLength++] = 0x00;
263  }
264 
265  //XOR M[n] with E[n-1] and key K3
266  xcbcMacXorBlock(context->buffer, context->buffer, context->mac,
267  context->cipher->blockSize);
268 
269  xcbcMacXorBlock(context->buffer, context->buffer, context->k3,
270  context->cipher->blockSize);
271 
272  //Then encrypt the result with key K1, yielding E[n]
273  context->cipher->encryptBlock(&context->cipherContext, context->buffer,
274  context->mac);
275  }
276 
277  //Copy the resulting MAC value
278  if(mac != NULL)
279  {
280  //The authenticator value is the leftmost bits of the 128-bit E[n]
281  osMemcpy(mac, context->mac, macLen);
282  }
283 
284  //Successful processing
285  return NO_ERROR;
286 }
287 
288 
289 /**
290  * @brief Release XCBC-MAC context
291  * @param[in] context Pointer to the XCBC-MAC context
292  **/
293 
295 {
296  //Make sure the XCBC-MAC context is valid
297  if(context != NULL)
298  {
299  //Release cipher context
300  context->cipher->deinit(&context->cipherContext);
301 
302  //Clear XCBC-MAC context
303  osMemset(context, 0, sizeof(XcbcMacContext));
304  }
305 }
306 
307 
308 /**
309  * @brief XOR operation
310  * @param[out] x Block resulting from the XOR operation
311  * @param[in] a First input block
312  * @param[in] b Second input block
313  * @param[in] n Size of the block, in bytes
314  **/
315 
316 void xcbcMacXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
317 {
318  size_t i;
319 
320  //Perform XOR operation
321  for(i = 0; i < n; i++)
322  {
323  x[i] = a[i] ^ b[i];
324  }
325 }
326 
327 #endif
XCBC-MAC algorithm context.
Definition: xcbc_mac.h:54
uint8_t k3[MAX_CIPHER_BLOCK_SIZE]
Definition: xcbc_mac.h:59
uint8_t b
Definition: nbns_common.h:104
const CipherAlgo * cipher
Definition: xcbc_mac.h:55
uint8_t a
Definition: ndp.h:411
uint8_t x
Definition: lldp_ext_med.h:211
@ CIPHER_ALGO_TYPE_BLOCK
Definition: crypto.h:953
error_t xcbcMacCompute(const CipherAlgo *cipher, const void *key, size_t keyLen, const void *data, size_t dataLen, uint8_t *mac, size_t macLen)
Compute XCBC-MAC using the specified cipher algorithm.
Definition: xcbc_mac.c:58
uint8_t data[]
Definition: ethernet.h:222
size_t bufferLength
Definition: xcbc_mac.h:61
size_t blockSize
Definition: crypto.h:1072
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
void xcbcMacUpdate(XcbcMacContext *context, const void *data, size_t dataLen)
Update the XCBC-MAC context with a portion of the message being hashed.
Definition: xcbc_mac.c:183
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1076
CipherAlgoInit init
Definition: crypto.h:1073
void xcbcMacXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
XOR operation.
Definition: xcbc_mac.c:316
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
error_t
Error codes.
Definition: error.h:43
XCBC-MAC message authentication code.
void xcbcMacDeinit(XcbcMacContext *context)
Release XCBC-MAC context.
Definition: xcbc_mac.c:294
CipherAlgoType type
Definition: crypto.h:1071
uint8_t k1[MAX_CIPHER_BLOCK_SIZE]
Definition: xcbc_mac.h:57
CipherContext cipherContext
Definition: xcbc_mac.h:56
uint8_t buffer[MAX_CIPHER_BLOCK_SIZE]
Definition: xcbc_mac.h:60
General definitions for cryptographic algorithms.
uint8_t k2[MAX_CIPHER_BLOCK_SIZE]
Definition: xcbc_mac.h:58
#define MIN(a, b)
Definition: os_port.h:63
uint32_t dataLen
Definition: sftp_common.h:229
error_t xcbcMacInit(XcbcMacContext *context, const CipherAlgo *cipher, const void *key, size_t keyLen)
Initialize XCBC-MAC calculation.
Definition: xcbc_mac.c:107
uint8_t mac[MAX_CIPHER_BLOCK_SIZE]
Definition: xcbc_mac.h:62
uint8_t n
void xcbcMacReset(XcbcMacContext *context)
Reset XCBC-MAC context.
Definition: xcbc_mac.c:164
#define cryptoFreeMem(p)
Definition: crypto.h:791
CipherAlgoDeinit deinit
Definition: crypto.h:1078
Common interface for encryption algorithms.
Definition: crypto.h:1068
#define cryptoAllocMem(size)
Definition: crypto.h:786
error_t xcbcMacFinal(XcbcMacContext *context, uint8_t *mac, size_t macLen)
Finish the XCBC-MAC calculation.
Definition: xcbc_mac.c:229
#define osMemset(p, value, length)
Definition: os_port.h:135
@ NO_ERROR
Success.
Definition: error.h:44