quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ccm.c (23446B)


      1 /*
      2  *  NIST SP800-38C compliant CCM implementation
      3  *
      4  *  Copyright The Mbed TLS Contributors
      5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
      6  */
      7 
      8 /*
      9  * Definition of CCM:
     10  * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
     11  * RFC 3610 "Counter with CBC-MAC (CCM)"
     12  *
     13  * Related:
     14  * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
     15  */
     16 
     17 #include "common.h"
     18 
     19 #if defined(MBEDTLS_CCM_C)
     20 
     21 #include "mbedtls/ccm.h"
     22 #include "mbedtls/platform_util.h"
     23 #include "mbedtls/error.h"
     24 #include "mbedtls/constant_time.h"
     25 
     26 #if defined(MBEDTLS_BLOCK_CIPHER_C)
     27 #include "block_cipher_internal.h"
     28 #endif
     29 
     30 #include <string.h>
     31 
     32 #if defined(MBEDTLS_PLATFORM_C)
     33 #include "mbedtls/platform.h"
     34 #else
     35 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
     36 #include <stdio.h>
     37 #define mbedtls_printf printf
     38 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
     39 #endif /* MBEDTLS_PLATFORM_C */
     40 
     41 #if !defined(MBEDTLS_CCM_ALT)
     42 
     43 
     44 /*
     45  * Initialize context
     46  */
     47 void mbedtls_ccm_init(mbedtls_ccm_context *ctx)
     48 {
     49     memset(ctx, 0, sizeof(mbedtls_ccm_context));
     50 }
     51 
     52 int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx,
     53                        mbedtls_cipher_id_t cipher,
     54                        const unsigned char *key,
     55                        unsigned int keybits)
     56 {
     57     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     58 
     59 #if defined(MBEDTLS_BLOCK_CIPHER_C)
     60     mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
     61 
     62     if ((ret = mbedtls_block_cipher_setup(&ctx->block_cipher_ctx, cipher)) != 0) {
     63         return MBEDTLS_ERR_CCM_BAD_INPUT;
     64     }
     65 
     66     if ((ret = mbedtls_block_cipher_setkey(&ctx->block_cipher_ctx, key, keybits)) != 0) {
     67         return MBEDTLS_ERR_CCM_BAD_INPUT;
     68     }
     69 #else
     70     const mbedtls_cipher_info_t *cipher_info;
     71 
     72     cipher_info = mbedtls_cipher_info_from_values(cipher, keybits,
     73                                                   MBEDTLS_MODE_ECB);
     74     if (cipher_info == NULL) {
     75         return MBEDTLS_ERR_CCM_BAD_INPUT;
     76     }
     77 
     78     if (mbedtls_cipher_info_get_block_size(cipher_info) != 16) {
     79         return MBEDTLS_ERR_CCM_BAD_INPUT;
     80     }
     81 
     82     mbedtls_cipher_free(&ctx->cipher_ctx);
     83 
     84     if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) {
     85         return ret;
     86     }
     87 
     88     if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
     89                                      MBEDTLS_ENCRYPT)) != 0) {
     90         return ret;
     91     }
     92 #endif
     93 
     94     return ret;
     95 }
     96 
     97 /*
     98  * Free context
     99  */
    100 void mbedtls_ccm_free(mbedtls_ccm_context *ctx)
    101 {
    102     if (ctx == NULL) {
    103         return;
    104     }
    105 #if defined(MBEDTLS_BLOCK_CIPHER_C)
    106     mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
    107 #else
    108     mbedtls_cipher_free(&ctx->cipher_ctx);
    109 #endif
    110     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ccm_context));
    111 }
    112 
    113 #define CCM_STATE__CLEAR                0
    114 #define CCM_STATE__STARTED              (1 << 0)
    115 #define CCM_STATE__LENGTHS_SET          (1 << 1)
    116 #define CCM_STATE__AUTH_DATA_STARTED    (1 << 2)
    117 #define CCM_STATE__AUTH_DATA_FINISHED   (1 << 3)
    118 #define CCM_STATE__ERROR                (1 << 4)
    119 
    120 /*
    121  * Encrypt or decrypt a partial block with CTR
    122  */
    123 static int mbedtls_ccm_crypt(mbedtls_ccm_context *ctx,
    124                              size_t offset, size_t use_len,
    125                              const unsigned char *input,
    126                              unsigned char *output)
    127 {
    128     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    129     unsigned char tmp_buf[16] = { 0 };
    130 
    131 #if defined(MBEDTLS_BLOCK_CIPHER_C)
    132     ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->ctr, tmp_buf);
    133 #else
    134     size_t olen = 0;
    135     ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->ctr, 16, tmp_buf, &olen);
    136 #endif
    137     if (ret != 0) {
    138         ctx->state |= CCM_STATE__ERROR;
    139         mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
    140         return ret;
    141     }
    142 
    143     mbedtls_xor(output, input, tmp_buf + offset, use_len);
    144 
    145     mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
    146     return ret;
    147 }
    148 
    149 static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx)
    150 {
    151     ctx->state = CCM_STATE__CLEAR;
    152     memset(ctx->y, 0, 16);
    153     memset(ctx->ctr, 0, 16);
    154 }
    155 
    156 static int ccm_calculate_first_block_if_ready(mbedtls_ccm_context *ctx)
    157 {
    158     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    159     unsigned char i;
    160     size_t len_left;
    161 #if !defined(MBEDTLS_BLOCK_CIPHER_C)
    162     size_t olen;
    163 #endif
    164 
    165     /* length calculation can be done only after both
    166      * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
    167      */
    168     if (!(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGTHS_SET)) {
    169         return 0;
    170     }
    171 
    172     /* CCM expects non-empty tag.
    173      * CCM* allows empty tag. For CCM* without tag, the tag calculation is skipped.
    174      */
    175     if (ctx->tag_len == 0) {
    176         if (ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT || ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) {
    177             ctx->plaintext_len = 0;
    178             return 0;
    179         } else {
    180             return MBEDTLS_ERR_CCM_BAD_INPUT;
    181         }
    182     }
    183 
    184     /*
    185      * First block:
    186      * 0        .. 0        flags
    187      * 1        .. iv_len   nonce (aka iv)  - set by: mbedtls_ccm_starts()
    188      * iv_len+1 .. 15       length
    189      *
    190      * With flags as (bits):
    191      * 7        0
    192      * 6        add present?
    193      * 5 .. 3   (t - 2) / 2
    194      * 2 .. 0   q - 1
    195      */
    196     ctx->y[0] |= (ctx->add_len > 0) << 6;
    197     ctx->y[0] |= ((ctx->tag_len - 2) / 2) << 3;
    198     ctx->y[0] |= ctx->q - 1;
    199 
    200     for (i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8) {
    201         ctx->y[15-i] = MBEDTLS_BYTE_0(len_left);
    202     }
    203 
    204     if (len_left > 0) {
    205         ctx->state |= CCM_STATE__ERROR;
    206         return MBEDTLS_ERR_CCM_BAD_INPUT;
    207     }
    208 
    209     /* Start CBC-MAC with first block*/
    210 #if defined(MBEDTLS_BLOCK_CIPHER_C)
    211     ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
    212 #else
    213     ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
    214 #endif
    215     if (ret != 0) {
    216         ctx->state |= CCM_STATE__ERROR;
    217         return ret;
    218     }
    219 
    220     return 0;
    221 }
    222 
    223 int mbedtls_ccm_starts(mbedtls_ccm_context *ctx,
    224                        int mode,
    225                        const unsigned char *iv,
    226                        size_t iv_len)
    227 {
    228     /* Also implies q is within bounds */
    229     if (iv_len < 7 || iv_len > 13) {
    230         return MBEDTLS_ERR_CCM_BAD_INPUT;
    231     }
    232 
    233     ctx->mode = mode;
    234     ctx->q = 16 - 1 - (unsigned char) iv_len;
    235 
    236     /*
    237      * Prepare counter block for encryption:
    238      * 0        .. 0        flags
    239      * 1        .. iv_len   nonce (aka iv)
    240      * iv_len+1 .. 15       counter (initially 1)
    241      *
    242      * With flags as (bits):
    243      * 7 .. 3   0
    244      * 2 .. 0   q - 1
    245      */
    246     memset(ctx->ctr, 0, 16);
    247     ctx->ctr[0] = ctx->q - 1;
    248     memcpy(ctx->ctr + 1, iv, iv_len);
    249     memset(ctx->ctr + 1 + iv_len, 0, ctx->q);
    250     ctx->ctr[15] = 1;
    251 
    252     /*
    253      * See ccm_calculate_first_block_if_ready() for block layout description
    254      */
    255     memcpy(ctx->y + 1, iv, iv_len);
    256 
    257     ctx->state |= CCM_STATE__STARTED;
    258     return ccm_calculate_first_block_if_ready(ctx);
    259 }
    260 
    261 int mbedtls_ccm_set_lengths(mbedtls_ccm_context *ctx,
    262                             size_t total_ad_len,
    263                             size_t plaintext_len,
    264                             size_t tag_len)
    265 {
    266     /*
    267      * Check length requirements: SP800-38C A.1
    268      * Additional requirement: a < 2^16 - 2^8 to simplify the code.
    269      * 'length' checked later (when writing it to the first block)
    270      *
    271      * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
    272      */
    273     if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0) {
    274         return MBEDTLS_ERR_CCM_BAD_INPUT;
    275     }
    276 
    277     if (total_ad_len >= 0xFF00) {
    278         return MBEDTLS_ERR_CCM_BAD_INPUT;
    279     }
    280 
    281     ctx->plaintext_len = plaintext_len;
    282     ctx->add_len = total_ad_len;
    283     ctx->tag_len = tag_len;
    284     ctx->processed = 0;
    285 
    286     ctx->state |= CCM_STATE__LENGTHS_SET;
    287     return ccm_calculate_first_block_if_ready(ctx);
    288 }
    289 
    290 int mbedtls_ccm_update_ad(mbedtls_ccm_context *ctx,
    291                           const unsigned char *add,
    292                           size_t add_len)
    293 {
    294     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    295     size_t use_len, offset;
    296 #if !defined(MBEDTLS_BLOCK_CIPHER_C)
    297     size_t olen;
    298 #endif
    299 
    300     if (ctx->state & CCM_STATE__ERROR) {
    301         return MBEDTLS_ERR_CCM_BAD_INPUT;
    302     }
    303 
    304     if (add_len > 0) {
    305         if (ctx->state & CCM_STATE__AUTH_DATA_FINISHED) {
    306             return MBEDTLS_ERR_CCM_BAD_INPUT;
    307         }
    308 
    309         if (!(ctx->state & CCM_STATE__AUTH_DATA_STARTED)) {
    310             if (add_len > ctx->add_len) {
    311                 return MBEDTLS_ERR_CCM_BAD_INPUT;
    312             }
    313 
    314             ctx->y[0] ^= (unsigned char) ((ctx->add_len >> 8) & 0xFF);
    315             ctx->y[1] ^= (unsigned char) ((ctx->add_len) & 0xFF);
    316 
    317             ctx->state |= CCM_STATE__AUTH_DATA_STARTED;
    318         } else if (ctx->processed + add_len > ctx->add_len) {
    319             return MBEDTLS_ERR_CCM_BAD_INPUT;
    320         }
    321 
    322         while (add_len > 0) {
    323             offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1]
    324                                                  * holding total auth data length */
    325             use_len = 16 - offset;
    326 
    327             if (use_len > add_len) {
    328                 use_len = add_len;
    329             }
    330 
    331             mbedtls_xor(ctx->y + offset, ctx->y + offset, add, use_len);
    332 
    333             ctx->processed += use_len;
    334             add_len -= use_len;
    335             add += use_len;
    336 
    337             if (use_len + offset == 16 || ctx->processed == ctx->add_len) {
    338 #if defined(MBEDTLS_BLOCK_CIPHER_C)
    339                 ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
    340 #else
    341                 ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
    342 #endif
    343                 if (ret != 0) {
    344                     ctx->state |= CCM_STATE__ERROR;
    345                     return ret;
    346                 }
    347             }
    348         }
    349 
    350         if (ctx->processed == ctx->add_len) {
    351             ctx->state |= CCM_STATE__AUTH_DATA_FINISHED;
    352             ctx->processed = 0; // prepare for mbedtls_ccm_update()
    353         }
    354     }
    355 
    356     return 0;
    357 }
    358 
    359 int mbedtls_ccm_update(mbedtls_ccm_context *ctx,
    360                        const unsigned char *input, size_t input_len,
    361                        unsigned char *output, size_t output_size,
    362                        size_t *output_len)
    363 {
    364     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    365     unsigned char i;
    366     size_t use_len, offset;
    367 #if !defined(MBEDTLS_BLOCK_CIPHER_C)
    368     size_t olen;
    369 #endif
    370 
    371     unsigned char local_output[16];
    372 
    373     if (ctx->state & CCM_STATE__ERROR) {
    374         return MBEDTLS_ERR_CCM_BAD_INPUT;
    375     }
    376 
    377     /* Check against plaintext length only if performing operation with
    378      * authentication
    379      */
    380     if (ctx->tag_len != 0 && ctx->processed + input_len > ctx->plaintext_len) {
    381         return MBEDTLS_ERR_CCM_BAD_INPUT;
    382     }
    383 
    384     if (output_size < input_len) {
    385         return MBEDTLS_ERR_CCM_BAD_INPUT;
    386     }
    387     *output_len = input_len;
    388 
    389     ret = 0;
    390 
    391     while (input_len > 0) {
    392         offset = ctx->processed % 16;
    393 
    394         use_len = 16 - offset;
    395 
    396         if (use_len > input_len) {
    397             use_len = input_len;
    398         }
    399 
    400         ctx->processed += use_len;
    401 
    402         if (ctx->mode == MBEDTLS_CCM_ENCRYPT || \
    403             ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT) {
    404             mbedtls_xor(ctx->y + offset, ctx->y + offset, input, use_len);
    405 
    406             if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
    407 #if defined(MBEDTLS_BLOCK_CIPHER_C)
    408                 ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
    409 #else
    410                 ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
    411 #endif
    412                 if (ret != 0) {
    413                     ctx->state |= CCM_STATE__ERROR;
    414                     goto exit;
    415                 }
    416             }
    417 
    418             ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, output);
    419             if (ret != 0) {
    420                 goto exit;
    421             }
    422         }
    423 
    424         if (ctx->mode == MBEDTLS_CCM_DECRYPT || \
    425             ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) {
    426             /* Since output may be in shared memory, we cannot be sure that
    427              * it will contain what we wrote to it. Therefore, we should avoid using
    428              * it as input to any operations.
    429              * Write decrypted data to local_output to avoid using output variable as
    430              * input in the XOR operation for Y.
    431              */
    432             ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, local_output);
    433             if (ret != 0) {
    434                 goto exit;
    435             }
    436 
    437             mbedtls_xor(ctx->y + offset, ctx->y + offset, local_output, use_len);
    438 
    439             memcpy(output, local_output, use_len);
    440 
    441             if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
    442 #if defined(MBEDTLS_BLOCK_CIPHER_C)
    443                 ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
    444 #else
    445                 ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
    446 #endif
    447                 if (ret != 0) {
    448                     ctx->state |= CCM_STATE__ERROR;
    449                     goto exit;
    450                 }
    451             }
    452         }
    453 
    454         if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
    455             for (i = 0; i < ctx->q; i++) {
    456                 if (++(ctx->ctr)[15-i] != 0) {
    457                     break;
    458                 }
    459             }
    460         }
    461 
    462         input_len -= use_len;
    463         input += use_len;
    464         output += use_len;
    465     }
    466 
    467 exit:
    468     mbedtls_platform_zeroize(local_output, 16);
    469 
    470     return ret;
    471 }
    472 
    473 int mbedtls_ccm_finish(mbedtls_ccm_context *ctx,
    474                        unsigned char *tag, size_t tag_len)
    475 {
    476     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    477     unsigned char i;
    478 
    479     if (ctx->state & CCM_STATE__ERROR) {
    480         return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    481     }
    482 
    483     if (ctx->add_len > 0 && !(ctx->state & CCM_STATE__AUTH_DATA_FINISHED)) {
    484         return MBEDTLS_ERR_CCM_BAD_INPUT;
    485     }
    486 
    487     if (ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len) {
    488         return MBEDTLS_ERR_CCM_BAD_INPUT;
    489     }
    490 
    491     /*
    492      * Authentication: reset counter and crypt/mask internal tag
    493      */
    494     for (i = 0; i < ctx->q; i++) {
    495         ctx->ctr[15-i] = 0;
    496     }
    497 
    498     ret = mbedtls_ccm_crypt(ctx, 0, 16, ctx->y, ctx->y);
    499     if (ret != 0) {
    500         return ret;
    501     }
    502     if (tag != NULL) {
    503         memcpy(tag, ctx->y, tag_len);
    504     }
    505     mbedtls_ccm_clear_state(ctx);
    506 
    507     return 0;
    508 }
    509 
    510 /*
    511  * Authenticated encryption or decryption
    512  */
    513 static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length,
    514                           const unsigned char *iv, size_t iv_len,
    515                           const unsigned char *add, size_t add_len,
    516                           const unsigned char *input, unsigned char *output,
    517                           unsigned char *tag, size_t tag_len)
    518 {
    519     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    520     size_t olen;
    521 
    522     if ((ret = mbedtls_ccm_starts(ctx, mode, iv, iv_len)) != 0) {
    523         return ret;
    524     }
    525 
    526     if ((ret = mbedtls_ccm_set_lengths(ctx, add_len, length, tag_len)) != 0) {
    527         return ret;
    528     }
    529 
    530     if ((ret = mbedtls_ccm_update_ad(ctx, add, add_len)) != 0) {
    531         return ret;
    532     }
    533 
    534     if ((ret = mbedtls_ccm_update(ctx, input, length,
    535                                   output, length, &olen)) != 0) {
    536         return ret;
    537     }
    538 
    539     if ((ret = mbedtls_ccm_finish(ctx, tag, tag_len)) != 0) {
    540         return ret;
    541     }
    542 
    543     return 0;
    544 }
    545 
    546 /*
    547  * Authenticated encryption
    548  */
    549 int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
    550                                      const unsigned char *iv, size_t iv_len,
    551                                      const unsigned char *add, size_t add_len,
    552                                      const unsigned char *input, unsigned char *output,
    553                                      unsigned char *tag, size_t tag_len)
    554 {
    555     return ccm_auth_crypt(ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len,
    556                           add, add_len, input, output, tag, tag_len);
    557 }
    558 
    559 int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
    560                                 const unsigned char *iv, size_t iv_len,
    561                                 const unsigned char *add, size_t add_len,
    562                                 const unsigned char *input, unsigned char *output,
    563                                 unsigned char *tag, size_t tag_len)
    564 {
    565     return ccm_auth_crypt(ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len,
    566                           add, add_len, input, output, tag, tag_len);
    567 }
    568 
    569 /*
    570  * Authenticated decryption
    571  */
    572 static int mbedtls_ccm_compare_tags(const unsigned char *tag1,
    573                                     const unsigned char *tag2,
    574                                     size_t tag_len)
    575 {
    576     /* Check tag in "constant-time" */
    577     int diff = mbedtls_ct_memcmp(tag1, tag2, tag_len);
    578 
    579     if (diff != 0) {
    580         return MBEDTLS_ERR_CCM_AUTH_FAILED;
    581     }
    582 
    583     return 0;
    584 }
    585 
    586 static int ccm_auth_decrypt(mbedtls_ccm_context *ctx, int mode, size_t length,
    587                             const unsigned char *iv, size_t iv_len,
    588                             const unsigned char *add, size_t add_len,
    589                             const unsigned char *input, unsigned char *output,
    590                             const unsigned char *tag, size_t tag_len)
    591 {
    592     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    593     unsigned char check_tag[16];
    594 
    595     if ((ret = ccm_auth_crypt(ctx, mode, length,
    596                               iv, iv_len, add, add_len,
    597                               input, output, check_tag, tag_len)) != 0) {
    598         return ret;
    599     }
    600 
    601     if ((ret = mbedtls_ccm_compare_tags(tag, check_tag, tag_len)) != 0) {
    602         mbedtls_platform_zeroize(output, length);
    603         return ret;
    604     }
    605 
    606     return 0;
    607 }
    608 
    609 int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
    610                                   const unsigned char *iv, size_t iv_len,
    611                                   const unsigned char *add, size_t add_len,
    612                                   const unsigned char *input, unsigned char *output,
    613                                   const unsigned char *tag, size_t tag_len)
    614 {
    615     return ccm_auth_decrypt(ctx, MBEDTLS_CCM_STAR_DECRYPT, length,
    616                             iv, iv_len, add, add_len,
    617                             input, output, tag, tag_len);
    618 }
    619 
    620 int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
    621                              const unsigned char *iv, size_t iv_len,
    622                              const unsigned char *add, size_t add_len,
    623                              const unsigned char *input, unsigned char *output,
    624                              const unsigned char *tag, size_t tag_len)
    625 {
    626     return ccm_auth_decrypt(ctx, MBEDTLS_CCM_DECRYPT, length,
    627                             iv, iv_len, add, add_len,
    628                             input, output, tag, tag_len);
    629 }
    630 #endif /* !MBEDTLS_CCM_ALT */
    631 
    632 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CCM_GCM_CAN_AES)
    633 /*
    634  * Examples 1 to 3 from SP800-38C Appendix C
    635  */
    636 
    637 #define NB_TESTS 3
    638 #define CCM_SELFTEST_PT_MAX_LEN 24
    639 #define CCM_SELFTEST_CT_MAX_LEN 32
    640 /*
    641  * The data is the same for all tests, only the used length changes
    642  */
    643 static const unsigned char key_test_data[] = {
    644     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
    645     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
    646 };
    647 
    648 static const unsigned char iv_test_data[] = {
    649     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    650     0x18, 0x19, 0x1a, 0x1b
    651 };
    652 
    653 static const unsigned char ad_test_data[] = {
    654     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    655     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    656     0x10, 0x11, 0x12, 0x13
    657 };
    658 
    659 static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
    660     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    661     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
    662     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    663 };
    664 
    665 static const size_t iv_len_test_data[NB_TESTS] = { 7, 8,  12 };
    666 static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
    667 static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
    668 static const size_t tag_len_test_data[NB_TESTS] = { 4, 6,  8  };
    669 
    670 static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
    671     {   0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
    672     {   0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
    673         0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
    674         0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
    675     {   0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
    676         0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
    677         0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
    678         0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
    679 };
    680 
    681 int mbedtls_ccm_self_test(int verbose)
    682 {
    683     mbedtls_ccm_context ctx;
    684     /*
    685      * Some hardware accelerators require the input and output buffers
    686      * would be in RAM, because the flash is not accessible.
    687      * Use buffers on the stack to hold the test vectors data.
    688      */
    689     unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
    690     unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
    691     size_t i;
    692     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    693 
    694     mbedtls_ccm_init(&ctx);
    695 
    696     if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
    697                            8 * sizeof(key_test_data)) != 0) {
    698         if (verbose != 0) {
    699             mbedtls_printf("  CCM: setup failed");
    700         }
    701 
    702         return 1;
    703     }
    704 
    705     for (i = 0; i < NB_TESTS; i++) {
    706         if (verbose != 0) {
    707             mbedtls_printf("  CCM-AES #%u: ", (unsigned int) i + 1);
    708         }
    709 
    710         memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
    711         memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN);
    712         memcpy(plaintext, msg_test_data, msg_len_test_data[i]);
    713 
    714         ret = mbedtls_ccm_encrypt_and_tag(&ctx, msg_len_test_data[i],
    715                                           iv_test_data, iv_len_test_data[i],
    716                                           ad_test_data, add_len_test_data[i],
    717                                           plaintext, ciphertext,
    718                                           ciphertext + msg_len_test_data[i],
    719                                           tag_len_test_data[i]);
    720 
    721         if (ret != 0 ||
    722             memcmp(ciphertext, res_test_data[i],
    723                    msg_len_test_data[i] + tag_len_test_data[i]) != 0) {
    724             if (verbose != 0) {
    725                 mbedtls_printf("failed\n");
    726             }
    727 
    728             return 1;
    729         }
    730         memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
    731 
    732         ret = mbedtls_ccm_auth_decrypt(&ctx, msg_len_test_data[i],
    733                                        iv_test_data, iv_len_test_data[i],
    734                                        ad_test_data, add_len_test_data[i],
    735                                        ciphertext, plaintext,
    736                                        ciphertext + msg_len_test_data[i],
    737                                        tag_len_test_data[i]);
    738 
    739         if (ret != 0 ||
    740             memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) {
    741             if (verbose != 0) {
    742                 mbedtls_printf("failed\n");
    743             }
    744 
    745             return 1;
    746         }
    747 
    748         if (verbose != 0) {
    749             mbedtls_printf("passed\n");
    750         }
    751     }
    752 
    753     mbedtls_ccm_free(&ctx);
    754 
    755     if (verbose != 0) {
    756         mbedtls_printf("\n");
    757     }
    758 
    759     return 0;
    760 }
    761 
    762 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
    763 
    764 #endif /* MBEDTLS_CCM_C */