1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * NIST SP800-38C compliant CCM implementation 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 57901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander */ 19817466cbSJens Wiklander 20817466cbSJens Wiklander /* 21817466cbSJens Wiklander * Definition of CCM: 22817466cbSJens Wiklander * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf 23817466cbSJens Wiklander * RFC 3610 "Counter with CBC-MAC (CCM)" 24817466cbSJens Wiklander * 25817466cbSJens Wiklander * Related: 26817466cbSJens Wiklander * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" 27817466cbSJens Wiklander */ 28817466cbSJens Wiklander 297901324dSJerome Forissier #include "common.h" 30817466cbSJens Wiklander 31817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C) 32817466cbSJens Wiklander 33817466cbSJens Wiklander #include "mbedtls/ccm.h" 343d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 3511fa71b9SJerome Forissier #include "mbedtls/error.h" 36817466cbSJens Wiklander 37817466cbSJens Wiklander #include <string.h> 38817466cbSJens Wiklander 39817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 40817466cbSJens Wiklander #include "mbedtls/platform.h" 41817466cbSJens Wiklander #else 42*32b31808SJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) 43817466cbSJens Wiklander #include <stdio.h> 44817466cbSJens Wiklander #define mbedtls_printf printf 45817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ 46*32b31808SJens Wiklander #endif /* MBEDTLS_PLATFORM_C */ 47817466cbSJens Wiklander 483d3b0591SJens Wiklander #if !defined(MBEDTLS_CCM_ALT) 493d3b0591SJens Wiklander 50817466cbSJens Wiklander 51817466cbSJens Wiklander /* 52817466cbSJens Wiklander * Initialize context 53817466cbSJens Wiklander */ 54817466cbSJens Wiklander void mbedtls_ccm_init(mbedtls_ccm_context *ctx) 55817466cbSJens Wiklander { 56817466cbSJens Wiklander memset(ctx, 0, sizeof(mbedtls_ccm_context)); 57817466cbSJens Wiklander } 58817466cbSJens Wiklander 59817466cbSJens Wiklander int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx, 60817466cbSJens Wiklander mbedtls_cipher_id_t cipher, 61817466cbSJens Wiklander const unsigned char *key, 62817466cbSJens Wiklander unsigned int keybits) 63817466cbSJens Wiklander { 6411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 65817466cbSJens Wiklander const mbedtls_cipher_info_t *cipher_info; 66817466cbSJens Wiklander 6711fa71b9SJerome Forissier cipher_info = mbedtls_cipher_info_from_values(cipher, keybits, 6811fa71b9SJerome Forissier MBEDTLS_MODE_ECB); 69*32b31808SJens Wiklander if (cipher_info == NULL) { 70*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 71*32b31808SJens Wiklander } 72817466cbSJens Wiklander 73*32b31808SJens Wiklander if (cipher_info->block_size != 16) { 74*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 75*32b31808SJens Wiklander } 76817466cbSJens Wiklander 77817466cbSJens Wiklander mbedtls_cipher_free(&ctx->cipher_ctx); 78817466cbSJens Wiklander 79*32b31808SJens Wiklander if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) { 80*32b31808SJens Wiklander return ret; 81817466cbSJens Wiklander } 82817466cbSJens Wiklander 83*32b31808SJens Wiklander if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits, 84*32b31808SJens Wiklander MBEDTLS_ENCRYPT)) != 0) { 85*32b31808SJens Wiklander return ret; 86*32b31808SJens Wiklander } 87*32b31808SJens Wiklander 88*32b31808SJens Wiklander return 0; 89817466cbSJens Wiklander } 90817466cbSJens Wiklander 91817466cbSJens Wiklander /* 92817466cbSJens Wiklander * Free context 93817466cbSJens Wiklander */ 94817466cbSJens Wiklander void mbedtls_ccm_free(mbedtls_ccm_context *ctx) 95817466cbSJens Wiklander { 96*32b31808SJens Wiklander if (ctx == NULL) { 973d3b0591SJens Wiklander return; 98*32b31808SJens Wiklander } 99817466cbSJens Wiklander mbedtls_cipher_free(&ctx->cipher_ctx); 1003d3b0591SJens Wiklander mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ccm_context)); 101817466cbSJens Wiklander } 102817466cbSJens Wiklander 103*32b31808SJens Wiklander #define CCM_STATE__CLEAR 0 104*32b31808SJens Wiklander #define CCM_STATE__STARTED (1 << 0) 105*32b31808SJens Wiklander #define CCM_STATE__LENGTHS_SET (1 << 1) 106*32b31808SJens Wiklander #define CCM_STATE__AUTH_DATA_STARTED (1 << 2) 107*32b31808SJens Wiklander #define CCM_STATE__AUTH_DATA_FINISHED (1 << 3) 108*32b31808SJens Wiklander #define CCM_STATE__ERROR (1 << 4) 109817466cbSJens Wiklander 110817466cbSJens Wiklander /* 111817466cbSJens Wiklander * Encrypt or decrypt a partial block with CTR 112817466cbSJens Wiklander */ 113*32b31808SJens Wiklander static int mbedtls_ccm_crypt(mbedtls_ccm_context *ctx, 114*32b31808SJens Wiklander size_t offset, size_t use_len, 115*32b31808SJens Wiklander const unsigned char *input, 116*32b31808SJens Wiklander unsigned char *output) 117*32b31808SJens Wiklander { 118*32b31808SJens Wiklander size_t olen = 0; 119*32b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 120*32b31808SJens Wiklander unsigned char tmp_buf[16] = { 0 }; 121817466cbSJens Wiklander 122*32b31808SJens Wiklander if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->ctr, 16, tmp_buf, 123*32b31808SJens Wiklander &olen)) != 0) { 124*32b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 125*32b31808SJens Wiklander mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf)); 126*32b31808SJens Wiklander return ret; 127*32b31808SJens Wiklander } 128*32b31808SJens Wiklander 129*32b31808SJens Wiklander mbedtls_xor(output, input, tmp_buf + offset, use_len); 130*32b31808SJens Wiklander 131*32b31808SJens Wiklander mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf)); 132*32b31808SJens Wiklander return ret; 133*32b31808SJens Wiklander } 134*32b31808SJens Wiklander 135*32b31808SJens Wiklander static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx) 136*32b31808SJens Wiklander { 137*32b31808SJens Wiklander ctx->state = CCM_STATE__CLEAR; 138*32b31808SJens Wiklander memset(ctx->y, 0, 16); 139*32b31808SJens Wiklander memset(ctx->ctr, 0, 16); 140*32b31808SJens Wiklander } 141*32b31808SJens Wiklander 142*32b31808SJens Wiklander static int ccm_calculate_first_block_if_ready(mbedtls_ccm_context *ctx) 143817466cbSJens Wiklander { 14411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 145817466cbSJens Wiklander unsigned char i; 146817466cbSJens Wiklander size_t len_left, olen; 147817466cbSJens Wiklander 148*32b31808SJens Wiklander /* length calculation can be done only after both 149*32b31808SJens Wiklander * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed 150817466cbSJens Wiklander */ 151*32b31808SJens Wiklander if (!(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGTHS_SET)) { 152*32b31808SJens Wiklander return 0; 153*32b31808SJens Wiklander } 154817466cbSJens Wiklander 155*32b31808SJens Wiklander /* CCM expects non-empty tag. 156*32b31808SJens Wiklander * CCM* allows empty tag. For CCM* without tag, ignore plaintext length. 157*32b31808SJens Wiklander */ 158*32b31808SJens Wiklander if (ctx->tag_len == 0) { 159*32b31808SJens Wiklander if (ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT || ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) { 160*32b31808SJens Wiklander ctx->plaintext_len = 0; 161*32b31808SJens Wiklander } else { 162*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 163*32b31808SJens Wiklander } 164*32b31808SJens Wiklander } 165817466cbSJens Wiklander 166817466cbSJens Wiklander /* 167*32b31808SJens Wiklander * First block: 168817466cbSJens Wiklander * 0 .. 0 flags 169*32b31808SJens Wiklander * 1 .. iv_len nonce (aka iv) - set by: mbedtls_ccm_starts() 170817466cbSJens Wiklander * iv_len+1 .. 15 length 171817466cbSJens Wiklander * 172817466cbSJens Wiklander * With flags as (bits): 173817466cbSJens Wiklander * 7 0 174817466cbSJens Wiklander * 6 add present? 175817466cbSJens Wiklander * 5 .. 3 (t - 2) / 2 176817466cbSJens Wiklander * 2 .. 0 q - 1 177817466cbSJens Wiklander */ 178*32b31808SJens Wiklander ctx->y[0] |= (ctx->add_len > 0) << 6; 179*32b31808SJens Wiklander ctx->y[0] |= ((ctx->tag_len - 2) / 2) << 3; 180*32b31808SJens Wiklander ctx->y[0] |= ctx->q - 1; 181817466cbSJens Wiklander 182*32b31808SJens Wiklander for (i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8) { 183*32b31808SJens Wiklander ctx->y[15-i] = MBEDTLS_BYTE_0(len_left); 184*32b31808SJens Wiklander } 185817466cbSJens Wiklander 186*32b31808SJens Wiklander if (len_left > 0) { 187*32b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 188*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 189*32b31808SJens Wiklander } 190817466cbSJens Wiklander 191817466cbSJens Wiklander /* Start CBC-MAC with first block*/ 192*32b31808SJens Wiklander if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen)) != 0) { 193*32b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 194*32b31808SJens Wiklander return ret; 195817466cbSJens Wiklander } 196*32b31808SJens Wiklander 197*32b31808SJens Wiklander return 0; 198817466cbSJens Wiklander } 199817466cbSJens Wiklander 200*32b31808SJens Wiklander int mbedtls_ccm_starts(mbedtls_ccm_context *ctx, 201*32b31808SJens Wiklander int mode, 202*32b31808SJens Wiklander const unsigned char *iv, 203*32b31808SJens Wiklander size_t iv_len) 204*32b31808SJens Wiklander { 205*32b31808SJens Wiklander /* Also implies q is within bounds */ 206*32b31808SJens Wiklander if (iv_len < 7 || iv_len > 13) { 207*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 208*32b31808SJens Wiklander } 209*32b31808SJens Wiklander 210*32b31808SJens Wiklander ctx->mode = mode; 211*32b31808SJens Wiklander ctx->q = 16 - 1 - (unsigned char) iv_len; 212*32b31808SJens Wiklander 213817466cbSJens Wiklander /* 214817466cbSJens Wiklander * Prepare counter block for encryption: 215817466cbSJens Wiklander * 0 .. 0 flags 216817466cbSJens Wiklander * 1 .. iv_len nonce (aka iv) 217817466cbSJens Wiklander * iv_len+1 .. 15 counter (initially 1) 218817466cbSJens Wiklander * 219817466cbSJens Wiklander * With flags as (bits): 220817466cbSJens Wiklander * 7 .. 3 0 221817466cbSJens Wiklander * 2 .. 0 q - 1 222817466cbSJens Wiklander */ 223*32b31808SJens Wiklander memset(ctx->ctr, 0, 16); 224*32b31808SJens Wiklander ctx->ctr[0] = ctx->q - 1; 225*32b31808SJens Wiklander memcpy(ctx->ctr + 1, iv, iv_len); 226*32b31808SJens Wiklander memset(ctx->ctr + 1 + iv_len, 0, ctx->q); 227*32b31808SJens Wiklander ctx->ctr[15] = 1; 228817466cbSJens Wiklander 229817466cbSJens Wiklander /* 230*32b31808SJens Wiklander * See ccm_calculate_first_block_if_ready() for block layout description 231*32b31808SJens Wiklander */ 232*32b31808SJens Wiklander memcpy(ctx->y + 1, iv, iv_len); 233*32b31808SJens Wiklander 234*32b31808SJens Wiklander ctx->state |= CCM_STATE__STARTED; 235*32b31808SJens Wiklander return ccm_calculate_first_block_if_ready(ctx); 236*32b31808SJens Wiklander } 237*32b31808SJens Wiklander 238*32b31808SJens Wiklander int mbedtls_ccm_set_lengths(mbedtls_ccm_context *ctx, 239*32b31808SJens Wiklander size_t total_ad_len, 240*32b31808SJens Wiklander size_t plaintext_len, 241*32b31808SJens Wiklander size_t tag_len) 242*32b31808SJens Wiklander { 243*32b31808SJens Wiklander /* 244*32b31808SJens Wiklander * Check length requirements: SP800-38C A.1 245*32b31808SJens Wiklander * Additional requirement: a < 2^16 - 2^8 to simplify the code. 246*32b31808SJens Wiklander * 'length' checked later (when writing it to the first block) 247817466cbSJens Wiklander * 248*32b31808SJens Wiklander * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4). 249817466cbSJens Wiklander */ 250*32b31808SJens Wiklander if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0) { 251*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 252817466cbSJens Wiklander } 253817466cbSJens Wiklander 254*32b31808SJens Wiklander if (total_ad_len >= 0xFF00) { 255*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 256817466cbSJens Wiklander } 257817466cbSJens Wiklander 258*32b31808SJens Wiklander ctx->plaintext_len = plaintext_len; 259*32b31808SJens Wiklander ctx->add_len = total_ad_len; 260*32b31808SJens Wiklander ctx->tag_len = tag_len; 261*32b31808SJens Wiklander ctx->processed = 0; 262817466cbSJens Wiklander 263*32b31808SJens Wiklander ctx->state |= CCM_STATE__LENGTHS_SET; 264*32b31808SJens Wiklander return ccm_calculate_first_block_if_ready(ctx); 265*32b31808SJens Wiklander } 266*32b31808SJens Wiklander 267*32b31808SJens Wiklander int mbedtls_ccm_update_ad(mbedtls_ccm_context *ctx, 268*32b31808SJens Wiklander const unsigned char *add, 269*32b31808SJens Wiklander size_t add_len) 270*32b31808SJens Wiklander { 271*32b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 272*32b31808SJens Wiklander size_t olen, use_len, offset; 273*32b31808SJens Wiklander 274*32b31808SJens Wiklander if (ctx->state & CCM_STATE__ERROR) { 275*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 276*32b31808SJens Wiklander } 277*32b31808SJens Wiklander 278*32b31808SJens Wiklander if (add_len > 0) { 279*32b31808SJens Wiklander if (ctx->state & CCM_STATE__AUTH_DATA_FINISHED) { 280*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 281*32b31808SJens Wiklander } 282*32b31808SJens Wiklander 283*32b31808SJens Wiklander if (!(ctx->state & CCM_STATE__AUTH_DATA_STARTED)) { 284*32b31808SJens Wiklander if (add_len > ctx->add_len) { 285*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 286*32b31808SJens Wiklander } 287*32b31808SJens Wiklander 288*32b31808SJens Wiklander ctx->y[0] ^= (unsigned char) ((ctx->add_len >> 8) & 0xFF); 289*32b31808SJens Wiklander ctx->y[1] ^= (unsigned char) ((ctx->add_len) & 0xFF); 290*32b31808SJens Wiklander 291*32b31808SJens Wiklander ctx->state |= CCM_STATE__AUTH_DATA_STARTED; 292*32b31808SJens Wiklander } else if (ctx->processed + add_len > ctx->add_len) { 293*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 294*32b31808SJens Wiklander } 295*32b31808SJens Wiklander 296*32b31808SJens Wiklander while (add_len > 0) { 297*32b31808SJens Wiklander offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1] 298*32b31808SJens Wiklander * holding total auth data length */ 299*32b31808SJens Wiklander use_len = 16 - offset; 300*32b31808SJens Wiklander 301*32b31808SJens Wiklander if (use_len > add_len) { 302*32b31808SJens Wiklander use_len = add_len; 303*32b31808SJens Wiklander } 304*32b31808SJens Wiklander 305*32b31808SJens Wiklander mbedtls_xor(ctx->y + offset, ctx->y + offset, add, use_len); 306*32b31808SJens Wiklander 307*32b31808SJens Wiklander ctx->processed += use_len; 308*32b31808SJens Wiklander add_len -= use_len; 309*32b31808SJens Wiklander add += use_len; 310*32b31808SJens Wiklander 311*32b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->add_len) { 312*32b31808SJens Wiklander if ((ret = 313*32b31808SJens Wiklander mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen)) != 0) { 314*32b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 315*32b31808SJens Wiklander return ret; 316*32b31808SJens Wiklander } 317*32b31808SJens Wiklander } 318*32b31808SJens Wiklander } 319*32b31808SJens Wiklander 320*32b31808SJens Wiklander if (ctx->processed == ctx->add_len) { 321*32b31808SJens Wiklander ctx->state |= CCM_STATE__AUTH_DATA_FINISHED; 322*32b31808SJens Wiklander ctx->processed = 0; // prepare for mbedtls_ccm_update() 323*32b31808SJens Wiklander } 324*32b31808SJens Wiklander } 325*32b31808SJens Wiklander 326*32b31808SJens Wiklander return 0; 327*32b31808SJens Wiklander } 328*32b31808SJens Wiklander 329*32b31808SJens Wiklander int mbedtls_ccm_update(mbedtls_ccm_context *ctx, 330*32b31808SJens Wiklander const unsigned char *input, size_t input_len, 331*32b31808SJens Wiklander unsigned char *output, size_t output_size, 332*32b31808SJens Wiklander size_t *output_len) 333*32b31808SJens Wiklander { 334*32b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 335*32b31808SJens Wiklander unsigned char i; 336*32b31808SJens Wiklander size_t use_len, offset, olen; 337*32b31808SJens Wiklander 338*32b31808SJens Wiklander unsigned char local_output[16]; 339*32b31808SJens Wiklander 340*32b31808SJens Wiklander if (ctx->state & CCM_STATE__ERROR) { 341*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 342*32b31808SJens Wiklander } 343*32b31808SJens Wiklander 344*32b31808SJens Wiklander /* Check against plaintext length only if performing operation with 345*32b31808SJens Wiklander * authentication 346817466cbSJens Wiklander */ 347*32b31808SJens Wiklander if (ctx->tag_len != 0 && ctx->processed + input_len > ctx->plaintext_len) { 348*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 349*32b31808SJens Wiklander } 350*32b31808SJens Wiklander 351*32b31808SJens Wiklander if (output_size < input_len) { 352*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 353*32b31808SJens Wiklander } 354*32b31808SJens Wiklander *output_len = input_len; 355*32b31808SJens Wiklander 356*32b31808SJens Wiklander ret = 0; 357*32b31808SJens Wiklander 358*32b31808SJens Wiklander while (input_len > 0) { 359*32b31808SJens Wiklander offset = ctx->processed % 16; 360*32b31808SJens Wiklander 361*32b31808SJens Wiklander use_len = 16 - offset; 362*32b31808SJens Wiklander 363*32b31808SJens Wiklander if (use_len > input_len) { 364*32b31808SJens Wiklander use_len = input_len; 365*32b31808SJens Wiklander } 366*32b31808SJens Wiklander 367*32b31808SJens Wiklander ctx->processed += use_len; 368*32b31808SJens Wiklander 369*32b31808SJens Wiklander if (ctx->mode == MBEDTLS_CCM_ENCRYPT || \ 370*32b31808SJens Wiklander ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT) { 371*32b31808SJens Wiklander mbedtls_xor(ctx->y + offset, ctx->y + offset, input, use_len); 372*32b31808SJens Wiklander 373*32b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) { 374*32b31808SJens Wiklander if ((ret = 375*32b31808SJens Wiklander mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen)) != 0) { 376*32b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 377*32b31808SJens Wiklander goto exit; 378*32b31808SJens Wiklander } 379*32b31808SJens Wiklander } 380*32b31808SJens Wiklander 381*32b31808SJens Wiklander ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, output); 382*32b31808SJens Wiklander if (ret != 0) { 383*32b31808SJens Wiklander goto exit; 384*32b31808SJens Wiklander } 385*32b31808SJens Wiklander } 386*32b31808SJens Wiklander 387*32b31808SJens Wiklander if (ctx->mode == MBEDTLS_CCM_DECRYPT || \ 388*32b31808SJens Wiklander ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) { 389*32b31808SJens Wiklander /* Since output may be in shared memory, we cannot be sure that 390*32b31808SJens Wiklander * it will contain what we wrote to it. Therefore, we should avoid using 391*32b31808SJens Wiklander * it as input to any operations. 392*32b31808SJens Wiklander * Write decrypted data to local_output to avoid using output variable as 393*32b31808SJens Wiklander * input in the XOR operation for Y. 394*32b31808SJens Wiklander */ 395*32b31808SJens Wiklander ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, local_output); 396*32b31808SJens Wiklander if (ret != 0) { 397*32b31808SJens Wiklander goto exit; 398*32b31808SJens Wiklander } 399*32b31808SJens Wiklander 400*32b31808SJens Wiklander mbedtls_xor(ctx->y + offset, ctx->y + offset, local_output, use_len); 401*32b31808SJens Wiklander 402*32b31808SJens Wiklander memcpy(output, local_output, use_len); 403*32b31808SJens Wiklander mbedtls_platform_zeroize(local_output, 16); 404*32b31808SJens Wiklander 405*32b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) { 406*32b31808SJens Wiklander if ((ret = 407*32b31808SJens Wiklander mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen)) != 0) { 408*32b31808SJens Wiklander ctx->state |= CCM_STATE__ERROR; 409*32b31808SJens Wiklander goto exit; 410*32b31808SJens Wiklander } 411*32b31808SJens Wiklander } 412*32b31808SJens Wiklander } 413*32b31808SJens Wiklander 414*32b31808SJens Wiklander if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) { 415*32b31808SJens Wiklander for (i = 0; i < ctx->q; i++) { 416*32b31808SJens Wiklander if (++(ctx->ctr)[15-i] != 0) { 417817466cbSJens Wiklander break; 418817466cbSJens Wiklander } 419*32b31808SJens Wiklander } 420*32b31808SJens Wiklander } 421*32b31808SJens Wiklander 422*32b31808SJens Wiklander input_len -= use_len; 423*32b31808SJens Wiklander input += use_len; 424*32b31808SJens Wiklander output += use_len; 425*32b31808SJens Wiklander } 426*32b31808SJens Wiklander 427*32b31808SJens Wiklander exit: 428*32b31808SJens Wiklander mbedtls_platform_zeroize(local_output, 16); 429*32b31808SJens Wiklander 430*32b31808SJens Wiklander return ret; 431*32b31808SJens Wiklander } 432*32b31808SJens Wiklander 433*32b31808SJens Wiklander int mbedtls_ccm_finish(mbedtls_ccm_context *ctx, 434*32b31808SJens Wiklander unsigned char *tag, size_t tag_len) 435*32b31808SJens Wiklander { 436*32b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 437*32b31808SJens Wiklander unsigned char i; 438*32b31808SJens Wiklander 439*32b31808SJens Wiklander if (ctx->state & CCM_STATE__ERROR) { 440*32b31808SJens Wiklander return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 441*32b31808SJens Wiklander } 442*32b31808SJens Wiklander 443*32b31808SJens Wiklander if (ctx->add_len > 0 && !(ctx->state & CCM_STATE__AUTH_DATA_FINISHED)) { 444*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 445*32b31808SJens Wiklander } 446*32b31808SJens Wiklander 447*32b31808SJens Wiklander if (ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len) { 448*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_BAD_INPUT; 449*32b31808SJens Wiklander } 450817466cbSJens Wiklander 451817466cbSJens Wiklander /* 452817466cbSJens Wiklander * Authentication: reset counter and crypt/mask internal tag 453817466cbSJens Wiklander */ 454*32b31808SJens Wiklander for (i = 0; i < ctx->q; i++) { 455*32b31808SJens Wiklander ctx->ctr[15-i] = 0; 456*32b31808SJens Wiklander } 457817466cbSJens Wiklander 458*32b31808SJens Wiklander ret = mbedtls_ccm_crypt(ctx, 0, 16, ctx->y, ctx->y); 459*32b31808SJens Wiklander if (ret != 0) { 460*32b31808SJens Wiklander return ret; 461*32b31808SJens Wiklander } 462*32b31808SJens Wiklander if (tag != NULL) { 463*32b31808SJens Wiklander memcpy(tag, ctx->y, tag_len); 464*32b31808SJens Wiklander } 465*32b31808SJens Wiklander mbedtls_ccm_clear_state(ctx); 466817466cbSJens Wiklander 467*32b31808SJens Wiklander return 0; 468*32b31808SJens Wiklander } 469*32b31808SJens Wiklander 470*32b31808SJens Wiklander /* 471*32b31808SJens Wiklander * Authenticated encryption or decryption 472*32b31808SJens Wiklander */ 473*32b31808SJens Wiklander static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length, 474*32b31808SJens Wiklander const unsigned char *iv, size_t iv_len, 475*32b31808SJens Wiklander const unsigned char *add, size_t add_len, 476*32b31808SJens Wiklander const unsigned char *input, unsigned char *output, 477*32b31808SJens Wiklander unsigned char *tag, size_t tag_len) 478*32b31808SJens Wiklander { 479*32b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 480*32b31808SJens Wiklander size_t olen; 481*32b31808SJens Wiklander 482*32b31808SJens Wiklander if ((ret = mbedtls_ccm_starts(ctx, mode, iv, iv_len)) != 0) { 483*32b31808SJens Wiklander return ret; 484*32b31808SJens Wiklander } 485*32b31808SJens Wiklander 486*32b31808SJens Wiklander if ((ret = mbedtls_ccm_set_lengths(ctx, add_len, length, tag_len)) != 0) { 487*32b31808SJens Wiklander return ret; 488*32b31808SJens Wiklander } 489*32b31808SJens Wiklander 490*32b31808SJens Wiklander if ((ret = mbedtls_ccm_update_ad(ctx, add, add_len)) != 0) { 491*32b31808SJens Wiklander return ret; 492*32b31808SJens Wiklander } 493*32b31808SJens Wiklander 494*32b31808SJens Wiklander if ((ret = mbedtls_ccm_update(ctx, input, length, 495*32b31808SJens Wiklander output, length, &olen)) != 0) { 496*32b31808SJens Wiklander return ret; 497*32b31808SJens Wiklander } 498*32b31808SJens Wiklander 499*32b31808SJens Wiklander if ((ret = mbedtls_ccm_finish(ctx, tag, tag_len)) != 0) { 500*32b31808SJens Wiklander return ret; 501*32b31808SJens Wiklander } 502*32b31808SJens Wiklander 503*32b31808SJens Wiklander return 0; 504817466cbSJens Wiklander } 505817466cbSJens Wiklander 506817466cbSJens Wiklander /* 507817466cbSJens Wiklander * Authenticated encryption 508817466cbSJens Wiklander */ 5093d3b0591SJens Wiklander int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, 5103d3b0591SJens Wiklander const unsigned char *iv, size_t iv_len, 5113d3b0591SJens Wiklander const unsigned char *add, size_t add_len, 5123d3b0591SJens Wiklander const unsigned char *input, unsigned char *output, 5133d3b0591SJens Wiklander unsigned char *tag, size_t tag_len) 5143d3b0591SJens Wiklander { 515*32b31808SJens Wiklander return ccm_auth_crypt(ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len, 516*32b31808SJens Wiklander add, add_len, input, output, tag, tag_len); 5173d3b0591SJens Wiklander } 5183d3b0591SJens Wiklander 519817466cbSJens Wiklander int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length, 520817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 521817466cbSJens Wiklander const unsigned char *add, size_t add_len, 522817466cbSJens Wiklander const unsigned char *input, unsigned char *output, 523817466cbSJens Wiklander unsigned char *tag, size_t tag_len) 524817466cbSJens Wiklander { 525*32b31808SJens Wiklander return ccm_auth_crypt(ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len, 526*32b31808SJens Wiklander add, add_len, input, output, tag, tag_len); 527817466cbSJens Wiklander } 528817466cbSJens Wiklander 529817466cbSJens Wiklander /* 530817466cbSJens Wiklander * Authenticated decryption 531817466cbSJens Wiklander */ 532*32b31808SJens Wiklander static int mbedtls_ccm_compare_tags(const unsigned char *tag1, 533*32b31808SJens Wiklander const unsigned char *tag2, 534*32b31808SJens Wiklander size_t tag_len) 535*32b31808SJens Wiklander { 536*32b31808SJens Wiklander unsigned char i; 537*32b31808SJens Wiklander int diff; 538*32b31808SJens Wiklander 539*32b31808SJens Wiklander /* Check tag in "constant-time" */ 540*32b31808SJens Wiklander for (diff = 0, i = 0; i < tag_len; i++) { 541*32b31808SJens Wiklander diff |= tag1[i] ^ tag2[i]; 542*32b31808SJens Wiklander } 543*32b31808SJens Wiklander 544*32b31808SJens Wiklander if (diff != 0) { 545*32b31808SJens Wiklander return MBEDTLS_ERR_CCM_AUTH_FAILED; 546*32b31808SJens Wiklander } 547*32b31808SJens Wiklander 548*32b31808SJens Wiklander return 0; 549*32b31808SJens Wiklander } 550*32b31808SJens Wiklander 551*32b31808SJens Wiklander static int ccm_auth_decrypt(mbedtls_ccm_context *ctx, int mode, size_t length, 552817466cbSJens Wiklander const unsigned char *iv, size_t iv_len, 553817466cbSJens Wiklander const unsigned char *add, size_t add_len, 554817466cbSJens Wiklander const unsigned char *input, unsigned char *output, 555817466cbSJens Wiklander const unsigned char *tag, size_t tag_len) 556817466cbSJens Wiklander { 55711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 558817466cbSJens Wiklander unsigned char check_tag[16]; 559817466cbSJens Wiklander 560*32b31808SJens Wiklander if ((ret = ccm_auth_crypt(ctx, mode, length, 561817466cbSJens Wiklander iv, iv_len, add, add_len, 562*32b31808SJens Wiklander input, output, check_tag, tag_len)) != 0) { 563*32b31808SJens Wiklander return ret; 564817466cbSJens Wiklander } 565817466cbSJens Wiklander 566*32b31808SJens Wiklander if ((ret = mbedtls_ccm_compare_tags(tag, check_tag, tag_len)) != 0) { 5673d3b0591SJens Wiklander mbedtls_platform_zeroize(output, length); 568*32b31808SJens Wiklander return ret; 569817466cbSJens Wiklander } 570817466cbSJens Wiklander 571*32b31808SJens Wiklander return 0; 572*32b31808SJens Wiklander } 573*32b31808SJens Wiklander 574*32b31808SJens Wiklander int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, 575*32b31808SJens Wiklander const unsigned char *iv, size_t iv_len, 576*32b31808SJens Wiklander const unsigned char *add, size_t add_len, 577*32b31808SJens Wiklander const unsigned char *input, unsigned char *output, 578*32b31808SJens Wiklander const unsigned char *tag, size_t tag_len) 579*32b31808SJens Wiklander { 580*32b31808SJens Wiklander return ccm_auth_decrypt(ctx, MBEDTLS_CCM_STAR_DECRYPT, length, 581*32b31808SJens Wiklander iv, iv_len, add, add_len, 582*32b31808SJens Wiklander input, output, tag, tag_len); 583817466cbSJens Wiklander } 584817466cbSJens Wiklander 5853d3b0591SJens Wiklander int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, 5863d3b0591SJens Wiklander const unsigned char *iv, size_t iv_len, 5873d3b0591SJens Wiklander const unsigned char *add, size_t add_len, 5883d3b0591SJens Wiklander const unsigned char *input, unsigned char *output, 5893d3b0591SJens Wiklander const unsigned char *tag, size_t tag_len) 5903d3b0591SJens Wiklander { 591*32b31808SJens Wiklander return ccm_auth_decrypt(ctx, MBEDTLS_CCM_DECRYPT, length, 592*32b31808SJens Wiklander iv, iv_len, add, add_len, 593*32b31808SJens Wiklander input, output, tag, tag_len); 5943d3b0591SJens Wiklander } 5953d3b0591SJens Wiklander #endif /* !MBEDTLS_CCM_ALT */ 596817466cbSJens Wiklander 597817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) 598817466cbSJens Wiklander /* 599817466cbSJens Wiklander * Examples 1 to 3 from SP800-38C Appendix C 600817466cbSJens Wiklander */ 601817466cbSJens Wiklander 602817466cbSJens Wiklander #define NB_TESTS 3 6033d3b0591SJens Wiklander #define CCM_SELFTEST_PT_MAX_LEN 24 6043d3b0591SJens Wiklander #define CCM_SELFTEST_CT_MAX_LEN 32 605817466cbSJens Wiklander /* 606817466cbSJens Wiklander * The data is the same for all tests, only the used length changes 607817466cbSJens Wiklander */ 60811fa71b9SJerome Forissier static const unsigned char key_test_data[] = { 609817466cbSJens Wiklander 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 610817466cbSJens Wiklander 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f 611817466cbSJens Wiklander }; 612817466cbSJens Wiklander 61311fa71b9SJerome Forissier static const unsigned char iv_test_data[] = { 614817466cbSJens Wiklander 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 615817466cbSJens Wiklander 0x18, 0x19, 0x1a, 0x1b 616817466cbSJens Wiklander }; 617817466cbSJens Wiklander 61811fa71b9SJerome Forissier static const unsigned char ad_test_data[] = { 619817466cbSJens Wiklander 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 620817466cbSJens Wiklander 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 621817466cbSJens Wiklander 0x10, 0x11, 0x12, 0x13 622817466cbSJens Wiklander }; 623817466cbSJens Wiklander 62411fa71b9SJerome Forissier static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = { 625817466cbSJens Wiklander 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 626817466cbSJens Wiklander 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 627817466cbSJens Wiklander 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 628817466cbSJens Wiklander }; 629817466cbSJens Wiklander 63011fa71b9SJerome Forissier static const size_t iv_len_test_data[NB_TESTS] = { 7, 8, 12 }; 63111fa71b9SJerome Forissier static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 }; 63211fa71b9SJerome Forissier static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 }; 63311fa71b9SJerome Forissier static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 }; 634817466cbSJens Wiklander 63511fa71b9SJerome Forissier static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = { 636817466cbSJens Wiklander { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, 637817466cbSJens Wiklander { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, 638817466cbSJens Wiklander 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, 639817466cbSJens Wiklander 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, 640817466cbSJens Wiklander { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 641817466cbSJens Wiklander 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 642817466cbSJens Wiklander 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 643817466cbSJens Wiklander 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } 644817466cbSJens Wiklander }; 645817466cbSJens Wiklander 646817466cbSJens Wiklander int mbedtls_ccm_self_test(int verbose) 647817466cbSJens Wiklander { 648817466cbSJens Wiklander mbedtls_ccm_context ctx; 6493d3b0591SJens Wiklander /* 6503d3b0591SJens Wiklander * Some hardware accelerators require the input and output buffers 6513d3b0591SJens Wiklander * would be in RAM, because the flash is not accessible. 6523d3b0591SJens Wiklander * Use buffers on the stack to hold the test vectors data. 6533d3b0591SJens Wiklander */ 6543d3b0591SJens Wiklander unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN]; 6553d3b0591SJens Wiklander unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN]; 656817466cbSJens Wiklander size_t i; 65711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 658817466cbSJens Wiklander 659817466cbSJens Wiklander mbedtls_ccm_init(&ctx); 660817466cbSJens Wiklander 66111fa71b9SJerome Forissier if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data, 662*32b31808SJens Wiklander 8 * sizeof(key_test_data)) != 0) { 663*32b31808SJens Wiklander if (verbose != 0) { 664817466cbSJens Wiklander mbedtls_printf(" CCM: setup failed"); 665817466cbSJens Wiklander } 666817466cbSJens Wiklander 667*32b31808SJens Wiklander return 1; 668*32b31808SJens Wiklander } 669*32b31808SJens Wiklander 670*32b31808SJens Wiklander for (i = 0; i < NB_TESTS; i++) { 671*32b31808SJens Wiklander if (verbose != 0) { 672817466cbSJens Wiklander mbedtls_printf(" CCM-AES #%u: ", (unsigned int) i + 1); 673*32b31808SJens Wiklander } 674817466cbSJens Wiklander 6753d3b0591SJens Wiklander memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN); 6763d3b0591SJens Wiklander memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN); 67711fa71b9SJerome Forissier memcpy(plaintext, msg_test_data, msg_len_test_data[i]); 6783d3b0591SJens Wiklander 67911fa71b9SJerome Forissier ret = mbedtls_ccm_encrypt_and_tag(&ctx, msg_len_test_data[i], 68011fa71b9SJerome Forissier iv_test_data, iv_len_test_data[i], 68111fa71b9SJerome Forissier ad_test_data, add_len_test_data[i], 6823d3b0591SJens Wiklander plaintext, ciphertext, 68311fa71b9SJerome Forissier ciphertext + msg_len_test_data[i], 68411fa71b9SJerome Forissier tag_len_test_data[i]); 685817466cbSJens Wiklander 686817466cbSJens Wiklander if (ret != 0 || 68711fa71b9SJerome Forissier memcmp(ciphertext, res_test_data[i], 688*32b31808SJens Wiklander msg_len_test_data[i] + tag_len_test_data[i]) != 0) { 689*32b31808SJens Wiklander if (verbose != 0) { 690817466cbSJens Wiklander mbedtls_printf("failed\n"); 691*32b31808SJens Wiklander } 692817466cbSJens Wiklander 693*32b31808SJens Wiklander return 1; 694817466cbSJens Wiklander } 6953d3b0591SJens Wiklander memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN); 696817466cbSJens Wiklander 69711fa71b9SJerome Forissier ret = mbedtls_ccm_auth_decrypt(&ctx, msg_len_test_data[i], 69811fa71b9SJerome Forissier iv_test_data, iv_len_test_data[i], 69911fa71b9SJerome Forissier ad_test_data, add_len_test_data[i], 7003d3b0591SJens Wiklander ciphertext, plaintext, 70111fa71b9SJerome Forissier ciphertext + msg_len_test_data[i], 70211fa71b9SJerome Forissier tag_len_test_data[i]); 703817466cbSJens Wiklander 704817466cbSJens Wiklander if (ret != 0 || 705*32b31808SJens Wiklander memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) { 706*32b31808SJens Wiklander if (verbose != 0) { 707817466cbSJens Wiklander mbedtls_printf("failed\n"); 708817466cbSJens Wiklander } 709817466cbSJens Wiklander 710*32b31808SJens Wiklander return 1; 711*32b31808SJens Wiklander } 712*32b31808SJens Wiklander 713*32b31808SJens Wiklander if (verbose != 0) { 714817466cbSJens Wiklander mbedtls_printf("passed\n"); 715817466cbSJens Wiklander } 716*32b31808SJens Wiklander } 717817466cbSJens Wiklander 718817466cbSJens Wiklander mbedtls_ccm_free(&ctx); 719817466cbSJens Wiklander 720*32b31808SJens Wiklander if (verbose != 0) { 721817466cbSJens Wiklander mbedtls_printf("\n"); 722*32b31808SJens Wiklander } 723817466cbSJens Wiklander 724*32b31808SJens Wiklander return 0; 725817466cbSJens Wiklander } 726817466cbSJens Wiklander 727817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ 728817466cbSJens Wiklander 729817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */ 730