1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * NIST SP800-38C compliant CCM implementation 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 5*b0563631STom 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" 24*b0563631STom Van Eyck #include "mbedtls/constant_time.h" 25*b0563631STom Van Eyck 26*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C) 27*b0563631STom Van Eyck #include "block_cipher_internal.h" 28*b0563631STom 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 */ 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 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; 58*b0563631STom Van Eyck 59*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C) 60*b0563631STom Van Eyck mbedtls_block_cipher_free(&ctx->block_cipher_ctx); 61*b0563631STom Van Eyck 62*b0563631STom Van Eyck if ((ret = mbedtls_block_cipher_setup(&ctx->block_cipher_ctx, cipher)) != 0) { 63*b0563631STom Van Eyck return MBEDTLS_ERR_CCM_BAD_INPUT; 64*b0563631STom Van Eyck } 65*b0563631STom Van Eyck 66*b0563631STom Van Eyck if ((ret = mbedtls_block_cipher_setkey(&ctx->block_cipher_ctx, key, keybits)) != 0) { 67*b0563631STom Van Eyck return MBEDTLS_ERR_CCM_BAD_INPUT; 68*b0563631STom Van Eyck } 69*b0563631STom 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 78*b0563631STom 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 } 92*b0563631STom Van Eyck #endif 9332b31808SJens Wiklander 94*b0563631STom Van Eyck return ret; 95817466cbSJens Wiklander } 96817466cbSJens Wiklander 97817466cbSJens Wiklander /* 98817466cbSJens Wiklander * Free context 99817466cbSJens Wiklander */ 100817466cbSJens Wiklander void mbedtls_ccm_free(mbedtls_ccm_context *ctx) 101817466cbSJens Wiklander { 10232b31808SJens Wiklander if (ctx == NULL) { 1033d3b0591SJens Wiklander return; 10432b31808SJens Wiklander } 105*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C) 106*b0563631STom Van Eyck mbedtls_block_cipher_free(&ctx->block_cipher_ctx); 107*b0563631STom Van Eyck #else 108817466cbSJens Wiklander mbedtls_cipher_free(&ctx->cipher_ctx); 109*b0563631STom 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 */ 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 131*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C) 132*b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->ctr, tmp_buf); 133*b0563631STom Van Eyck #else 134*b0563631STom Van Eyck size_t olen = 0; 135*b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->ctr, 16, tmp_buf, &olen); 136*b0563631STom Van Eyck #endif 137*b0563631STom 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 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 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; 160*b0563631STom Van Eyck size_t len_left; 161*b0563631STom Van Eyck #if !defined(MBEDTLS_BLOCK_CIPHER_C) 162*b0563631STom Van Eyck size_t olen; 163*b0563631STom 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. 17332b31808SJens Wiklander * CCM* allows empty tag. For CCM* without tag, ignore plaintext length. 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; 17832b31808SJens Wiklander } else { 17932b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 18032b31808SJens Wiklander } 18132b31808SJens Wiklander } 182817466cbSJens Wiklander 183817466cbSJens Wiklander /* 18432b31808SJens Wiklander * First block: 185817466cbSJens Wiklander * 0 .. 0 flags 18632b31808SJens Wiklander * 1 .. iv_len nonce (aka iv) - set by: mbedtls_ccm_starts() 187817466cbSJens Wiklander * iv_len+1 .. 15 length 188817466cbSJens Wiklander * 189817466cbSJens Wiklander * With flags as (bits): 190817466cbSJens Wiklander * 7 0 191817466cbSJens Wiklander * 6 add present? 192817466cbSJens Wiklander * 5 .. 3 (t - 2) / 2 193817466cbSJens Wiklander * 2 .. 0 q - 1 194817466cbSJens Wiklander */ 19532b31808SJens Wiklander ctx->y[0] |= (ctx->add_len > 0) << 6; 19632b31808SJens Wiklander ctx->y[0] |= ((ctx->tag_len - 2) / 2) << 3; 19732b31808SJens Wiklander ctx->y[0] |= ctx->q - 1; 198817466cbSJens Wiklander 19932b31808SJens Wiklander for (i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8) { 20032b31808SJens Wiklander ctx->y[15-i] = MBEDTLS_BYTE_0(len_left); 20132b31808SJens Wiklander } 202817466cbSJens Wiklander 20332b31808SJens Wiklander if (len_left > 0) { 20432b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 20532b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 20632b31808SJens Wiklander } 207817466cbSJens Wiklander 208817466cbSJens Wiklander /* Start CBC-MAC with first block*/ 209*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C) 210*b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y); 211*b0563631STom Van Eyck #else 212*b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen); 213*b0563631STom Van Eyck #endif 214*b0563631STom Van Eyck if (ret != 0) { 21532b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 21632b31808SJens Wiklander return ret; 217817466cbSJens Wiklander } 21832b31808SJens Wiklander 21932b31808SJens Wiklander return 0; 220817466cbSJens Wiklander } 221817466cbSJens Wiklander 22232b31808SJens Wiklander int mbedtls_ccm_starts(mbedtls_ccm_context *ctx, 22332b31808SJens Wiklander int mode, 22432b31808SJens Wiklander const unsigned char *iv, 22532b31808SJens Wiklander size_t iv_len) 22632b31808SJens Wiklander { 22732b31808SJens Wiklander /* Also implies q is within bounds */ 22832b31808SJens Wiklander if (iv_len < 7 || iv_len > 13) { 22932b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 23032b31808SJens Wiklander } 23132b31808SJens Wiklander 23232b31808SJens Wiklander ctx->mode = mode; 23332b31808SJens Wiklander ctx->q = 16 - 1 - (unsigned char) iv_len; 23432b31808SJens Wiklander 235817466cbSJens Wiklander /* 236817466cbSJens Wiklander * Prepare counter block for encryption: 237817466cbSJens Wiklander * 0 .. 0 flags 238817466cbSJens Wiklander * 1 .. iv_len nonce (aka iv) 239817466cbSJens Wiklander * iv_len+1 .. 15 counter (initially 1) 240817466cbSJens Wiklander * 241817466cbSJens Wiklander * With flags as (bits): 242817466cbSJens Wiklander * 7 .. 3 0 243817466cbSJens Wiklander * 2 .. 0 q - 1 244817466cbSJens Wiklander */ 24532b31808SJens Wiklander memset(ctx->ctr, 0, 16); 24632b31808SJens Wiklander ctx->ctr[0] = ctx->q - 1; 24732b31808SJens Wiklander memcpy(ctx->ctr + 1, iv, iv_len); 24832b31808SJens Wiklander memset(ctx->ctr + 1 + iv_len, 0, ctx->q); 24932b31808SJens Wiklander ctx->ctr[15] = 1; 250817466cbSJens Wiklander 251817466cbSJens Wiklander /* 25232b31808SJens Wiklander * See ccm_calculate_first_block_if_ready() for block layout description 25332b31808SJens Wiklander */ 25432b31808SJens Wiklander memcpy(ctx->y + 1, iv, iv_len); 25532b31808SJens Wiklander 25632b31808SJens Wiklander ctx->state |= CCM_STATE__STARTED; 25732b31808SJens Wiklander return ccm_calculate_first_block_if_ready(ctx); 25832b31808SJens Wiklander } 25932b31808SJens Wiklander 26032b31808SJens Wiklander int mbedtls_ccm_set_lengths(mbedtls_ccm_context *ctx, 26132b31808SJens Wiklander size_t total_ad_len, 26232b31808SJens Wiklander size_t plaintext_len, 26332b31808SJens Wiklander size_t tag_len) 26432b31808SJens Wiklander { 26532b31808SJens Wiklander /* 26632b31808SJens Wiklander * Check length requirements: SP800-38C A.1 26732b31808SJens Wiklander * Additional requirement: a < 2^16 - 2^8 to simplify the code. 26832b31808SJens Wiklander * 'length' checked later (when writing it to the first block) 269817466cbSJens Wiklander * 27032b31808SJens Wiklander * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4). 271817466cbSJens Wiklander */ 27232b31808SJens Wiklander if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0) { 27332b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 274817466cbSJens Wiklander } 275817466cbSJens Wiklander 27632b31808SJens Wiklander if (total_ad_len >= 0xFF00) { 27732b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 278817466cbSJens Wiklander } 279817466cbSJens Wiklander 28032b31808SJens Wiklander ctx->plaintext_len = plaintext_len; 28132b31808SJens Wiklander ctx->add_len = total_ad_len; 28232b31808SJens Wiklander ctx->tag_len = tag_len; 28332b31808SJens Wiklander ctx->processed = 0; 284817466cbSJens Wiklander 28532b31808SJens Wiklander ctx->state |= CCM_STATE__LENGTHS_SET; 28632b31808SJens Wiklander return ccm_calculate_first_block_if_ready(ctx); 28732b31808SJens Wiklander } 28832b31808SJens Wiklander 28932b31808SJens Wiklander int mbedtls_ccm_update_ad(mbedtls_ccm_context *ctx, 29032b31808SJens Wiklander const unsigned char *add, 29132b31808SJens Wiklander size_t add_len) 29232b31808SJens Wiklander { 29332b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 294*b0563631STom Van Eyck size_t use_len, offset; 295*b0563631STom Van Eyck #if !defined(MBEDTLS_BLOCK_CIPHER_C) 296*b0563631STom Van Eyck size_t olen; 297*b0563631STom Van Eyck #endif 29832b31808SJens Wiklander 29932b31808SJens Wiklander if (ctx->state & CCM_STATE__ERROR) { 30032b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 30132b31808SJens Wiklander } 30232b31808SJens Wiklander 30332b31808SJens Wiklander if (add_len > 0) { 30432b31808SJens Wiklander if (ctx->state & CCM_STATE__AUTH_DATA_FINISHED) { 30532b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 30632b31808SJens Wiklander } 30732b31808SJens Wiklander 30832b31808SJens Wiklander if (!(ctx->state & CCM_STATE__AUTH_DATA_STARTED)) { 30932b31808SJens Wiklander if (add_len > ctx->add_len) { 31032b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 31132b31808SJens Wiklander } 31232b31808SJens Wiklander 31332b31808SJens Wiklander ctx->y[0] ^= (unsigned char) ((ctx->add_len >> 8) & 0xFF); 31432b31808SJens Wiklander ctx->y[1] ^= (unsigned char) ((ctx->add_len) & 0xFF); 31532b31808SJens Wiklander 31632b31808SJens Wiklander ctx->state |= CCM_STATE__AUTH_DATA_STARTED; 31732b31808SJens Wiklander } else if (ctx->processed + add_len > ctx->add_len) { 31832b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 31932b31808SJens Wiklander } 32032b31808SJens Wiklander 32132b31808SJens Wiklander while (add_len > 0) { 32232b31808SJens Wiklander offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1] 32332b31808SJens Wiklander * holding total auth data length */ 32432b31808SJens Wiklander use_len = 16 - offset; 32532b31808SJens Wiklander 32632b31808SJens Wiklander if (use_len > add_len) { 32732b31808SJens Wiklander use_len = add_len; 32832b31808SJens Wiklander } 32932b31808SJens Wiklander 33032b31808SJens Wiklander mbedtls_xor(ctx->y + offset, ctx->y + offset, add, use_len); 33132b31808SJens Wiklander 33232b31808SJens Wiklander ctx->processed += use_len; 33332b31808SJens Wiklander add_len -= use_len; 33432b31808SJens Wiklander add += use_len; 33532b31808SJens Wiklander 33632b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->add_len) { 337*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C) 338*b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y); 339*b0563631STom Van Eyck #else 340*b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen); 341*b0563631STom Van Eyck #endif 342*b0563631STom Van Eyck if (ret != 0) { 34332b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 34432b31808SJens Wiklander return ret; 34532b31808SJens Wiklander } 34632b31808SJens Wiklander } 34732b31808SJens Wiklander } 34832b31808SJens Wiklander 34932b31808SJens Wiklander if (ctx->processed == ctx->add_len) { 35032b31808SJens Wiklander ctx->state |= CCM_STATE__AUTH_DATA_FINISHED; 35132b31808SJens Wiklander ctx->processed = 0; // prepare for mbedtls_ccm_update() 35232b31808SJens Wiklander } 35332b31808SJens Wiklander } 35432b31808SJens Wiklander 35532b31808SJens Wiklander return 0; 35632b31808SJens Wiklander } 35732b31808SJens Wiklander 35832b31808SJens Wiklander int mbedtls_ccm_update(mbedtls_ccm_context *ctx, 35932b31808SJens Wiklander const unsigned char *input, size_t input_len, 36032b31808SJens Wiklander unsigned char *output, size_t output_size, 36132b31808SJens Wiklander size_t *output_len) 36232b31808SJens Wiklander { 36332b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 36432b31808SJens Wiklander unsigned char i; 365*b0563631STom Van Eyck size_t use_len, offset; 366*b0563631STom Van Eyck #if !defined(MBEDTLS_BLOCK_CIPHER_C) 367*b0563631STom Van Eyck size_t olen; 368*b0563631STom Van Eyck #endif 36932b31808SJens Wiklander 37032b31808SJens Wiklander unsigned char local_output[16]; 37132b31808SJens Wiklander 37232b31808SJens Wiklander if (ctx->state & CCM_STATE__ERROR) { 37332b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 37432b31808SJens Wiklander } 37532b31808SJens Wiklander 37632b31808SJens Wiklander /* Check against plaintext length only if performing operation with 37732b31808SJens Wiklander * authentication 378817466cbSJens Wiklander */ 37932b31808SJens Wiklander if (ctx->tag_len != 0 && ctx->processed + input_len > ctx->plaintext_len) { 38032b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 38132b31808SJens Wiklander } 38232b31808SJens Wiklander 38332b31808SJens Wiklander if (output_size < input_len) { 38432b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 38532b31808SJens Wiklander } 38632b31808SJens Wiklander *output_len = input_len; 38732b31808SJens Wiklander 38832b31808SJens Wiklander ret = 0; 38932b31808SJens Wiklander 39032b31808SJens Wiklander while (input_len > 0) { 39132b31808SJens Wiklander offset = ctx->processed % 16; 39232b31808SJens Wiklander 39332b31808SJens Wiklander use_len = 16 - offset; 39432b31808SJens Wiklander 39532b31808SJens Wiklander if (use_len > input_len) { 39632b31808SJens Wiklander use_len = input_len; 39732b31808SJens Wiklander } 39832b31808SJens Wiklander 39932b31808SJens Wiklander ctx->processed += use_len; 40032b31808SJens Wiklander 40132b31808SJens Wiklander if (ctx->mode == MBEDTLS_CCM_ENCRYPT || \ 40232b31808SJens Wiklander ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT) { 40332b31808SJens Wiklander mbedtls_xor(ctx->y + offset, ctx->y + offset, input, use_len); 40432b31808SJens Wiklander 40532b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) { 406*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C) 407*b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y); 408*b0563631STom Van Eyck #else 409*b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen); 410*b0563631STom Van Eyck #endif 411*b0563631STom Van Eyck if (ret != 0) { 41232b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 41332b31808SJens Wiklander goto exit; 41432b31808SJens Wiklander } 41532b31808SJens Wiklander } 41632b31808SJens Wiklander 41732b31808SJens Wiklander ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, output); 41832b31808SJens Wiklander if (ret != 0) { 41932b31808SJens Wiklander goto exit; 42032b31808SJens Wiklander } 42132b31808SJens Wiklander } 42232b31808SJens Wiklander 42332b31808SJens Wiklander if (ctx->mode == MBEDTLS_CCM_DECRYPT || \ 42432b31808SJens Wiklander ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) { 42532b31808SJens Wiklander /* Since output may be in shared memory, we cannot be sure that 42632b31808SJens Wiklander * it will contain what we wrote to it. Therefore, we should avoid using 42732b31808SJens Wiklander * it as input to any operations. 42832b31808SJens Wiklander * Write decrypted data to local_output to avoid using output variable as 42932b31808SJens Wiklander * input in the XOR operation for Y. 43032b31808SJens Wiklander */ 43132b31808SJens Wiklander ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, local_output); 43232b31808SJens Wiklander if (ret != 0) { 43332b31808SJens Wiklander goto exit; 43432b31808SJens Wiklander } 43532b31808SJens Wiklander 43632b31808SJens Wiklander mbedtls_xor(ctx->y + offset, ctx->y + offset, local_output, use_len); 43732b31808SJens Wiklander 43832b31808SJens Wiklander memcpy(output, local_output, use_len); 43932b31808SJens Wiklander 44032b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) { 441*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C) 442*b0563631STom Van Eyck ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y); 443*b0563631STom Van Eyck #else 444*b0563631STom Van Eyck ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen); 445*b0563631STom Van Eyck #endif 446*b0563631STom Van Eyck if (ret != 0) { 44732b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 44832b31808SJens Wiklander goto exit; 44932b31808SJens Wiklander } 45032b31808SJens Wiklander } 45132b31808SJens Wiklander } 45232b31808SJens Wiklander 45332b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) { 45432b31808SJens Wiklander for (i = 0; i < ctx->q; i++) { 45532b31808SJens Wiklander if (++(ctx->ctr)[15-i] != 0) { 456817466cbSJens Wiklander break; 457817466cbSJens Wiklander } 45832b31808SJens Wiklander } 45932b31808SJens Wiklander } 46032b31808SJens Wiklander 46132b31808SJens Wiklander input_len -= use_len; 46232b31808SJens Wiklander input += use_len; 46332b31808SJens Wiklander output += use_len; 46432b31808SJens Wiklander } 46532b31808SJens Wiklander 46632b31808SJens Wiklander exit: 46732b31808SJens Wiklander mbedtls_platform_zeroize(local_output, 16); 46832b31808SJens Wiklander 46932b31808SJens Wiklander return ret; 47032b31808SJens Wiklander } 47132b31808SJens Wiklander 47232b31808SJens Wiklander int mbedtls_ccm_finish(mbedtls_ccm_context *ctx, 47332b31808SJens Wiklander unsigned char *tag, size_t tag_len) 47432b31808SJens Wiklander { 47532b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 47632b31808SJens Wiklander unsigned char i; 47732b31808SJens Wiklander 47832b31808SJens Wiklander if (ctx->state & CCM_STATE__ERROR) { 47932b31808SJens Wiklander return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 48032b31808SJens Wiklander } 48132b31808SJens Wiklander 48232b31808SJens Wiklander if (ctx->add_len > 0 && !(ctx->state & CCM_STATE__AUTH_DATA_FINISHED)) { 48332b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 48432b31808SJens Wiklander } 48532b31808SJens Wiklander 48632b31808SJens Wiklander if (ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len) { 48732b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 48832b31808SJens Wiklander } 489817466cbSJens Wiklander 490817466cbSJens Wiklander /* 491817466cbSJens Wiklander * Authentication: reset counter and crypt/mask internal tag 492817466cbSJens Wiklander */ 49332b31808SJens Wiklander for (i = 0; i < ctx->q; i++) { 49432b31808SJens Wiklander ctx->ctr[15-i] = 0; 49532b31808SJens Wiklander } 496817466cbSJens Wiklander 49732b31808SJens Wiklander ret = mbedtls_ccm_crypt(ctx, 0, 16, ctx->y, ctx->y); 49832b31808SJens Wiklander if (ret != 0) { 49932b31808SJens Wiklander return ret; 50032b31808SJens Wiklander } 50132b31808SJens Wiklander if (tag != NULL) { 50232b31808SJens Wiklander memcpy(tag, ctx->y, tag_len); 50332b31808SJens Wiklander } 50432b31808SJens Wiklander mbedtls_ccm_clear_state(ctx); 505817466cbSJens Wiklander 50632b31808SJens Wiklander return 0; 50732b31808SJens Wiklander } 50832b31808SJens Wiklander 50932b31808SJens Wiklander /* 51032b31808SJens Wiklander * Authenticated encryption or decryption 51132b31808SJens Wiklander */ 51232b31808SJens Wiklander static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length, 51332b31808SJens Wiklander const unsigned char *iv, size_t iv_len, 51432b31808SJens Wiklander const unsigned char *add, size_t add_len, 51532b31808SJens Wiklander const unsigned char *input, unsigned char *output, 51632b31808SJens Wiklander unsigned char *tag, size_t tag_len) 51732b31808SJens Wiklander { 51832b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 51932b31808SJens Wiklander size_t olen; 52032b31808SJens Wiklander 52132b31808SJens Wiklander if ((ret = mbedtls_ccm_starts(ctx, mode, iv, iv_len)) != 0) { 52232b31808SJens Wiklander return ret; 52332b31808SJens Wiklander } 52432b31808SJens Wiklander 52532b31808SJens Wiklander if ((ret = mbedtls_ccm_set_lengths(ctx, add_len, length, tag_len)) != 0) { 52632b31808SJens Wiklander return ret; 52732b31808SJens Wiklander } 52832b31808SJens Wiklander 52932b31808SJens Wiklander if ((ret = mbedtls_ccm_update_ad(ctx, add, add_len)) != 0) { 53032b31808SJens Wiklander return ret; 53132b31808SJens Wiklander } 53232b31808SJens Wiklander 53332b31808SJens Wiklander if ((ret = mbedtls_ccm_update(ctx, input, length, 53432b31808SJens Wiklander output, length, &olen)) != 0) { 53532b31808SJens Wiklander return ret; 53632b31808SJens Wiklander } 53732b31808SJens Wiklander 53832b31808SJens Wiklander if ((ret = mbedtls_ccm_finish(ctx, tag, tag_len)) != 0) { 53932b31808SJens Wiklander return ret; 54032b31808SJens Wiklander } 54132b31808SJens Wiklander 54232b31808SJens Wiklander return 0; 543817466cbSJens Wiklander } 544817466cbSJens Wiklander 545817466cbSJens Wiklander /* 546817466cbSJens Wiklander * Authenticated encryption 547817466cbSJens Wiklander */ 5483d3b0591SJens Wiklander int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, 5493d3b0591SJens Wiklander const unsigned char *iv, size_t iv_len, 5503d3b0591SJens Wiklander const unsigned char *add, size_t add_len, 5513d3b0591SJens Wiklander const unsigned char *input, unsigned char *output, 5523d3b0591SJens Wiklander unsigned char *tag, size_t tag_len) 5533d3b0591SJens Wiklander { 55432b31808SJens Wiklander return ccm_auth_crypt(ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len, 55532b31808SJens Wiklander add, add_len, input, output, tag, tag_len); 5563d3b0591SJens Wiklander } 5573d3b0591SJens Wiklander 558817466cbSJens Wiklander int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, 559817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 560817466cbSJens Wiklander const unsigned char *add, size_t add_len, 561817466cbSJens Wiklander const unsigned char *input, unsigned char *output, 562817466cbSJens Wiklander unsigned char *tag, size_t tag_len) 563817466cbSJens Wiklander { 56432b31808SJens Wiklander return ccm_auth_crypt(ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len, 56532b31808SJens Wiklander add, add_len, input, output, tag, tag_len); 566817466cbSJens Wiklander } 567817466cbSJens Wiklander 568817466cbSJens Wiklander /* 569817466cbSJens Wiklander * Authenticated decryption 570817466cbSJens Wiklander */ 57132b31808SJens Wiklander static int mbedtls_ccm_compare_tags(const unsigned char *tag1, 57232b31808SJens Wiklander const unsigned char *tag2, 57332b31808SJens Wiklander size_t tag_len) 57432b31808SJens Wiklander { 57532b31808SJens Wiklander /* Check tag in "constant-time" */ 576*b0563631STom Van Eyck int diff = mbedtls_ct_memcmp(tag1, tag2, tag_len); 57732b31808SJens Wiklander 57832b31808SJens Wiklander if (diff != 0) { 57932b31808SJens Wiklander return MBEDTLS_ERR_CCM_AUTH_FAILED; 58032b31808SJens Wiklander } 58132b31808SJens Wiklander 58232b31808SJens Wiklander return 0; 58332b31808SJens Wiklander } 58432b31808SJens Wiklander 58532b31808SJens Wiklander static int ccm_auth_decrypt(mbedtls_ccm_context *ctx, int mode, size_t length, 586817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 587817466cbSJens Wiklander const unsigned char *add, size_t add_len, 588817466cbSJens Wiklander const unsigned char *input, unsigned char *output, 589817466cbSJens Wiklander const unsigned char *tag, size_t tag_len) 590817466cbSJens Wiklander { 59111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 592817466cbSJens Wiklander unsigned char check_tag[16]; 593817466cbSJens Wiklander 59432b31808SJens Wiklander if ((ret = ccm_auth_crypt(ctx, mode, length, 595817466cbSJens Wiklander iv, iv_len, add, add_len, 59632b31808SJens Wiklander input, output, check_tag, tag_len)) != 0) { 59732b31808SJens Wiklander return ret; 598817466cbSJens Wiklander } 599817466cbSJens Wiklander 60032b31808SJens Wiklander if ((ret = mbedtls_ccm_compare_tags(tag, check_tag, tag_len)) != 0) { 6013d3b0591SJens Wiklander mbedtls_platform_zeroize(output, length); 60232b31808SJens Wiklander return ret; 603817466cbSJens Wiklander } 604817466cbSJens Wiklander 60532b31808SJens Wiklander return 0; 60632b31808SJens Wiklander } 60732b31808SJens Wiklander 60832b31808SJens Wiklander int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, 60932b31808SJens Wiklander const unsigned char *iv, size_t iv_len, 61032b31808SJens Wiklander const unsigned char *add, size_t add_len, 61132b31808SJens Wiklander const unsigned char *input, unsigned char *output, 61232b31808SJens Wiklander const unsigned char *tag, size_t tag_len) 61332b31808SJens Wiklander { 61432b31808SJens Wiklander return ccm_auth_decrypt(ctx, MBEDTLS_CCM_STAR_DECRYPT, length, 61532b31808SJens Wiklander iv, iv_len, add, add_len, 61632b31808SJens Wiklander input, output, tag, tag_len); 617817466cbSJens Wiklander } 618817466cbSJens Wiklander 6193d3b0591SJens Wiklander int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, 6203d3b0591SJens Wiklander const unsigned char *iv, size_t iv_len, 6213d3b0591SJens Wiklander const unsigned char *add, size_t add_len, 6223d3b0591SJens Wiklander const unsigned char *input, unsigned char *output, 6233d3b0591SJens Wiklander const unsigned char *tag, size_t tag_len) 6243d3b0591SJens Wiklander { 62532b31808SJens Wiklander return ccm_auth_decrypt(ctx, MBEDTLS_CCM_DECRYPT, length, 62632b31808SJens Wiklander iv, iv_len, add, add_len, 62732b31808SJens Wiklander input, output, tag, tag_len); 6283d3b0591SJens Wiklander } 6293d3b0591SJens Wiklander #endif /* !MBEDTLS_CCM_ALT */ 630817466cbSJens Wiklander 631*b0563631STom Van Eyck #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CCM_GCM_CAN_AES) 632817466cbSJens Wiklander /* 633817466cbSJens Wiklander * Examples 1 to 3 from SP800-38C Appendix C 634817466cbSJens Wiklander */ 635817466cbSJens Wiklander 636817466cbSJens Wiklander #define NB_TESTS 3 6373d3b0591SJens Wiklander #define CCM_SELFTEST_PT_MAX_LEN 24 6383d3b0591SJens Wiklander #define CCM_SELFTEST_CT_MAX_LEN 32 639817466cbSJens Wiklander /* 640817466cbSJens Wiklander * The data is the same for all tests, only the used length changes 641817466cbSJens Wiklander */ 64211fa71b9SJerome Forissier static const unsigned char key_test_data[] = { 643817466cbSJens Wiklander 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 644817466cbSJens Wiklander 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f 645817466cbSJens Wiklander }; 646817466cbSJens Wiklander 64711fa71b9SJerome Forissier static const unsigned char iv_test_data[] = { 648817466cbSJens Wiklander 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 649817466cbSJens Wiklander 0x18, 0x19, 0x1a, 0x1b 650817466cbSJens Wiklander }; 651817466cbSJens Wiklander 65211fa71b9SJerome Forissier static const unsigned char ad_test_data[] = { 653817466cbSJens Wiklander 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 654817466cbSJens Wiklander 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 655817466cbSJens Wiklander 0x10, 0x11, 0x12, 0x13 656817466cbSJens Wiklander }; 657817466cbSJens Wiklander 65811fa71b9SJerome Forissier static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = { 659817466cbSJens Wiklander 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 660817466cbSJens Wiklander 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 661817466cbSJens Wiklander 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 662817466cbSJens Wiklander }; 663817466cbSJens Wiklander 66411fa71b9SJerome Forissier static const size_t iv_len_test_data[NB_TESTS] = { 7, 8, 12 }; 66511fa71b9SJerome Forissier static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 }; 66611fa71b9SJerome Forissier static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 }; 66711fa71b9SJerome Forissier static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 }; 668817466cbSJens Wiklander 66911fa71b9SJerome Forissier static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = { 670817466cbSJens Wiklander { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, 671817466cbSJens Wiklander { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, 672817466cbSJens Wiklander 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, 673817466cbSJens Wiklander 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, 674817466cbSJens Wiklander { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 675817466cbSJens Wiklander 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 676817466cbSJens Wiklander 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 677817466cbSJens Wiklander 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } 678817466cbSJens Wiklander }; 679817466cbSJens Wiklander 680817466cbSJens Wiklander int mbedtls_ccm_self_test(int verbose) 681817466cbSJens Wiklander { 682817466cbSJens Wiklander mbedtls_ccm_context ctx; 6833d3b0591SJens Wiklander /* 6843d3b0591SJens Wiklander * Some hardware accelerators require the input and output buffers 6853d3b0591SJens Wiklander * would be in RAM, because the flash is not accessible. 6863d3b0591SJens Wiklander * Use buffers on the stack to hold the test vectors data. 6873d3b0591SJens Wiklander */ 6883d3b0591SJens Wiklander unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN]; 6893d3b0591SJens Wiklander unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN]; 690817466cbSJens Wiklander size_t i; 69111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 692817466cbSJens Wiklander 693817466cbSJens Wiklander mbedtls_ccm_init(&ctx); 694817466cbSJens Wiklander 69511fa71b9SJerome Forissier if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data, 69632b31808SJens Wiklander 8 * sizeof(key_test_data)) != 0) { 69732b31808SJens Wiklander if (verbose != 0) { 698817466cbSJens Wiklander mbedtls_printf(" CCM: setup failed"); 699817466cbSJens Wiklander } 700817466cbSJens Wiklander 70132b31808SJens Wiklander return 1; 70232b31808SJens Wiklander } 70332b31808SJens Wiklander 70432b31808SJens Wiklander for (i = 0; i < NB_TESTS; i++) { 70532b31808SJens Wiklander if (verbose != 0) { 706817466cbSJens Wiklander mbedtls_printf(" CCM-AES #%u: ", (unsigned int) i + 1); 70732b31808SJens Wiklander } 708817466cbSJens Wiklander 7093d3b0591SJens Wiklander memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN); 7103d3b0591SJens Wiklander memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN); 71111fa71b9SJerome Forissier memcpy(plaintext, msg_test_data, msg_len_test_data[i]); 7123d3b0591SJens Wiklander 71311fa71b9SJerome Forissier ret = mbedtls_ccm_encrypt_and_tag(&ctx, msg_len_test_data[i], 71411fa71b9SJerome Forissier iv_test_data, iv_len_test_data[i], 71511fa71b9SJerome Forissier ad_test_data, add_len_test_data[i], 7163d3b0591SJens Wiklander plaintext, ciphertext, 71711fa71b9SJerome Forissier ciphertext + msg_len_test_data[i], 71811fa71b9SJerome Forissier tag_len_test_data[i]); 719817466cbSJens Wiklander 720817466cbSJens Wiklander if (ret != 0 || 72111fa71b9SJerome Forissier memcmp(ciphertext, res_test_data[i], 72232b31808SJens Wiklander msg_len_test_data[i] + tag_len_test_data[i]) != 0) { 72332b31808SJens Wiklander if (verbose != 0) { 724817466cbSJens Wiklander mbedtls_printf("failed\n"); 72532b31808SJens Wiklander } 726817466cbSJens Wiklander 72732b31808SJens Wiklander return 1; 728817466cbSJens Wiklander } 7293d3b0591SJens Wiklander memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN); 730817466cbSJens Wiklander 73111fa71b9SJerome Forissier ret = mbedtls_ccm_auth_decrypt(&ctx, msg_len_test_data[i], 73211fa71b9SJerome Forissier iv_test_data, iv_len_test_data[i], 73311fa71b9SJerome Forissier ad_test_data, add_len_test_data[i], 7343d3b0591SJens Wiklander ciphertext, plaintext, 73511fa71b9SJerome Forissier ciphertext + msg_len_test_data[i], 73611fa71b9SJerome Forissier tag_len_test_data[i]); 737817466cbSJens Wiklander 738817466cbSJens Wiklander if (ret != 0 || 73932b31808SJens Wiklander memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) { 74032b31808SJens Wiklander if (verbose != 0) { 741817466cbSJens Wiklander mbedtls_printf("failed\n"); 742817466cbSJens Wiklander } 743817466cbSJens Wiklander 74432b31808SJens Wiklander return 1; 74532b31808SJens Wiklander } 74632b31808SJens Wiklander 74732b31808SJens Wiklander if (verbose != 0) { 748817466cbSJens Wiklander mbedtls_printf("passed\n"); 749817466cbSJens Wiklander } 75032b31808SJens Wiklander } 751817466cbSJens Wiklander 752817466cbSJens Wiklander mbedtls_ccm_free(&ctx); 753817466cbSJens Wiklander 75432b31808SJens Wiklander if (verbose != 0) { 755817466cbSJens Wiklander mbedtls_printf("\n"); 75632b31808SJens Wiklander } 757817466cbSJens Wiklander 75832b31808SJens Wiklander return 0; 759817466cbSJens Wiklander } 760817466cbSJens Wiklander 761817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ 762817466cbSJens Wiklander 763817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */ 764