ccm.c
Go to the documentation of this file.
1 /**
2  * @file ccm.c
3  * @brief Cipher Block Chaining-Message Authentication Code (CCM)
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  * CCM mode (Cipher Block Chaining-Message Authentication Code) is a mode of
30  * operation for cryptographic block ciphers. It is an authenticated encryption
31  * algorithm designed to provide both authentication and confidentiality. CCM
32  * mode is only defined for block ciphers with a block length of 128 bits.
33  * Refer to SP 800-38D for more details
34  *
35  * @author Oryx Embedded SARL (www.oryx-embedded.com)
36  * @version 2.4.4
37  **/
38 
39 //Switch to the appropriate trace level
40 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
41 
42 //Dependencies
43 #include "core/crypto.h"
44 #include "aead/ccm.h"
45 #include "debug.h"
46 
47 //Check crypto library configuration
48 #if (CCM_SUPPORT == ENABLED)
49 
50 
51 /**
52  * @brief Authenticated encryption using CCM
53  * @param[in] cipher Cipher algorithm
54  * @param[in] context Cipher algorithm context
55  * @param[in] n Nonce
56  * @param[in] nLen Length of the nonce
57  * @param[in] a Additional authenticated data
58  * @param[in] aLen Length of the additional data
59  * @param[in] p Plaintext to be encrypted
60  * @param[out] c Ciphertext resulting from the encryption
61  * @param[in] length Total number of data bytes to be encrypted
62  * @param[out] t MAC resulting from the encryption process
63  * @param[in] tLen Length of the MAC
64  * @return Error code
65  **/
66 
67 __weak_func error_t ccmEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *n,
68  size_t nLen, const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c,
69  size_t length, uint8_t *t, size_t tLen)
70 {
71  error_t error;
72  size_t m;
73  uint8_t b[16];
74  uint8_t y[16];
75  uint8_t s[16];
76 
77  //Check parameters
78  if(cipher == NULL || context == NULL)
80 
81  //CCM supports only symmetric block ciphers whose block size is 128 bits
82  if(cipher->type != CIPHER_ALGO_TYPE_BLOCK || cipher->blockSize != 16)
84 
85  //Format first block B(0)
86  error = ccmFormatBlock0(length, n, nLen, aLen, tLen, b);
87  //Invalid parameters?
88  if(error)
89  return error;
90 
91  //Set Y(0) = CIPH(B(0))
92  cipher->encryptBlock(context, b, y);
93 
94  //Any additional data?
95  if(aLen > 0)
96  {
97  //Format the associated data
98  osMemset(b, 0, 16);
99 
100  //Check the length of the associated data string
101  if(aLen < 0xFF00)
102  {
103  //The length is encoded as 2 octets
104  STORE16BE(aLen, b);
105 
106  //Number of bytes to copy
107  m = MIN(aLen, 16 - 2);
108  //Concatenate the associated data A
109  osMemcpy(b + 2, a, m);
110  }
111  else
112  {
113  //The length is encoded as 6 octets
114  b[0] = 0xFF;
115  b[1] = 0xFE;
116 
117  //MSB is stored first
118  STORE32BE(aLen, b + 2);
119 
120  //Number of bytes to copy
121  m = MIN(aLen, 16 - 6);
122  //Concatenate the associated data A
123  osMemcpy(b + 6, a, m);
124  }
125 
126  //XOR B(1) with Y(0)
127  ccmXorBlock(y, b, y, 16);
128  //Compute Y(1) = CIPH(B(1) ^ Y(0))
129  cipher->encryptBlock(context, y, y);
130 
131  //Number of remaining data bytes
132  aLen -= m;
133  a += m;
134 
135  //Process the remaining data bytes
136  while(aLen > 0)
137  {
138  //Associated data are processed in a block-by-block fashion
139  m = MIN(aLen, 16);
140 
141  //XOR B(i) with Y(i-1)
142  ccmXorBlock(y, a, y, m);
143  //Compute Y(i) = CIPH(B(i) ^ Y(i-1))
144  cipher->encryptBlock(context, y, y);
145 
146  //Next block
147  aLen -= m;
148  a += m;
149  }
150  }
151 
152  //Format initial counter value CTR(0)
153  ccmFormatCounter0(n, nLen, b);
154 
155  //Compute S(0) = CIPH(CTR(0))
156  cipher->encryptBlock(context, b, s);
157  //Save MSB(S(0))
158  osMemcpy(t, s, tLen);
159 
160  //Encrypt plaintext
161  while(length > 0)
162  {
163  //The encryption operates in a block-by-block fashion
164  m = MIN(length, 16);
165 
166  //XOR B(i) with Y(i-1)
167  ccmXorBlock(y, p, y, m);
168  //Compute Y(i) = CIPH(B(i) ^ Y(i-1))
169  cipher->encryptBlock(context, y, y);
170 
171  //Increment counter
172  ccmIncCounter(b, 15 - nLen);
173  //Compute S(i) = CIPH(CTR(i))
174  cipher->encryptBlock(context, b, s);
175  //Compute C(i) = B(i) XOR S(i)
176  ccmXorBlock(c, p, s, m);
177 
178  //Next block
179  length -= m;
180  p += m;
181  c += m;
182  }
183 
184  //Compute MAC
185  ccmXorBlock(t, t, y, tLen);
186 
187  //Successful encryption
188  return NO_ERROR;
189 }
190 
191 
192 /**
193  * @brief Authenticated decryption using CCM
194  * @param[in] cipher Cipher algorithm
195  * @param[in] context Cipher algorithm context
196  * @param[in] n Nonce
197  * @param[in] nLen Length of the nonce
198  * @param[in] a Additional authenticated data
199  * @param[in] aLen Length of the additional data
200  * @param[in] c Ciphertext to be decrypted
201  * @param[out] p Plaintext resulting from the decryption
202  * @param[in] length Total number of data bytes to be decrypted
203  * @param[in] t MAC to be verified
204  * @param[in] tLen Length of the MAC
205  * @return Error code
206  **/
207 
208 __weak_func error_t ccmDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *n,
209  size_t nLen, const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p,
210  size_t length, const uint8_t *t, size_t tLen)
211 {
212  error_t error;
213  uint8_t mask;
214  size_t m;
215  uint8_t b[16];
216  uint8_t y[16];
217  uint8_t r[16];
218  uint8_t s[16];
219 
220  //Check parameters
221  if(cipher == NULL || context == NULL)
223 
224  //CCM supports only symmetric block ciphers whose block size is 128 bits
225  if(cipher->type != CIPHER_ALGO_TYPE_BLOCK || cipher->blockSize != 16)
227 
228  //Format first block B(0)
229  error = ccmFormatBlock0(length, n, nLen, aLen, tLen, b);
230  //Invalid parameters?
231  if(error)
232  return error;
233 
234  //Set Y(0) = CIPH(B(0))
235  cipher->encryptBlock(context, b, y);
236 
237  //Any additional data?
238  if(aLen > 0)
239  {
240  //Format the associated data
241  osMemset(b, 0, 16);
242 
243  //Check the length of the associated data string
244  if(aLen < 0xFF00)
245  {
246  //The length is encoded as 2 octets
247  STORE16BE(aLen, b);
248 
249  //Number of bytes to copy
250  m = MIN(aLen, 16 - 2);
251  //Concatenate the associated data A
252  osMemcpy(b + 2, a, m);
253  }
254  else
255  {
256  //The length is encoded as 6 octets
257  b[0] = 0xFF;
258  b[1] = 0xFE;
259 
260  //MSB is stored first
261  STORE32BE(aLen, b + 2);
262 
263  //Number of bytes to copy
264  m = MIN(aLen, 16 - 6);
265  //Concatenate the associated data A
266  osMemcpy(b + 6, a, m);
267  }
268 
269  //XOR B(1) with Y(0)
270  ccmXorBlock(y, b, y, 16);
271  //Compute Y(1) = CIPH(B(1) ^ Y(0))
272  cipher->encryptBlock(context, y, y);
273 
274  //Number of remaining data bytes
275  aLen -= m;
276  a += m;
277 
278  //Process the remaining data bytes
279  while(aLen > 0)
280  {
281  //Associated data are processed in a block-by-block fashion
282  m = MIN(aLen, 16);
283 
284  //XOR B(i) with Y(i-1)
285  ccmXorBlock(y, a, y, m);
286  //Compute Y(i) = CIPH(B(i) ^ Y(i-1))
287  cipher->encryptBlock(context, y, y);
288 
289  //Next block
290  aLen -= m;
291  a += m;
292  }
293  }
294 
295  //Format initial counter value CTR(0)
296  ccmFormatCounter0(n, nLen, b);
297 
298  //Compute S(0) = CIPH(CTR(0))
299  cipher->encryptBlock(context, b, s);
300  //Save MSB(S(0))
301  osMemcpy(r, s, tLen);
302 
303  //Decrypt ciphertext
304  while(length > 0)
305  {
306  //The decryption operates in a block-by-block fashion
307  m = MIN(length, 16);
308 
309  //Increment counter
310  ccmIncCounter(b, 15 - nLen);
311  //Compute S(i) = CIPH(CTR(i))
312  cipher->encryptBlock(context, b, s);
313  //Compute B(i) = C(i) XOR S(i)
314  ccmXorBlock(p, c, s, m);
315 
316  //XOR B(i) with Y(i-1)
317  ccmXorBlock(y, p, y, m);
318  //Compute Y(i) = CIPH(B(i) ^ Y(i-1))
319  cipher->encryptBlock(context, y, y);
320 
321  //Next block
322  length -= m;
323  c += m;
324  p += m;
325  }
326 
327  //Compute MAC
328  ccmXorBlock(r, r, y, tLen);
329 
330  //The calculated tag is bitwise compared to the received tag. The message
331  //is authenticated if and only if the tags match
332  for(mask = 0, m = 0; m < tLen; m++)
333  {
334  mask |= r[m] ^ t[m];
335  }
336 
337  //Return status code
338  return (mask == 0) ? NO_ERROR : ERROR_FAILURE;
339 }
340 
341 
342 /**
343  * @brief Format first block B(0)
344  * @param[in] q Bit string representation of the octet length of P
345  * @param[in] n Nonce
346  * @param[in] nLen Length of the nonce
347  * @param[in] aLen Length of the additional data
348  * @param[in] tLen Length of the MAC
349  * @param[out] b Pointer to the buffer where to format B(0)
350  * @return Error code
351  **/
352 
353 error_t ccmFormatBlock0(size_t q, const uint8_t *n, size_t nLen, size_t aLen,
354  size_t tLen, uint8_t *b)
355 {
356  size_t i;
357  size_t qLen;
358 
359  //Check the length of the nonce
360  if(nLen < 7 || nLen > 13)
361  return ERROR_INVALID_LENGTH;
362 
363  //Check the length of the MAC
364  if(tLen < 4 || tLen > 16 || (tLen % 2) != 0)
365  return ERROR_INVALID_LENGTH;
366 
367  //Compute the octet length of Q
368  qLen = 15 - nLen;
369 
370  //Format the leading octet of the first block
371  b[0] = (aLen > 0) ? 0x40 : 0x00;
372  //Encode the octet length of T
373  b[0] |= ((tLen - 2) / 2) << 3;
374  //Encode the octet length of Q
375  b[0] |= qLen - 1;
376 
377  //Copy the nonce
378  osMemcpy(b + 1, n, nLen);
379 
380  //Encode the length field Q
381  for(i = 0; i < qLen; i++, q >>= 8)
382  {
383  b[15 - i] = q & 0xFF;
384  }
385 
386  //Return status code
387  return (q == 0) ? NO_ERROR : ERROR_INVALID_LENGTH;
388 }
389 
390 
391 /**
392  * @brief XOR operation
393  * @param[out] x Block resulting from the XOR operation
394  * @param[in] a First block
395  * @param[in] b Second block
396  * @param[in] n Size of the block
397  **/
398 
399 void ccmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
400 {
401  size_t i;
402 
403  //Perform XOR operation
404  for(i = 0; i < n; i++)
405  {
406  x[i] = a[i] ^ b[i];
407  }
408 }
409 
410 
411 /**
412  * @brief Format initial counter value CTR(0)
413  * @param[in] n Nonce
414  * @param[in] nLen Length of the nonce
415  * @param[out] ctr Pointer to the buffer where to format CTR(0)
416  **/
417 
418 void ccmFormatCounter0(const uint8_t *n, size_t nLen, uint8_t *ctr)
419 {
420  size_t qLen;
421 
422  //Compute the octet length of Q
423  qLen = 15 - nLen;
424 
425  //Format CTR(0)
426  ctr[0] = qLen - 1;
427  //Copy the nonce
428  osMemcpy(ctr + 1, n, nLen);
429  //Initialize counter value
430  osMemset(ctr + 1 + nLen, 0, qLen);
431 }
432 
433 
434 /**
435  * @brief Increment counter block
436  * @param[in,out] ctr Pointer to the counter block
437  * @param[in] n Size in bytes of the specific part of the block to be incremented
438  **/
439 
440 void ccmIncCounter(uint8_t *ctr, size_t n)
441 {
442  size_t i;
443  uint16_t temp;
444 
445  //The function increments the right-most bytes of the block. The remaining
446  //left-most bytes remain unchanged
447  for(temp = 1, i = 0; i < n; i++)
448  {
449  //Increment the current byte and propagate the carry
450  temp += ctr[15 - i];
451  ctr[15 - i] = temp & 0xFF;
452  temp >>= 8;
453  }
454 }
455 
456 #endif
__weak_func error_t ccmDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
Authenticated decryption using CCM.
Definition: ccm.c:208
void ccmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
XOR operation.
Definition: ccm.c:399
uint8_t b
Definition: nbns_common.h:104
uint8_t a
Definition: ndp.h:411
uint8_t p
Definition: ndp.h:300
uint8_t x
Definition: lldp_ext_med.h:211
@ CIPHER_ALGO_TYPE_BLOCK
Definition: crypto.h:953
uint8_t t
Definition: lldp_ext_med.h:212
__weak_func error_t ccmEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
Authenticated encryption using CCM.
Definition: ccm.c:67
size_t blockSize
Definition: crypto.h:1072
void ccmFormatCounter0(const uint8_t *n, size_t nLen, uint8_t *ctr)
Format initial counter value CTR(0)
Definition: ccm.c:418
void ccmIncCounter(uint8_t *ctr, size_t n)
Increment counter block.
Definition: ccm.c:440
CipherAlgoEncryptBlock encryptBlock
Definition: crypto.h:1076
uint8_t r
Definition: ndp.h:346
@ 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
CipherAlgoType type
Definition: crypto.h:1071
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define STORE16BE(a, p)
Definition: cpu_endian.h:262
error_t ccmFormatBlock0(size_t q, const uint8_t *n, size_t nLen, size_t aLen, size_t tLen, uint8_t *b)
Format first block B(0)
Definition: ccm.c:353
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
uint8_t mask
Definition: web_socket.h:319
uint8_t length
Definition: tcp.h:368
#define MIN(a, b)
Definition: os_port.h:63
uint8_t m
Definition: ndp.h:304
uint8_t n
Common interface for encryption algorithms.
Definition: crypto.h:1068
uint8_t s
Definition: igmp_common.h:234
#define osMemset(p, value, length)
Definition: os_port.h:135
Cipher Block Chaining-Message Authentication Code (CCM)
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.