xref: /optee_os/lib/libmbedtls/mbedtls/library/ccm.c (revision c3deb3d6f3b13d0e17fc9efe5880aec039e47594)
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