NCBI C++ ToolKit
ccm.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /*
2  * NIST SP800-38C compliant CCM implementation
3  *
4  * Copyright The Mbed TLS Contributors
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may
8  * not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 /*
21  * Definition of CCM:
22  * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
23  * RFC 3610 "Counter with CBC-MAC (CCM)"
24  *
25  * Related:
26  * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
27  */
28 
29 #include "common.h"
30 
31 #if defined(MBEDTLS_CCM_C)
32 
33 #include "mbedtls/ccm.h"
34 #include "mbedtls/platform_util.h"
35 #include "mbedtls/error.h"
36 
37 #include <string.h>
38 
39 #include "mbedtls/platform.h"
40 
41 #if !defined(MBEDTLS_CCM_ALT)
42 
43 #define CCM_VALIDATE_RET(cond) \
44  MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_CCM_BAD_INPUT)
45 #define CCM_VALIDATE(cond) \
46  MBEDTLS_INTERNAL_VALIDATE(cond)
47 
48 #define CCM_ENCRYPT 0
49 #define CCM_DECRYPT 1
50 
51 /*
52  * Initialize context
53  */
55 {
56  CCM_VALIDATE(ctx != NULL);
57  memset(ctx, 0, sizeof(mbedtls_ccm_context));
58 }
59 
61  mbedtls_cipher_id_t cipher,
62  const unsigned char *key,
63  unsigned int keybits)
64 {
66  const mbedtls_cipher_info_t *cipher_info;
67 
70 
71  cipher_info = mbedtls_cipher_info_from_values(cipher, keybits,
73  if (cipher_info == NULL) {
75  }
76 
77  if (cipher_info->block_size != 16) {
79  }
80 
81  mbedtls_cipher_free(&ctx->cipher_ctx);
82 
83  if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) {
84  return ret;
85  }
86 
87  if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
88  MBEDTLS_ENCRYPT)) != 0) {
89  return ret;
90  }
91 
92  return 0;
93 }
94 
95 /*
96  * Free context
97  */
99 {
100  if (ctx == NULL) {
101  return;
102  }
103  mbedtls_cipher_free(&ctx->cipher_ctx);
105 }
106 
107 /*
108  * Macros for common operations.
109  * Results in smaller compiled code than static inline functions.
110  */
111 
112 /*
113  * Update the CBC-MAC state in y using a block in b
114  * (Always using b as the source helps the compiler optimise a bit better.)
115  */
116 #define UPDATE_CBC_MAC \
117  for (i = 0; i < 16; i++) \
118  y[i] ^= b[i]; \
119  \
120  if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, y, 16, y, &olen)) != 0) \
121  return ret;
122 
123 /*
124  * Encrypt or decrypt a partial block with CTR
125  * Warning: using b for temporary storage! src and dst must not be b!
126  * This avoids allocating one more 16 bytes buffer while allowing src == dst.
127  */
128 #define CTR_CRYPT(dst, src, len) \
129  do \
130  { \
131  if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctr, \
132  16, b, &olen)) != 0) \
133  { \
134  return ret; \
135  } \
136  \
137  for (i = 0; i < (len); i++) \
138  (dst)[i] = (src)[i] ^ b[i]; \
139  } while (0)
140 
141 /*
142  * Authenticated encryption or decryption
143  */
144 static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length,
145  const unsigned char *iv, size_t iv_len,
146  const unsigned char *add, size_t add_len,
147  const unsigned char *input, unsigned char *output,
148  unsigned char *tag, size_t tag_len)
149 {
151  unsigned char i;
152  unsigned char q;
153  size_t len_left, olen;
154  unsigned char b[16];
155  unsigned char y[16];
156  unsigned char ctr[16];
157  const unsigned char *src;
158  unsigned char *dst;
159 
160  /*
161  * Check length requirements: SP800-38C A.1
162  * Additional requirement: a < 2^16 - 2^8 to simplify the code.
163  * 'length' checked later (when writing it to the first block)
164  *
165  * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
166  */
167  if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0) {
169  }
170 
171  /* Also implies q is within bounds */
172  if (iv_len < 7 || iv_len > 13) {
174  }
175 
176  if (add_len >= 0xFF00) {
178  }
179 
180  q = 16 - 1 - (unsigned char) iv_len;
181 
182  /*
183  * First block B_0:
184  * 0 .. 0 flags
185  * 1 .. iv_len nonce (aka iv)
186  * iv_len+1 .. 15 length
187  *
188  * With flags as (bits):
189  * 7 0
190  * 6 add present?
191  * 5 .. 3 (t - 2) / 2
192  * 2 .. 0 q - 1
193  */
194  b[0] = 0;
195  b[0] |= (add_len > 0) << 6;
196  b[0] |= ((tag_len - 2) / 2) << 3;
197  b[0] |= q - 1;
198 
199  memcpy(b + 1, iv, iv_len);
200 
201  for (i = 0, len_left = length; i < q; i++, len_left >>= 8) {
202  b[15-i] = MBEDTLS_BYTE_0(len_left);
203  }
204 
205  if (len_left > 0) {
207  }
208 
209 
210  /* Start CBC-MAC with first block */
211  memset(y, 0, 16);
213 
214  /*
215  * If there is additional data, update CBC-MAC with
216  * add_len, add, 0 (padding to a block boundary)
217  */
218  if (add_len > 0) {
219  size_t use_len;
220  len_left = add_len;
221  src = add;
222 
223  memset(b, 0, 16);
224  MBEDTLS_PUT_UINT16_BE(add_len, b, 0);
225 
226  use_len = len_left < 16 - 2 ? len_left : 16 - 2;
227  memcpy(b + 2, src, use_len);
228  len_left -= use_len;
229  src += use_len;
230 
232 
233  while (len_left > 0) {
234  use_len = len_left > 16 ? 16 : len_left;
235 
236  memset(b, 0, 16);
237  memcpy(b, src, use_len);
239 
240  len_left -= use_len;
241  src += use_len;
242  }
243  }
244 
245  /*
246  * Prepare counter block for encryption:
247  * 0 .. 0 flags
248  * 1 .. iv_len nonce (aka iv)
249  * iv_len+1 .. 15 counter (initially 1)
250  *
251  * With flags as (bits):
252  * 7 .. 3 0
253  * 2 .. 0 q - 1
254  */
255  ctr[0] = q - 1;
256  memcpy(ctr + 1, iv, iv_len);
257  memset(ctr + 1 + iv_len, 0, q);
258  ctr[15] = 1;
259 
260  /*
261  * Authenticate and {en,de}crypt the message.
262  *
263  * The only difference between encryption and decryption is
264  * the respective order of authentication and {en,de}cryption.
265  */
266  len_left = length;
267  src = input;
268  dst = output;
269 
270  while (len_left > 0) {
271  size_t use_len = len_left > 16 ? 16 : len_left;
272 
273  if (mode == CCM_ENCRYPT) {
274  memset(b, 0, 16);
275  memcpy(b, src, use_len);
277  }
278 
279  CTR_CRYPT(dst, src, use_len);
280 
281  if (mode == CCM_DECRYPT) {
282  memset(b, 0, 16);
283  memcpy(b, dst, use_len);
285  }
286 
287  dst += use_len;
288  src += use_len;
289  len_left -= use_len;
290 
291  /*
292  * Increment counter.
293  * No need to check for overflow thanks to the length check above.
294  */
295  for (i = 0; i < q; i++) {
296  if (++ctr[15-i] != 0) {
297  break;
298  }
299  }
300  }
301 
302  /*
303  * Authentication: reset counter and crypt/mask internal tag
304  */
305  for (i = 0; i < q; i++) {
306  ctr[15-i] = 0;
307  }
308 
309  CTR_CRYPT(y, y, 16);
310  memcpy(tag, y, tag_len);
311 
312  return 0;
313 }
314 
315 /*
316  * Authenticated encryption
317  */
319  const unsigned char *iv, size_t iv_len,
320  const unsigned char *add, size_t add_len,
321  const unsigned char *input, unsigned char *output,
322  unsigned char *tag, size_t tag_len)
323 {
325  CCM_VALIDATE_RET(iv != NULL);
326  CCM_VALIDATE_RET(add_len == 0 || add != NULL);
327  CCM_VALIDATE_RET(length == 0 || input != NULL);
328  CCM_VALIDATE_RET(length == 0 || output != NULL);
329  CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
330  return ccm_auth_crypt(ctx, CCM_ENCRYPT, length, iv, iv_len,
331  add, add_len, input, output, tag, tag_len);
332 }
333 
335  const unsigned char *iv, size_t iv_len,
336  const unsigned char *add, size_t add_len,
337  const unsigned char *input, unsigned char *output,
338  unsigned char *tag, size_t tag_len)
339 {
341  CCM_VALIDATE_RET(iv != NULL);
342  CCM_VALIDATE_RET(add_len == 0 || add != NULL);
343  CCM_VALIDATE_RET(length == 0 || input != NULL);
344  CCM_VALIDATE_RET(length == 0 || output != NULL);
345  CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
346  if (tag_len == 0) {
348  }
349 
350  return mbedtls_ccm_star_encrypt_and_tag(ctx, length, iv, iv_len, add,
351  add_len, input, output, tag, tag_len);
352 }
353 
354 /*
355  * Authenticated decryption
356  */
358  const unsigned char *iv, size_t iv_len,
359  const unsigned char *add, size_t add_len,
360  const unsigned char *input, unsigned char *output,
361  const unsigned char *tag, size_t tag_len)
362 {
364  unsigned char check_tag[16];
365  unsigned char i;
366  int diff;
367 
369  CCM_VALIDATE_RET(iv != NULL);
370  CCM_VALIDATE_RET(add_len == 0 || add != NULL);
371  CCM_VALIDATE_RET(length == 0 || input != NULL);
372  CCM_VALIDATE_RET(length == 0 || output != NULL);
373  CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
374 
375  if ((ret = ccm_auth_crypt(ctx, CCM_DECRYPT, length,
376  iv, iv_len, add, add_len,
377  input, output, check_tag, tag_len)) != 0) {
378  return ret;
379  }
380 
381  /* Check tag in "constant-time" */
382  for (diff = 0, i = 0; i < tag_len; i++) {
383  diff |= tag[i] ^ check_tag[i];
384  }
385 
386  if (diff != 0) {
389  }
390 
391  return 0;
392 }
393 
395  const unsigned char *iv, size_t iv_len,
396  const unsigned char *add, size_t add_len,
397  const unsigned char *input, unsigned char *output,
398  const unsigned char *tag, size_t tag_len)
399 {
401  CCM_VALIDATE_RET(iv != NULL);
402  CCM_VALIDATE_RET(add_len == 0 || add != NULL);
403  CCM_VALIDATE_RET(length == 0 || input != NULL);
404  CCM_VALIDATE_RET(length == 0 || output != NULL);
405  CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
406 
407  if (tag_len == 0) {
409  }
410 
411  return mbedtls_ccm_star_auth_decrypt(ctx, length, iv, iv_len, add,
412  add_len, input, output, tag, tag_len);
413 }
414 #endif /* !MBEDTLS_CCM_ALT */
415 
416 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
417 /*
418  * Examples 1 to 3 from SP800-38C Appendix C
419  */
420 
421 #define NB_TESTS 3
422 #define CCM_SELFTEST_PT_MAX_LEN 24
423 #define CCM_SELFTEST_CT_MAX_LEN 32
424 /*
425  * The data is the same for all tests, only the used length changes
426  */
427 static const unsigned char key_test_data[] = {
428  0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
429  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
430 };
431 
432 static const unsigned char iv_test_data[] = {
433  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
434  0x18, 0x19, 0x1a, 0x1b
435 };
436 
437 static const unsigned char ad_test_data[] = {
438  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
439  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
440  0x10, 0x11, 0x12, 0x13
441 };
442 
443 static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
444  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
445  0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
446  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
447 };
448 
449 static const size_t iv_len_test_data[NB_TESTS] = { 7, 8, 12 };
450 static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
451 static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
452 static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 };
453 
454 static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
455  { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
456  { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
457  0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
458  0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
459  { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
460  0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
461  0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
462  0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
463 };
464 
465 int mbedtls_ccm_self_test(int verbose)
466 {
468  /*
469  * Some hardware accelerators require the input and output buffers
470  * would be in RAM, because the flash is not accessible.
471  * Use buffers on the stack to hold the test vectors data.
472  */
473  unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
474  unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
475  size_t i;
477 
479 
480  if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
481  8 * sizeof(key_test_data)) != 0) {
482  if (verbose != 0) {
483  mbedtls_printf(" CCM: setup failed");
484  }
485 
486  return 1;
487  }
488 
489  for (i = 0; i < NB_TESTS; i++) {
490  if (verbose != 0) {
491  mbedtls_printf(" CCM-AES #%u: ", (unsigned int) i + 1);
492  }
493 
494  memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
495  memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN);
496  memcpy(plaintext, msg_test_data, msg_len_test_data[i]);
497 
498  ret = mbedtls_ccm_encrypt_and_tag(&ctx, msg_len_test_data[i],
499  iv_test_data, iv_len_test_data[i],
500  ad_test_data, add_len_test_data[i],
501  plaintext, ciphertext,
502  ciphertext + msg_len_test_data[i],
503  tag_len_test_data[i]);
504 
505  if (ret != 0 ||
506  memcmp(ciphertext, res_test_data[i],
507  msg_len_test_data[i] + tag_len_test_data[i]) != 0) {
508  if (verbose != 0) {
509  mbedtls_printf("failed\n");
510  }
511 
512  return 1;
513  }
514  memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
515 
516  ret = mbedtls_ccm_auth_decrypt(&ctx, msg_len_test_data[i],
517  iv_test_data, iv_len_test_data[i],
518  ad_test_data, add_len_test_data[i],
519  ciphertext, plaintext,
520  ciphertext + msg_len_test_data[i],
521  tag_len_test_data[i]);
522 
523  if (ret != 0 ||
524  memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) {
525  if (verbose != 0) {
526  mbedtls_printf("failed\n");
527  }
528 
529  return 1;
530  }
531 
532  if (verbose != 0) {
533  mbedtls_printf("passed\n");
534  }
535  }
536 
538 
539  if (verbose != 0) {
540  mbedtls_printf("\n");
541  }
542 
543  return 0;
544 }
545 
546 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
547 
548 #endif /* MBEDTLS_CCM_C */
#define CTR_CRYPT(dst, src, len)
Definition: ccm.c:128
#define CCM_VALIDATE(cond)
Definition: ccm.c:45
#define CCM_DECRYPT
Definition: ccm.c:49
#define UPDATE_CBC_MAC
Definition: ccm.c:116
#define CCM_VALIDATE_RET(cond)
Definition: ccm.c:43
#define CCM_ENCRYPT
Definition: ccm.c:48
static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, unsigned char *tag, size_t tag_len)
Definition: ccm.c:144
This file provides an API for the CCM authenticated encryption mode for block ciphers.
void mbedtls_ccm_free(mbedtls_ccm_context *ctx)
This function releases and clears the specified CCM context and underlying cipher sub-context.
int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, const unsigned char *tag, size_t tag_len)
This function performs a CCM* authenticated decryption of a buffer.
int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx, mbedtls_cipher_id_t cipher, const unsigned char *key, unsigned int keybits)
This function initializes the CCM context set in the ctx parameter and sets the encryption key.
int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, unsigned char *tag, size_t tag_len)
This function encrypts a buffer using CCM*.
int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, unsigned char *tag, size_t tag_len)
This function encrypts a buffer using CCM.
#define MBEDTLS_ERR_CCM_BAD_INPUT
Bad input parameters to the function.
Definition: ccm.h:59
int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, const unsigned char *tag, size_t tag_len)
This function performs a CCM authenticated decryption of a buffer.
void mbedtls_ccm_init(mbedtls_ccm_context *ctx)
This function initializes the specified CCM context, to make references valid, and prepare the contex...
#define MBEDTLS_ERR_CCM_AUTH_FAILED
Authenticated decryption failed.
Definition: ccm.h:61
int mbedtls_cipher_setup(mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info)
This function initializes a cipher context for use with the given cipher primitive.
int mbedtls_cipher_setkey(mbedtls_cipher_context_t *ctx, const unsigned char *key, int key_bitlen, const mbedtls_operation_t operation)
This function sets the key to use with the given context.
void mbedtls_cipher_free(mbedtls_cipher_context_t *ctx)
This function frees and clears the cipher-specific context of ctx.
const mbedtls_cipher_info_t * mbedtls_cipher_info_from_values(const mbedtls_cipher_id_t cipher_id, int key_bitlen, const mbedtls_cipher_mode_t mode)
This function retrieves the cipher-information structure associated with the given cipher ID,...
@ MBEDTLS_ENCRYPT
Definition: cipher.h:223
@ MBEDTLS_MODE_ECB
The ECB cipher mode.
Definition: cipher.h:196
mbedtls_cipher_id_t
Supported cipher types.
Definition: cipher.h:90
@ MBEDTLS_CIPHER_ID_AES
The AES cipher.
Definition: cipher.h:93
#define MBEDTLS_PUT_UINT16_BE(n, data, offset)
Put in memory a 16 bits unsigned integer in big-endian order.
Definition: common.h:252
#define MBEDTLS_BYTE_0(x)
Byte Reading Macros.
Definition: common.h:106
CS_CONTEXT * ctx
Definition: t0006.c:12
#define NULL
Definition: ncbistd.hpp:225
static int input()
int i
mdb_mode_t mode
Definition: lmdb++.h:38
const struct ncbi::grid::netcache::search::fields::KEY key
const char * tag
This file contains the definitions and functions of the Mbed TLS platform abstraction layer.
#define mbedtls_printf
Definition: platform.h:219
Common and shared functions used by multiple modules in the Mbed TLS library.
void mbedtls_platform_zeroize(void *buf, size_t len)
Securely zeroize a buffer.
static SQLCHAR output[256]
Definition: print.c:5
true_type verbose
Definition: processing.cpp:902
Error to string translation.
#define MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
This is a bug in the library.
Definition: error.h:122
The CCM context-type definition.
Definition: ccm.h:79
Cipher information.
Definition: cipher.h:276
unsigned int block_size
The block size, in Bytes.
Definition: cipher.h:307
Modified on Tue Dec 05 02:02:26 2023 by modify_doxy.py rev. 669887