1817466cbSJens Wiklander /*
2817466cbSJens Wiklander * NIST SP800-38C compliant CCM implementation
3817466cbSJens Wiklander *
47901324dSJerome Forissier * Copyright The Mbed TLS Contributors
5b0563631STom Van Eyck * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6817466cbSJens Wiklander */
7817466cbSJens Wiklander
8817466cbSJens Wiklander /*
9817466cbSJens Wiklander * Definition of CCM:
10817466cbSJens Wiklander * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
11817466cbSJens Wiklander * RFC 3610 "Counter with CBC-MAC (CCM)"
12817466cbSJens Wiklander *
13817466cbSJens Wiklander * Related:
14817466cbSJens Wiklander * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
15817466cbSJens Wiklander */
16817466cbSJens Wiklander
177901324dSJerome Forissier #include "common.h"
18817466cbSJens Wiklander
19817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C)
20817466cbSJens Wiklander
21817466cbSJens Wiklander #include "mbedtls/ccm.h"
223d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
2311fa71b9SJerome Forissier #include "mbedtls/error.h"
24b0563631STom Van Eyck #include "mbedtls/constant_time.h"
25b0563631STom Van Eyck
26b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
27b0563631STom Van Eyck #include "block_cipher_internal.h"
28b0563631STom Van Eyck #endif
29817466cbSJens Wiklander
30817466cbSJens Wiklander #include <string.h>
31817466cbSJens Wiklander
32817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
33817466cbSJens Wiklander #include "mbedtls/platform.h"
34817466cbSJens Wiklander #else
3532b31808SJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
36817466cbSJens Wiklander #include <stdio.h>
37817466cbSJens Wiklander #define mbedtls_printf printf
38817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
3932b31808SJens Wiklander #endif /* MBEDTLS_PLATFORM_C */
40817466cbSJens Wiklander
413d3b0591SJens Wiklander #if !defined(MBEDTLS_CCM_ALT)
423d3b0591SJens Wiklander
43817466cbSJens Wiklander
44817466cbSJens Wiklander /*
45817466cbSJens Wiklander * Initialize context
46817466cbSJens Wiklander */
mbedtls_ccm_init(mbedtls_ccm_context * ctx)47817466cbSJens Wiklander void mbedtls_ccm_init(mbedtls_ccm_context *ctx)
48817466cbSJens Wiklander {
49817466cbSJens Wiklander memset(ctx, 0, sizeof(mbedtls_ccm_context));
50817466cbSJens Wiklander }
51817466cbSJens Wiklander
mbedtls_ccm_setkey(mbedtls_ccm_context * ctx,mbedtls_cipher_id_t cipher,const unsigned char * key,unsigned int keybits)52817466cbSJens Wiklander int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx,
53817466cbSJens Wiklander mbedtls_cipher_id_t cipher,
54817466cbSJens Wiklander const unsigned char *key,
55817466cbSJens Wiklander unsigned int keybits)
56817466cbSJens Wiklander {
5711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
58b0563631STom Van Eyck
59b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
60b0563631STom Van Eyck mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
61b0563631STom Van Eyck
62b0563631STom Van Eyck if ((ret = mbedtls_block_cipher_setup(&ctx->block_cipher_ctx, cipher)) != 0) {
63b0563631STom Van Eyck return MBEDTLS_ERR_CCM_BAD_INPUT;
64b0563631STom Van Eyck }
65b0563631STom Van Eyck
66b0563631STom Van Eyck if ((ret = mbedtls_block_cipher_setkey(&ctx->block_cipher_ctx, key, keybits)) != 0) {
67b0563631STom Van Eyck return MBEDTLS_ERR_CCM_BAD_INPUT;
68b0563631STom Van Eyck }
69b0563631STom Van Eyck #else
70817466cbSJens Wiklander const mbedtls_cipher_info_t *cipher_info;
71817466cbSJens Wiklander
7211fa71b9SJerome Forissier cipher_info = mbedtls_cipher_info_from_values(cipher, keybits,
7311fa71b9SJerome Forissier MBEDTLS_MODE_ECB);
7432b31808SJens Wiklander if (cipher_info == NULL) {
7532b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
7632b31808SJens Wiklander }
77817466cbSJens Wiklander
78b0563631STom Van Eyck if (mbedtls_cipher_info_get_block_size(cipher_info) != 16) {
7932b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
8032b31808SJens Wiklander }
81817466cbSJens Wiklander
82817466cbSJens Wiklander mbedtls_cipher_free(&ctx->cipher_ctx);
83817466cbSJens Wiklander
8432b31808SJens Wiklander if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) {
8532b31808SJens Wiklander return ret;
86817466cbSJens Wiklander }
87817466cbSJens Wiklander
8832b31808SJens Wiklander if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
8932b31808SJens Wiklander MBEDTLS_ENCRYPT)) != 0) {
9032b31808SJens Wiklander return ret;
9132b31808SJens Wiklander }
92b0563631STom Van Eyck #endif
9332b31808SJens Wiklander
94b0563631STom Van Eyck return ret;
95817466cbSJens Wiklander }
96817466cbSJens Wiklander
97817466cbSJens Wiklander /*
98817466cbSJens Wiklander * Free context
99817466cbSJens Wiklander */
mbedtls_ccm_free(mbedtls_ccm_context * ctx)100817466cbSJens Wiklander void mbedtls_ccm_free(mbedtls_ccm_context *ctx)
101817466cbSJens Wiklander {
10232b31808SJens Wiklander if (ctx == NULL) {
1033d3b0591SJens Wiklander return;
10432b31808SJens Wiklander }
105b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
106b0563631STom Van Eyck mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
107b0563631STom Van Eyck #else
108817466cbSJens Wiklander mbedtls_cipher_free(&ctx->cipher_ctx);
109b0563631STom Van Eyck #endif
1103d3b0591SJens Wiklander mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ccm_context));
111817466cbSJens Wiklander }
112817466cbSJens Wiklander
11332b31808SJens Wiklander #define CCM_STATE__CLEAR 0
11432b31808SJens Wiklander #define CCM_STATE__STARTED (1 << 0)
11532b31808SJens Wiklander #define CCM_STATE__LENGTHS_SET (1 << 1)
11632b31808SJens Wiklander #define CCM_STATE__AUTH_DATA_STARTED (1 << 2)
11732b31808SJens Wiklander #define CCM_STATE__AUTH_DATA_FINISHED (1 << 3)
11832b31808SJens Wiklander #define CCM_STATE__ERROR (1 << 4)
119817466cbSJens Wiklander
120817466cbSJens Wiklander /*
121817466cbSJens Wiklander * Encrypt or decrypt a partial block with CTR
122817466cbSJens Wiklander */
mbedtls_ccm_crypt(mbedtls_ccm_context * ctx,size_t offset,size_t use_len,const unsigned char * input,unsigned char * output)12332b31808SJens Wiklander static int mbedtls_ccm_crypt(mbedtls_ccm_context *ctx,
12432b31808SJens Wiklander size_t offset, size_t use_len,
12532b31808SJens Wiklander const unsigned char *input,
12632b31808SJens Wiklander unsigned char *output)
12732b31808SJens Wiklander {
12832b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
12932b31808SJens Wiklander unsigned char tmp_buf[16] = { 0 };
130817466cbSJens Wiklander
131b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
132b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->ctr, tmp_buf);
133b0563631STom Van Eyck #else
134b0563631STom Van Eyck size_t olen = 0;
135b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->ctr, 16, tmp_buf, &olen);
136b0563631STom Van Eyck #endif
137b0563631STom Van Eyck if (ret != 0) {
13832b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR;
13932b31808SJens Wiklander mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
14032b31808SJens Wiklander return ret;
14132b31808SJens Wiklander }
14232b31808SJens Wiklander
14332b31808SJens Wiklander mbedtls_xor(output, input, tmp_buf + offset, use_len);
14432b31808SJens Wiklander
14532b31808SJens Wiklander mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
14632b31808SJens Wiklander return ret;
14732b31808SJens Wiklander }
14832b31808SJens Wiklander
mbedtls_ccm_clear_state(mbedtls_ccm_context * ctx)14932b31808SJens Wiklander static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx)
15032b31808SJens Wiklander {
15132b31808SJens Wiklander ctx->state = CCM_STATE__CLEAR;
15232b31808SJens Wiklander memset(ctx->y, 0, 16);
15332b31808SJens Wiklander memset(ctx->ctr, 0, 16);
15432b31808SJens Wiklander }
15532b31808SJens Wiklander
ccm_calculate_first_block_if_ready(mbedtls_ccm_context * ctx)15632b31808SJens Wiklander static int ccm_calculate_first_block_if_ready(mbedtls_ccm_context *ctx)
157817466cbSJens Wiklander {
15811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
159817466cbSJens Wiklander unsigned char i;
160b0563631STom Van Eyck size_t len_left;
161b0563631STom Van Eyck #if !defined(MBEDTLS_BLOCK_CIPHER_C)
162b0563631STom Van Eyck size_t olen;
163b0563631STom Van Eyck #endif
164817466cbSJens Wiklander
16532b31808SJens Wiklander /* length calculation can be done only after both
16632b31808SJens Wiklander * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
167817466cbSJens Wiklander */
16832b31808SJens Wiklander if (!(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGTHS_SET)) {
16932b31808SJens Wiklander return 0;
17032b31808SJens Wiklander }
171817466cbSJens Wiklander
17232b31808SJens Wiklander /* CCM expects non-empty tag.
173*c3deb3d6SEtienne Carriere * CCM* allows empty tag. For CCM* without tag, the tag calculation is skipped.
17432b31808SJens Wiklander */
17532b31808SJens Wiklander if (ctx->tag_len == 0) {
17632b31808SJens Wiklander if (ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT || ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) {
17732b31808SJens Wiklander ctx->plaintext_len = 0;
178*c3deb3d6SEtienne Carriere return 0;
17932b31808SJens Wiklander } else {
18032b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
18132b31808SJens Wiklander }
18232b31808SJens Wiklander }
183817466cbSJens Wiklander
184817466cbSJens Wiklander /*
18532b31808SJens Wiklander * First block:
186817466cbSJens Wiklander * 0 .. 0 flags
18732b31808SJens Wiklander * 1 .. iv_len nonce (aka iv) - set by: mbedtls_ccm_starts()
188817466cbSJens Wiklander * iv_len+1 .. 15 length
189817466cbSJens Wiklander *
190817466cbSJens Wiklander * With flags as (bits):
191817466cbSJens Wiklander * 7 0
192817466cbSJens Wiklander * 6 add present?
193817466cbSJens Wiklander * 5 .. 3 (t - 2) / 2
194817466cbSJens Wiklander * 2 .. 0 q - 1
195817466cbSJens Wiklander */
19632b31808SJens Wiklander ctx->y[0] |= (ctx->add_len > 0) << 6;
19732b31808SJens Wiklander ctx->y[0] |= ((ctx->tag_len - 2) / 2) << 3;
19832b31808SJens Wiklander ctx->y[0] |= ctx->q - 1;
199817466cbSJens Wiklander
20032b31808SJens Wiklander for (i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8) {
20132b31808SJens Wiklander ctx->y[15-i] = MBEDTLS_BYTE_0(len_left);
20232b31808SJens Wiklander }
203817466cbSJens Wiklander
20432b31808SJens Wiklander if (len_left > 0) {
20532b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR;
20632b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
20732b31808SJens Wiklander }
208817466cbSJens Wiklander
209817466cbSJens Wiklander /* Start CBC-MAC with first block*/
210b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
211b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
212b0563631STom Van Eyck #else
213b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
214b0563631STom Van Eyck #endif
215b0563631STom Van Eyck if (ret != 0) {
21632b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR;
21732b31808SJens Wiklander return ret;
218817466cbSJens Wiklander }
21932b31808SJens Wiklander
22032b31808SJens Wiklander return 0;
221817466cbSJens Wiklander }
222817466cbSJens Wiklander
mbedtls_ccm_starts(mbedtls_ccm_context * ctx,int mode,const unsigned char * iv,size_t iv_len)22332b31808SJens Wiklander int mbedtls_ccm_starts(mbedtls_ccm_context *ctx,
22432b31808SJens Wiklander int mode,
22532b31808SJens Wiklander const unsigned char *iv,
22632b31808SJens Wiklander size_t iv_len)
22732b31808SJens Wiklander {
22832b31808SJens Wiklander /* Also implies q is within bounds */
22932b31808SJens Wiklander if (iv_len < 7 || iv_len > 13) {
23032b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
23132b31808SJens Wiklander }
23232b31808SJens Wiklander
23332b31808SJens Wiklander ctx->mode = mode;
23432b31808SJens Wiklander ctx->q = 16 - 1 - (unsigned char) iv_len;
23532b31808SJens Wiklander
236817466cbSJens Wiklander /*
237817466cbSJens Wiklander * Prepare counter block for encryption:
238817466cbSJens Wiklander * 0 .. 0 flags
239817466cbSJens Wiklander * 1 .. iv_len nonce (aka iv)
240817466cbSJens Wiklander * iv_len+1 .. 15 counter (initially 1)
241817466cbSJens Wiklander *
242817466cbSJens Wiklander * With flags as (bits):
243817466cbSJens Wiklander * 7 .. 3 0
244817466cbSJens Wiklander * 2 .. 0 q - 1
245817466cbSJens Wiklander */
24632b31808SJens Wiklander memset(ctx->ctr, 0, 16);
24732b31808SJens Wiklander ctx->ctr[0] = ctx->q - 1;
24832b31808SJens Wiklander memcpy(ctx->ctr + 1, iv, iv_len);
24932b31808SJens Wiklander memset(ctx->ctr + 1 + iv_len, 0, ctx->q);
25032b31808SJens Wiklander ctx->ctr[15] = 1;
251817466cbSJens Wiklander
252817466cbSJens Wiklander /*
25332b31808SJens Wiklander * See ccm_calculate_first_block_if_ready() for block layout description
25432b31808SJens Wiklander */
25532b31808SJens Wiklander memcpy(ctx->y + 1, iv, iv_len);
25632b31808SJens Wiklander
25732b31808SJens Wiklander ctx->state |= CCM_STATE__STARTED;
25832b31808SJens Wiklander return ccm_calculate_first_block_if_ready(ctx);
25932b31808SJens Wiklander }
26032b31808SJens Wiklander
mbedtls_ccm_set_lengths(mbedtls_ccm_context * ctx,size_t total_ad_len,size_t plaintext_len,size_t tag_len)26132b31808SJens Wiklander int mbedtls_ccm_set_lengths(mbedtls_ccm_context *ctx,
26232b31808SJens Wiklander size_t total_ad_len,
26332b31808SJens Wiklander size_t plaintext_len,
26432b31808SJens Wiklander size_t tag_len)
26532b31808SJens Wiklander {
26632b31808SJens Wiklander /*
26732b31808SJens Wiklander * Check length requirements: SP800-38C A.1
26832b31808SJens Wiklander * Additional requirement: a < 2^16 - 2^8 to simplify the code.
26932b31808SJens Wiklander * 'length' checked later (when writing it to the first block)
270817466cbSJens Wiklander *
27132b31808SJens Wiklander * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
272817466cbSJens Wiklander */
27332b31808SJens Wiklander if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0) {
27432b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
275817466cbSJens Wiklander }
276817466cbSJens Wiklander
27732b31808SJens Wiklander if (total_ad_len >= 0xFF00) {
27832b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
279817466cbSJens Wiklander }
280817466cbSJens Wiklander
28132b31808SJens Wiklander ctx->plaintext_len = plaintext_len;
28232b31808SJens Wiklander ctx->add_len = total_ad_len;
28332b31808SJens Wiklander ctx->tag_len = tag_len;
28432b31808SJens Wiklander ctx->processed = 0;
285817466cbSJens Wiklander
28632b31808SJens Wiklander ctx->state |= CCM_STATE__LENGTHS_SET;
28732b31808SJens Wiklander return ccm_calculate_first_block_if_ready(ctx);
28832b31808SJens Wiklander }
28932b31808SJens Wiklander
mbedtls_ccm_update_ad(mbedtls_ccm_context * ctx,const unsigned char * add,size_t add_len)29032b31808SJens Wiklander int mbedtls_ccm_update_ad(mbedtls_ccm_context *ctx,
29132b31808SJens Wiklander const unsigned char *add,
29232b31808SJens Wiklander size_t add_len)
29332b31808SJens Wiklander {
29432b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
295b0563631STom Van Eyck size_t use_len, offset;
296b0563631STom Van Eyck #if !defined(MBEDTLS_BLOCK_CIPHER_C)
297b0563631STom Van Eyck size_t olen;
298b0563631STom Van Eyck #endif
29932b31808SJens Wiklander
30032b31808SJens Wiklander if (ctx->state & CCM_STATE__ERROR) {
30132b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
30232b31808SJens Wiklander }
30332b31808SJens Wiklander
30432b31808SJens Wiklander if (add_len > 0) {
30532b31808SJens Wiklander if (ctx->state & CCM_STATE__AUTH_DATA_FINISHED) {
30632b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
30732b31808SJens Wiklander }
30832b31808SJens Wiklander
30932b31808SJens Wiklander if (!(ctx->state & CCM_STATE__AUTH_DATA_STARTED)) {
31032b31808SJens Wiklander if (add_len > ctx->add_len) {
31132b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
31232b31808SJens Wiklander }
31332b31808SJens Wiklander
31432b31808SJens Wiklander ctx->y[0] ^= (unsigned char) ((ctx->add_len >> 8) & 0xFF);
31532b31808SJens Wiklander ctx->y[1] ^= (unsigned char) ((ctx->add_len) & 0xFF);
31632b31808SJens Wiklander
31732b31808SJens Wiklander ctx->state |= CCM_STATE__AUTH_DATA_STARTED;
31832b31808SJens Wiklander } else if (ctx->processed + add_len > ctx->add_len) {
31932b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
32032b31808SJens Wiklander }
32132b31808SJens Wiklander
32232b31808SJens Wiklander while (add_len > 0) {
32332b31808SJens Wiklander offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1]
32432b31808SJens Wiklander * holding total auth data length */
32532b31808SJens Wiklander use_len = 16 - offset;
32632b31808SJens Wiklander
32732b31808SJens Wiklander if (use_len > add_len) {
32832b31808SJens Wiklander use_len = add_len;
32932b31808SJens Wiklander }
33032b31808SJens Wiklander
33132b31808SJens Wiklander mbedtls_xor(ctx->y + offset, ctx->y + offset, add, use_len);
33232b31808SJens Wiklander
33332b31808SJens Wiklander ctx->processed += use_len;
33432b31808SJens Wiklander add_len -= use_len;
33532b31808SJens Wiklander add += use_len;
33632b31808SJens Wiklander
33732b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->add_len) {
338b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
339b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
340b0563631STom Van Eyck #else
341b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
342b0563631STom Van Eyck #endif
343b0563631STom Van Eyck if (ret != 0) {
34432b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR;
34532b31808SJens Wiklander return ret;
34632b31808SJens Wiklander }
34732b31808SJens Wiklander }
34832b31808SJens Wiklander }
34932b31808SJens Wiklander
35032b31808SJens Wiklander if (ctx->processed == ctx->add_len) {
35132b31808SJens Wiklander ctx->state |= CCM_STATE__AUTH_DATA_FINISHED;
35232b31808SJens Wiklander ctx->processed = 0; // prepare for mbedtls_ccm_update()
35332b31808SJens Wiklander }
35432b31808SJens Wiklander }
35532b31808SJens Wiklander
35632b31808SJens Wiklander return 0;
35732b31808SJens Wiklander }
35832b31808SJens Wiklander
mbedtls_ccm_update(mbedtls_ccm_context * ctx,const unsigned char * input,size_t input_len,unsigned char * output,size_t output_size,size_t * output_len)35932b31808SJens Wiklander int mbedtls_ccm_update(mbedtls_ccm_context *ctx,
36032b31808SJens Wiklander const unsigned char *input, size_t input_len,
36132b31808SJens Wiklander unsigned char *output, size_t output_size,
36232b31808SJens Wiklander size_t *output_len)
36332b31808SJens Wiklander {
36432b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
36532b31808SJens Wiklander unsigned char i;
366b0563631STom Van Eyck size_t use_len, offset;
367b0563631STom Van Eyck #if !defined(MBEDTLS_BLOCK_CIPHER_C)
368b0563631STom Van Eyck size_t olen;
369b0563631STom Van Eyck #endif
37032b31808SJens Wiklander
37132b31808SJens Wiklander unsigned char local_output[16];
37232b31808SJens Wiklander
37332b31808SJens Wiklander if (ctx->state & CCM_STATE__ERROR) {
37432b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
37532b31808SJens Wiklander }
37632b31808SJens Wiklander
37732b31808SJens Wiklander /* Check against plaintext length only if performing operation with
37832b31808SJens Wiklander * authentication
379817466cbSJens Wiklander */
38032b31808SJens Wiklander if (ctx->tag_len != 0 && ctx->processed + input_len > ctx->plaintext_len) {
38132b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
38232b31808SJens Wiklander }
38332b31808SJens Wiklander
38432b31808SJens Wiklander if (output_size < input_len) {
38532b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
38632b31808SJens Wiklander }
38732b31808SJens Wiklander *output_len = input_len;
38832b31808SJens Wiklander
38932b31808SJens Wiklander ret = 0;
39032b31808SJens Wiklander
39132b31808SJens Wiklander while (input_len > 0) {
39232b31808SJens Wiklander offset = ctx->processed % 16;
39332b31808SJens Wiklander
39432b31808SJens Wiklander use_len = 16 - offset;
39532b31808SJens Wiklander
39632b31808SJens Wiklander if (use_len > input_len) {
39732b31808SJens Wiklander use_len = input_len;
39832b31808SJens Wiklander }
39932b31808SJens Wiklander
40032b31808SJens Wiklander ctx->processed += use_len;
40132b31808SJens Wiklander
40232b31808SJens Wiklander if (ctx->mode == MBEDTLS_CCM_ENCRYPT || \
40332b31808SJens Wiklander ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT) {
40432b31808SJens Wiklander mbedtls_xor(ctx->y + offset, ctx->y + offset, input, use_len);
40532b31808SJens Wiklander
40632b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
407b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
408b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
409b0563631STom Van Eyck #else
410b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
411b0563631STom Van Eyck #endif
412b0563631STom Van Eyck if (ret != 0) {
41332b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR;
41432b31808SJens Wiklander goto exit;
41532b31808SJens Wiklander }
41632b31808SJens Wiklander }
41732b31808SJens Wiklander
41832b31808SJens Wiklander ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, output);
41932b31808SJens Wiklander if (ret != 0) {
42032b31808SJens Wiklander goto exit;
42132b31808SJens Wiklander }
42232b31808SJens Wiklander }
42332b31808SJens Wiklander
42432b31808SJens Wiklander if (ctx->mode == MBEDTLS_CCM_DECRYPT || \
42532b31808SJens Wiklander ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) {
42632b31808SJens Wiklander /* Since output may be in shared memory, we cannot be sure that
42732b31808SJens Wiklander * it will contain what we wrote to it. Therefore, we should avoid using
42832b31808SJens Wiklander * it as input to any operations.
42932b31808SJens Wiklander * Write decrypted data to local_output to avoid using output variable as
43032b31808SJens Wiklander * input in the XOR operation for Y.
43132b31808SJens Wiklander */
43232b31808SJens Wiklander ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, local_output);
43332b31808SJens Wiklander if (ret != 0) {
43432b31808SJens Wiklander goto exit;
43532b31808SJens Wiklander }
43632b31808SJens Wiklander
43732b31808SJens Wiklander mbedtls_xor(ctx->y + offset, ctx->y + offset, local_output, use_len);
43832b31808SJens Wiklander
43932b31808SJens Wiklander memcpy(output, local_output, use_len);
44032b31808SJens Wiklander
44132b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
442b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
443b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
444b0563631STom Van Eyck #else
445b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
446b0563631STom Van Eyck #endif
447b0563631STom Van Eyck if (ret != 0) {
44832b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR;
44932b31808SJens Wiklander goto exit;
45032b31808SJens Wiklander }
45132b31808SJens Wiklander }
45232b31808SJens Wiklander }
45332b31808SJens Wiklander
45432b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
45532b31808SJens Wiklander for (i = 0; i < ctx->q; i++) {
45632b31808SJens Wiklander if (++(ctx->ctr)[15-i] != 0) {
457817466cbSJens Wiklander break;
458817466cbSJens Wiklander }
45932b31808SJens Wiklander }
46032b31808SJens Wiklander }
46132b31808SJens Wiklander
46232b31808SJens Wiklander input_len -= use_len;
46332b31808SJens Wiklander input += use_len;
46432b31808SJens Wiklander output += use_len;
46532b31808SJens Wiklander }
46632b31808SJens Wiklander
46732b31808SJens Wiklander exit:
46832b31808SJens Wiklander mbedtls_platform_zeroize(local_output, 16);
46932b31808SJens Wiklander
47032b31808SJens Wiklander return ret;
47132b31808SJens Wiklander }
47232b31808SJens Wiklander
mbedtls_ccm_finish(mbedtls_ccm_context * ctx,unsigned char * tag,size_t tag_len)47332b31808SJens Wiklander int mbedtls_ccm_finish(mbedtls_ccm_context *ctx,
47432b31808SJens Wiklander unsigned char *tag, size_t tag_len)
47532b31808SJens Wiklander {
47632b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
47732b31808SJens Wiklander unsigned char i;
47832b31808SJens Wiklander
47932b31808SJens Wiklander if (ctx->state & CCM_STATE__ERROR) {
48032b31808SJens Wiklander return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
48132b31808SJens Wiklander }
48232b31808SJens Wiklander
48332b31808SJens Wiklander if (ctx->add_len > 0 && !(ctx->state & CCM_STATE__AUTH_DATA_FINISHED)) {
48432b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
48532b31808SJens Wiklander }
48632b31808SJens Wiklander
48732b31808SJens Wiklander if (ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len) {
48832b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT;
48932b31808SJens Wiklander }
490817466cbSJens Wiklander
491817466cbSJens Wiklander /*
492817466cbSJens Wiklander * Authentication: reset counter and crypt/mask internal tag
493817466cbSJens Wiklander */
49432b31808SJens Wiklander for (i = 0; i < ctx->q; i++) {
49532b31808SJens Wiklander ctx->ctr[15-i] = 0;
49632b31808SJens Wiklander }
497817466cbSJens Wiklander
49832b31808SJens Wiklander ret = mbedtls_ccm_crypt(ctx, 0, 16, ctx->y, ctx->y);
49932b31808SJens Wiklander if (ret != 0) {
50032b31808SJens Wiklander return ret;
50132b31808SJens Wiklander }
50232b31808SJens Wiklander if (tag != NULL) {
50332b31808SJens Wiklander memcpy(tag, ctx->y, tag_len);
50432b31808SJens Wiklander }
50532b31808SJens Wiklander mbedtls_ccm_clear_state(ctx);
506817466cbSJens Wiklander
50732b31808SJens Wiklander return 0;
50832b31808SJens Wiklander }
50932b31808SJens Wiklander
51032b31808SJens Wiklander /*
51132b31808SJens Wiklander * Authenticated encryption or decryption
51232b31808SJens Wiklander */
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)51332b31808SJens Wiklander static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length,
51432b31808SJens Wiklander const unsigned char *iv, size_t iv_len,
51532b31808SJens Wiklander const unsigned char *add, size_t add_len,
51632b31808SJens Wiklander const unsigned char *input, unsigned char *output,
51732b31808SJens Wiklander unsigned char *tag, size_t tag_len)
51832b31808SJens Wiklander {
51932b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
52032b31808SJens Wiklander size_t olen;
52132b31808SJens Wiklander
52232b31808SJens Wiklander if ((ret = mbedtls_ccm_starts(ctx, mode, iv, iv_len)) != 0) {
52332b31808SJens Wiklander return ret;
52432b31808SJens Wiklander }
52532b31808SJens Wiklander
52632b31808SJens Wiklander if ((ret = mbedtls_ccm_set_lengths(ctx, add_len, length, tag_len)) != 0) {
52732b31808SJens Wiklander return ret;
52832b31808SJens Wiklander }
52932b31808SJens Wiklander
53032b31808SJens Wiklander if ((ret = mbedtls_ccm_update_ad(ctx, add, add_len)) != 0) {
53132b31808SJens Wiklander return ret;
53232b31808SJens Wiklander }
53332b31808SJens Wiklander
53432b31808SJens Wiklander if ((ret = mbedtls_ccm_update(ctx, input, length,
53532b31808SJens Wiklander output, length, &olen)) != 0) {
53632b31808SJens Wiklander return ret;
53732b31808SJens Wiklander }
53832b31808SJens Wiklander
53932b31808SJens Wiklander if ((ret = mbedtls_ccm_finish(ctx, tag, tag_len)) != 0) {
54032b31808SJens Wiklander return ret;
54132b31808SJens Wiklander }
54232b31808SJens Wiklander
54332b31808SJens Wiklander return 0;
544817466cbSJens Wiklander }
545817466cbSJens Wiklander
546817466cbSJens Wiklander /*
547817466cbSJens Wiklander * Authenticated encryption
548817466cbSJens Wiklander */
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)5493d3b0591SJens Wiklander int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
5503d3b0591SJens Wiklander const unsigned char *iv, size_t iv_len,
5513d3b0591SJens Wiklander const unsigned char *add, size_t add_len,
5523d3b0591SJens Wiklander const unsigned char *input, unsigned char *output,
5533d3b0591SJens Wiklander unsigned char *tag, size_t tag_len)
5543d3b0591SJens Wiklander {
55532b31808SJens Wiklander return ccm_auth_crypt(ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len,
55632b31808SJens Wiklander add, add_len, input, output, tag, tag_len);
5573d3b0591SJens Wiklander }
5583d3b0591SJens Wiklander
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)559817466cbSJens Wiklander int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
560817466cbSJens Wiklander const unsigned char *iv, size_t iv_len,
561817466cbSJens Wiklander const unsigned char *add, size_t add_len,
562817466cbSJens Wiklander const unsigned char *input, unsigned char *output,
563817466cbSJens Wiklander unsigned char *tag, size_t tag_len)
564817466cbSJens Wiklander {
56532b31808SJens Wiklander return ccm_auth_crypt(ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len,
56632b31808SJens Wiklander add, add_len, input, output, tag, tag_len);
567817466cbSJens Wiklander }
568817466cbSJens Wiklander
569817466cbSJens Wiklander /*
570817466cbSJens Wiklander * Authenticated decryption
571817466cbSJens Wiklander */
mbedtls_ccm_compare_tags(const unsigned char * tag1,const unsigned char * tag2,size_t tag_len)57232b31808SJens Wiklander static int mbedtls_ccm_compare_tags(const unsigned char *tag1,
57332b31808SJens Wiklander const unsigned char *tag2,
57432b31808SJens Wiklander size_t tag_len)
57532b31808SJens Wiklander {
57632b31808SJens Wiklander /* Check tag in "constant-time" */
577b0563631STom Van Eyck int diff = mbedtls_ct_memcmp(tag1, tag2, tag_len);
57832b31808SJens Wiklander
57932b31808SJens Wiklander if (diff != 0) {
58032b31808SJens Wiklander return MBEDTLS_ERR_CCM_AUTH_FAILED;
58132b31808SJens Wiklander }
58232b31808SJens Wiklander
58332b31808SJens Wiklander return 0;
58432b31808SJens Wiklander }
58532b31808SJens Wiklander
ccm_auth_decrypt(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,const unsigned char * tag,size_t tag_len)58632b31808SJens Wiklander static int ccm_auth_decrypt(mbedtls_ccm_context *ctx, int mode, size_t length,
587817466cbSJens Wiklander const unsigned char *iv, size_t iv_len,
588817466cbSJens Wiklander const unsigned char *add, size_t add_len,
589817466cbSJens Wiklander const unsigned char *input, unsigned char *output,
590817466cbSJens Wiklander const unsigned char *tag, size_t tag_len)
591817466cbSJens Wiklander {
59211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
593817466cbSJens Wiklander unsigned char check_tag[16];
594817466cbSJens Wiklander
59532b31808SJens Wiklander if ((ret = ccm_auth_crypt(ctx, mode, length,
596817466cbSJens Wiklander iv, iv_len, add, add_len,
59732b31808SJens Wiklander input, output, check_tag, tag_len)) != 0) {
59832b31808SJens Wiklander return ret;
599817466cbSJens Wiklander }
600817466cbSJens Wiklander
60132b31808SJens Wiklander if ((ret = mbedtls_ccm_compare_tags(tag, check_tag, tag_len)) != 0) {
6023d3b0591SJens Wiklander mbedtls_platform_zeroize(output, length);
60332b31808SJens Wiklander return ret;
604817466cbSJens Wiklander }
605817466cbSJens Wiklander
60632b31808SJens Wiklander return 0;
60732b31808SJens Wiklander }
60832b31808SJens Wiklander
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)60932b31808SJens Wiklander int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
61032b31808SJens Wiklander const unsigned char *iv, size_t iv_len,
61132b31808SJens Wiklander const unsigned char *add, size_t add_len,
61232b31808SJens Wiklander const unsigned char *input, unsigned char *output,
61332b31808SJens Wiklander const unsigned char *tag, size_t tag_len)
61432b31808SJens Wiklander {
61532b31808SJens Wiklander return ccm_auth_decrypt(ctx, MBEDTLS_CCM_STAR_DECRYPT, length,
61632b31808SJens Wiklander iv, iv_len, add, add_len,
61732b31808SJens Wiklander input, output, tag, tag_len);
618817466cbSJens Wiklander }
619817466cbSJens Wiklander
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)6203d3b0591SJens Wiklander int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
6213d3b0591SJens Wiklander const unsigned char *iv, size_t iv_len,
6223d3b0591SJens Wiklander const unsigned char *add, size_t add_len,
6233d3b0591SJens Wiklander const unsigned char *input, unsigned char *output,
6243d3b0591SJens Wiklander const unsigned char *tag, size_t tag_len)
6253d3b0591SJens Wiklander {
62632b31808SJens Wiklander return ccm_auth_decrypt(ctx, MBEDTLS_CCM_DECRYPT, length,
62732b31808SJens Wiklander iv, iv_len, add, add_len,
62832b31808SJens Wiklander input, output, tag, tag_len);
6293d3b0591SJens Wiklander }
6303d3b0591SJens Wiklander #endif /* !MBEDTLS_CCM_ALT */
631817466cbSJens Wiklander
632b0563631STom Van Eyck #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CCM_GCM_CAN_AES)
633817466cbSJens Wiklander /*
634817466cbSJens Wiklander * Examples 1 to 3 from SP800-38C Appendix C
635817466cbSJens Wiklander */
636817466cbSJens Wiklander
637817466cbSJens Wiklander #define NB_TESTS 3
6383d3b0591SJens Wiklander #define CCM_SELFTEST_PT_MAX_LEN 24
6393d3b0591SJens Wiklander #define CCM_SELFTEST_CT_MAX_LEN 32
640817466cbSJens Wiklander /*
641817466cbSJens Wiklander * The data is the same for all tests, only the used length changes
642817466cbSJens Wiklander */
64311fa71b9SJerome Forissier static const unsigned char key_test_data[] = {
644817466cbSJens Wiklander 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
645817466cbSJens Wiklander 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
646817466cbSJens Wiklander };
647817466cbSJens Wiklander
64811fa71b9SJerome Forissier static const unsigned char iv_test_data[] = {
649817466cbSJens Wiklander 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
650817466cbSJens Wiklander 0x18, 0x19, 0x1a, 0x1b
651817466cbSJens Wiklander };
652817466cbSJens Wiklander
65311fa71b9SJerome Forissier static const unsigned char ad_test_data[] = {
654817466cbSJens Wiklander 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
655817466cbSJens Wiklander 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
656817466cbSJens Wiklander 0x10, 0x11, 0x12, 0x13
657817466cbSJens Wiklander };
658817466cbSJens Wiklander
65911fa71b9SJerome Forissier static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
660817466cbSJens Wiklander 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
661817466cbSJens Wiklander 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
662817466cbSJens Wiklander 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
663817466cbSJens Wiklander };
664817466cbSJens Wiklander
66511fa71b9SJerome Forissier static const size_t iv_len_test_data[NB_TESTS] = { 7, 8, 12 };
66611fa71b9SJerome Forissier static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
66711fa71b9SJerome Forissier static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
66811fa71b9SJerome Forissier static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 };
669817466cbSJens Wiklander
67011fa71b9SJerome Forissier static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
671817466cbSJens Wiklander { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
672817466cbSJens Wiklander { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
673817466cbSJens Wiklander 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
674817466cbSJens Wiklander 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
675817466cbSJens Wiklander { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
676817466cbSJens Wiklander 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
677817466cbSJens Wiklander 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
678817466cbSJens Wiklander 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
679817466cbSJens Wiklander };
680817466cbSJens Wiklander
mbedtls_ccm_self_test(int verbose)681817466cbSJens Wiklander int mbedtls_ccm_self_test(int verbose)
682817466cbSJens Wiklander {
683817466cbSJens Wiklander mbedtls_ccm_context ctx;
6843d3b0591SJens Wiklander /*
6853d3b0591SJens Wiklander * Some hardware accelerators require the input and output buffers
6863d3b0591SJens Wiklander * would be in RAM, because the flash is not accessible.
6873d3b0591SJens Wiklander * Use buffers on the stack to hold the test vectors data.
6883d3b0591SJens Wiklander */
6893d3b0591SJens Wiklander unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
6903d3b0591SJens Wiklander unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
691817466cbSJens Wiklander size_t i;
69211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
693817466cbSJens Wiklander
694817466cbSJens Wiklander mbedtls_ccm_init(&ctx);
695817466cbSJens Wiklander
69611fa71b9SJerome Forissier if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
69732b31808SJens Wiklander 8 * sizeof(key_test_data)) != 0) {
69832b31808SJens Wiklander if (verbose != 0) {
699817466cbSJens Wiklander mbedtls_printf(" CCM: setup failed");
700817466cbSJens Wiklander }
701817466cbSJens Wiklander
70232b31808SJens Wiklander return 1;
70332b31808SJens Wiklander }
70432b31808SJens Wiklander
70532b31808SJens Wiklander for (i = 0; i < NB_TESTS; i++) {
70632b31808SJens Wiklander if (verbose != 0) {
707817466cbSJens Wiklander mbedtls_printf(" CCM-AES #%u: ", (unsigned int) i + 1);
70832b31808SJens Wiklander }
709817466cbSJens Wiklander
7103d3b0591SJens Wiklander memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
7113d3b0591SJens Wiklander memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN);
71211fa71b9SJerome Forissier memcpy(plaintext, msg_test_data, msg_len_test_data[i]);
7133d3b0591SJens Wiklander
71411fa71b9SJerome Forissier ret = mbedtls_ccm_encrypt_and_tag(&ctx, msg_len_test_data[i],
71511fa71b9SJerome Forissier iv_test_data, iv_len_test_data[i],
71611fa71b9SJerome Forissier ad_test_data, add_len_test_data[i],
7173d3b0591SJens Wiklander plaintext, ciphertext,
71811fa71b9SJerome Forissier ciphertext + msg_len_test_data[i],
71911fa71b9SJerome Forissier tag_len_test_data[i]);
720817466cbSJens Wiklander
721817466cbSJens Wiklander if (ret != 0 ||
72211fa71b9SJerome Forissier memcmp(ciphertext, res_test_data[i],
72332b31808SJens Wiklander msg_len_test_data[i] + tag_len_test_data[i]) != 0) {
72432b31808SJens Wiklander if (verbose != 0) {
725817466cbSJens Wiklander mbedtls_printf("failed\n");
72632b31808SJens Wiklander }
727817466cbSJens Wiklander
72832b31808SJens Wiklander return 1;
729817466cbSJens Wiklander }
7303d3b0591SJens Wiklander memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
731817466cbSJens Wiklander
73211fa71b9SJerome Forissier ret = mbedtls_ccm_auth_decrypt(&ctx, msg_len_test_data[i],
73311fa71b9SJerome Forissier iv_test_data, iv_len_test_data[i],
73411fa71b9SJerome Forissier ad_test_data, add_len_test_data[i],
7353d3b0591SJens Wiklander ciphertext, plaintext,
73611fa71b9SJerome Forissier ciphertext + msg_len_test_data[i],
73711fa71b9SJerome Forissier tag_len_test_data[i]);
738817466cbSJens Wiklander
739817466cbSJens Wiklander if (ret != 0 ||
74032b31808SJens Wiklander memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) {
74132b31808SJens Wiklander if (verbose != 0) {
742817466cbSJens Wiklander mbedtls_printf("failed\n");
743817466cbSJens Wiklander }
744817466cbSJens Wiklander
74532b31808SJens Wiklander return 1;
74632b31808SJens Wiklander }
74732b31808SJens Wiklander
74832b31808SJens Wiklander if (verbose != 0) {
749817466cbSJens Wiklander mbedtls_printf("passed\n");
750817466cbSJens Wiklander }
75132b31808SJens Wiklander }
752817466cbSJens Wiklander
753817466cbSJens Wiklander mbedtls_ccm_free(&ctx);
754817466cbSJens Wiklander
75532b31808SJens Wiklander if (verbose != 0) {
756817466cbSJens Wiklander mbedtls_printf("\n");
75732b31808SJens Wiklander }
758817466cbSJens Wiklander
75932b31808SJens Wiklander return 0;
760817466cbSJens Wiklander }
761817466cbSJens Wiklander
762817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
763817466cbSJens Wiklander
764817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */
765