LCOV - code coverage report
Current view: top level - os_stub/mbedtlslib/mbedtls/library - chachapoly.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 151 0
Test Date: 2025-06-29 08:09:00 Functions: 0.0 % 13 0

            Line data    Source code
       1              : /**
       2              :  * \file chachapoly.c
       3              :  *
       4              :  * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
       5              :  *
       6              :  *  Copyright The Mbed TLS Contributors
       7              :  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
       8              :  */
       9              : #include "common.h"
      10              : 
      11              : #if defined(MBEDTLS_CHACHAPOLY_C)
      12              : 
      13              : #include "mbedtls/chachapoly.h"
      14              : #include "mbedtls/platform_util.h"
      15              : #include "mbedtls/error.h"
      16              : #include "mbedtls/constant_time.h"
      17              : 
      18              : #include <string.h>
      19              : 
      20              : #include "mbedtls/platform.h"
      21              : 
      22              : #if !defined(MBEDTLS_CHACHAPOLY_ALT)
      23              : 
      24              : #define CHACHAPOLY_STATE_INIT       (0)
      25              : #define CHACHAPOLY_STATE_AAD        (1)
      26              : #define CHACHAPOLY_STATE_CIPHERTEXT (2)   /* Encrypting or decrypting */
      27              : #define CHACHAPOLY_STATE_FINISHED   (3)
      28              : 
      29              : /**
      30              :  * \brief           Adds nul bytes to pad the AAD for Poly1305.
      31              :  *
      32              :  * \param ctx       The ChaCha20-Poly1305 context.
      33              :  */
      34            0 : static int chachapoly_pad_aad(mbedtls_chachapoly_context *ctx)
      35              : {
      36            0 :     uint32_t partial_block_len = (uint32_t) (ctx->aad_len % 16U);
      37              :     unsigned char zeroes[15];
      38              : 
      39            0 :     if (partial_block_len == 0U) {
      40            0 :         return 0;
      41              :     }
      42              : 
      43            0 :     memset(zeroes, 0, sizeof(zeroes));
      44              : 
      45            0 :     return mbedtls_poly1305_update(&ctx->poly1305_ctx,
      46              :                                    zeroes,
      47            0 :                                    16U - partial_block_len);
      48              : }
      49              : 
      50              : /**
      51              :  * \brief           Adds nul bytes to pad the ciphertext for Poly1305.
      52              :  *
      53              :  * \param ctx       The ChaCha20-Poly1305 context.
      54              :  */
      55            0 : static int chachapoly_pad_ciphertext(mbedtls_chachapoly_context *ctx)
      56              : {
      57            0 :     uint32_t partial_block_len = (uint32_t) (ctx->ciphertext_len % 16U);
      58              :     unsigned char zeroes[15];
      59              : 
      60            0 :     if (partial_block_len == 0U) {
      61            0 :         return 0;
      62              :     }
      63              : 
      64            0 :     memset(zeroes, 0, sizeof(zeroes));
      65            0 :     return mbedtls_poly1305_update(&ctx->poly1305_ctx,
      66              :                                    zeroes,
      67            0 :                                    16U - partial_block_len);
      68              : }
      69              : 
      70            0 : void mbedtls_chachapoly_init(mbedtls_chachapoly_context *ctx)
      71              : {
      72            0 :     mbedtls_chacha20_init(&ctx->chacha20_ctx);
      73            0 :     mbedtls_poly1305_init(&ctx->poly1305_ctx);
      74            0 :     ctx->aad_len        = 0U;
      75            0 :     ctx->ciphertext_len = 0U;
      76            0 :     ctx->state          = CHACHAPOLY_STATE_INIT;
      77            0 :     ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
      78            0 : }
      79              : 
      80            0 : void mbedtls_chachapoly_free(mbedtls_chachapoly_context *ctx)
      81              : {
      82            0 :     if (ctx == NULL) {
      83            0 :         return;
      84              :     }
      85              : 
      86            0 :     mbedtls_chacha20_free(&ctx->chacha20_ctx);
      87            0 :     mbedtls_poly1305_free(&ctx->poly1305_ctx);
      88            0 :     ctx->aad_len        = 0U;
      89            0 :     ctx->ciphertext_len = 0U;
      90            0 :     ctx->state          = CHACHAPOLY_STATE_INIT;
      91            0 :     ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
      92              : }
      93              : 
      94            0 : int mbedtls_chachapoly_setkey(mbedtls_chachapoly_context *ctx,
      95              :                               const unsigned char key[32])
      96              : {
      97            0 :     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
      98              : 
      99            0 :     ret = mbedtls_chacha20_setkey(&ctx->chacha20_ctx, key);
     100              : 
     101            0 :     return ret;
     102              : }
     103              : 
     104            0 : int mbedtls_chachapoly_starts(mbedtls_chachapoly_context *ctx,
     105              :                               const unsigned char nonce[12],
     106              :                               mbedtls_chachapoly_mode_t mode)
     107              : {
     108            0 :     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     109              :     unsigned char poly1305_key[64];
     110              : 
     111              :     /* Set counter = 0, will be update to 1 when generating Poly1305 key */
     112            0 :     ret = mbedtls_chacha20_starts(&ctx->chacha20_ctx, nonce, 0U);
     113            0 :     if (ret != 0) {
     114            0 :         goto cleanup;
     115              :     }
     116              : 
     117              :     /* Generate the Poly1305 key by getting the ChaCha20 keystream output with
     118              :      * counter = 0.  This is the same as encrypting a buffer of zeroes.
     119              :      * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
     120              :      * The other 256 bits are discarded.
     121              :      */
     122            0 :     memset(poly1305_key, 0, sizeof(poly1305_key));
     123            0 :     ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, sizeof(poly1305_key),
     124              :                                   poly1305_key, poly1305_key);
     125            0 :     if (ret != 0) {
     126            0 :         goto cleanup;
     127              :     }
     128              : 
     129            0 :     ret = mbedtls_poly1305_starts(&ctx->poly1305_ctx, poly1305_key);
     130              : 
     131            0 :     if (ret == 0) {
     132            0 :         ctx->aad_len        = 0U;
     133            0 :         ctx->ciphertext_len = 0U;
     134            0 :         ctx->state          = CHACHAPOLY_STATE_AAD;
     135            0 :         ctx->mode           = mode;
     136              :     }
     137              : 
     138            0 : cleanup:
     139            0 :     mbedtls_platform_zeroize(poly1305_key, 64U);
     140            0 :     return ret;
     141              : }
     142              : 
     143            0 : int mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context *ctx,
     144              :                                   const unsigned char *aad,
     145              :                                   size_t aad_len)
     146              : {
     147            0 :     if (ctx->state != CHACHAPOLY_STATE_AAD) {
     148            0 :         return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
     149              :     }
     150              : 
     151            0 :     ctx->aad_len += aad_len;
     152              : 
     153            0 :     return mbedtls_poly1305_update(&ctx->poly1305_ctx, aad, aad_len);
     154              : }
     155              : 
     156            0 : int mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx,
     157              :                               size_t len,
     158              :                               const unsigned char *input,
     159              :                               unsigned char *output)
     160              : {
     161            0 :     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     162              : 
     163            0 :     if ((ctx->state != CHACHAPOLY_STATE_AAD) &&
     164            0 :         (ctx->state != CHACHAPOLY_STATE_CIPHERTEXT)) {
     165            0 :         return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
     166              :     }
     167              : 
     168            0 :     if (ctx->state == CHACHAPOLY_STATE_AAD) {
     169            0 :         ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
     170              : 
     171            0 :         ret = chachapoly_pad_aad(ctx);
     172            0 :         if (ret != 0) {
     173            0 :             return ret;
     174              :         }
     175              :     }
     176              : 
     177            0 :     ctx->ciphertext_len += len;
     178              : 
     179            0 :     if (ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT) {
     180            0 :         ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);
     181            0 :         if (ret != 0) {
     182            0 :             return ret;
     183              :         }
     184              : 
     185            0 :         ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, output, len);
     186            0 :         if (ret != 0) {
     187            0 :             return ret;
     188              :         }
     189              :     } else { /* DECRYPT */
     190            0 :         ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, input, len);
     191            0 :         if (ret != 0) {
     192            0 :             return ret;
     193              :         }
     194              : 
     195            0 :         ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);
     196            0 :         if (ret != 0) {
     197            0 :             return ret;
     198              :         }
     199              :     }
     200              : 
     201            0 :     return 0;
     202              : }
     203              : 
     204            0 : int mbedtls_chachapoly_finish(mbedtls_chachapoly_context *ctx,
     205              :                               unsigned char mac[16])
     206              : {
     207            0 :     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     208              :     unsigned char len_block[16];
     209              : 
     210            0 :     if (ctx->state == CHACHAPOLY_STATE_INIT) {
     211            0 :         return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
     212              :     }
     213              : 
     214            0 :     if (ctx->state == CHACHAPOLY_STATE_AAD) {
     215            0 :         ret = chachapoly_pad_aad(ctx);
     216            0 :         if (ret != 0) {
     217            0 :             return ret;
     218              :         }
     219            0 :     } else if (ctx->state == CHACHAPOLY_STATE_CIPHERTEXT) {
     220            0 :         ret = chachapoly_pad_ciphertext(ctx);
     221            0 :         if (ret != 0) {
     222            0 :             return ret;
     223              :         }
     224              :     }
     225              : 
     226            0 :     ctx->state = CHACHAPOLY_STATE_FINISHED;
     227              : 
     228              :     /* The lengths of the AAD and ciphertext are processed by
     229              :      * Poly1305 as the final 128-bit block, encoded as little-endian integers.
     230              :      */
     231            0 :     MBEDTLS_PUT_UINT64_LE(ctx->aad_len, len_block, 0);
     232            0 :     MBEDTLS_PUT_UINT64_LE(ctx->ciphertext_len, len_block, 8);
     233              : 
     234            0 :     ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, len_block, 16U);
     235            0 :     if (ret != 0) {
     236            0 :         return ret;
     237              :     }
     238              : 
     239            0 :     ret = mbedtls_poly1305_finish(&ctx->poly1305_ctx, mac);
     240              : 
     241            0 :     return ret;
     242              : }
     243              : 
     244            0 : static int chachapoly_crypt_and_tag(mbedtls_chachapoly_context *ctx,
     245              :                                     mbedtls_chachapoly_mode_t mode,
     246              :                                     size_t length,
     247              :                                     const unsigned char nonce[12],
     248              :                                     const unsigned char *aad,
     249              :                                     size_t aad_len,
     250              :                                     const unsigned char *input,
     251              :                                     unsigned char *output,
     252              :                                     unsigned char tag[16])
     253              : {
     254            0 :     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     255              : 
     256            0 :     ret = mbedtls_chachapoly_starts(ctx, nonce, mode);
     257            0 :     if (ret != 0) {
     258            0 :         goto cleanup;
     259              :     }
     260              : 
     261            0 :     ret = mbedtls_chachapoly_update_aad(ctx, aad, aad_len);
     262            0 :     if (ret != 0) {
     263            0 :         goto cleanup;
     264              :     }
     265              : 
     266            0 :     ret = mbedtls_chachapoly_update(ctx, length, input, output);
     267            0 :     if (ret != 0) {
     268            0 :         goto cleanup;
     269              :     }
     270              : 
     271            0 :     ret = mbedtls_chachapoly_finish(ctx, tag);
     272              : 
     273            0 : cleanup:
     274            0 :     return ret;
     275              : }
     276              : 
     277            0 : int mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context *ctx,
     278              :                                        size_t length,
     279              :                                        const unsigned char nonce[12],
     280              :                                        const unsigned char *aad,
     281              :                                        size_t aad_len,
     282              :                                        const unsigned char *input,
     283              :                                        unsigned char *output,
     284              :                                        unsigned char tag[16])
     285              : {
     286            0 :     return chachapoly_crypt_and_tag(ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
     287              :                                     length, nonce, aad, aad_len,
     288              :                                     input, output, tag);
     289              : }
     290              : 
     291            0 : int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context *ctx,
     292              :                                     size_t length,
     293              :                                     const unsigned char nonce[12],
     294              :                                     const unsigned char *aad,
     295              :                                     size_t aad_len,
     296              :                                     const unsigned char tag[16],
     297              :                                     const unsigned char *input,
     298              :                                     unsigned char *output)
     299              : {
     300            0 :     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     301              :     unsigned char check_tag[16];
     302              :     int diff;
     303              : 
     304            0 :     if ((ret = chachapoly_crypt_and_tag(ctx,
     305              :                                         MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
     306              :                                         aad, aad_len, input, output, check_tag)) != 0) {
     307            0 :         return ret;
     308              :     }
     309              : 
     310              :     /* Check tag in "constant-time" */
     311            0 :     diff = mbedtls_ct_memcmp(tag, check_tag, sizeof(check_tag));
     312              : 
     313            0 :     if (diff != 0) {
     314            0 :         mbedtls_platform_zeroize(output, length);
     315            0 :         return MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED;
     316              :     }
     317              : 
     318            0 :     return 0;
     319              : }
     320              : 
     321              : #endif /* MBEDTLS_CHACHAPOLY_ALT */
     322              : 
     323              : #if defined(MBEDTLS_SELF_TEST)
     324              : 
     325              : static const unsigned char test_key[1][32] =
     326              : {
     327              :     {
     328              :         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
     329              :         0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
     330              :         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
     331              :         0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
     332              :     }
     333              : };
     334              : 
     335              : static const unsigned char test_nonce[1][12] =
     336              : {
     337              :     {
     338              :         0x07, 0x00, 0x00, 0x00,                         /* 32-bit common part */
     339              :         0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47  /* 64-bit IV */
     340              :     }
     341              : };
     342              : 
     343              : static const unsigned char test_aad[1][12] =
     344              : {
     345              :     {
     346              :         0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
     347              :         0xc4, 0xc5, 0xc6, 0xc7
     348              :     }
     349              : };
     350              : 
     351              : static const size_t test_aad_len[1] =
     352              : {
     353              :     12U
     354              : };
     355              : 
     356              : static const unsigned char test_input[1][114] =
     357              : {
     358              :     {
     359              :         0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
     360              :         0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
     361              :         0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
     362              :         0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
     363              :         0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
     364              :         0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
     365              :         0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
     366              :         0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
     367              :         0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
     368              :         0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
     369              :         0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
     370              :         0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
     371              :         0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
     372              :         0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
     373              :         0x74, 0x2e
     374              :     }
     375              : };
     376              : 
     377              : static const unsigned char test_output[1][114] =
     378              : {
     379              :     {
     380              :         0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
     381              :         0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
     382              :         0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
     383              :         0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
     384              :         0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
     385              :         0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
     386              :         0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
     387              :         0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
     388              :         0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
     389              :         0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
     390              :         0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
     391              :         0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
     392              :         0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
     393              :         0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
     394              :         0x61, 0x16
     395              :     }
     396              : };
     397              : 
     398              : static const size_t test_input_len[1] =
     399              : {
     400              :     114U
     401              : };
     402              : 
     403              : static const unsigned char test_mac[1][16] =
     404              : {
     405              :     {
     406              :         0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
     407              :         0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
     408              :     }
     409              : };
     410              : 
     411              : /* Make sure no other definition is already present. */
     412              : #undef ASSERT
     413              : 
     414              : #define ASSERT(cond, args)            \
     415              :     do                                  \
     416              :     {                                   \
     417              :         if (!(cond))                \
     418              :         {                               \
     419              :             if (verbose != 0)          \
     420              :             mbedtls_printf args;    \
     421              :                                         \
     422              :             return -1;               \
     423              :         }                               \
     424              :     }                                   \
     425              :     while (0)
     426              : 
     427            0 : int mbedtls_chachapoly_self_test(int verbose)
     428              : {
     429              :     mbedtls_chachapoly_context ctx;
     430              :     unsigned i;
     431            0 :     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     432              :     unsigned char output[200];
     433              :     unsigned char mac[16];
     434              : 
     435            0 :     for (i = 0U; i < 1U; i++) {
     436            0 :         if (verbose != 0) {
     437            0 :             mbedtls_printf("  ChaCha20-Poly1305 test %u ", i);
     438              :         }
     439              : 
     440            0 :         mbedtls_chachapoly_init(&ctx);
     441              : 
     442            0 :         ret = mbedtls_chachapoly_setkey(&ctx, test_key[i]);
     443            0 :         ASSERT(0 == ret, ("setkey() error code: %i\n", ret));
     444              : 
     445            0 :         ret = mbedtls_chachapoly_encrypt_and_tag(&ctx,
     446            0 :                                                  test_input_len[i],
     447            0 :                                                  test_nonce[i],
     448            0 :                                                  test_aad[i],
     449            0 :                                                  test_aad_len[i],
     450            0 :                                                  test_input[i],
     451              :                                                  output,
     452              :                                                  mac);
     453              : 
     454            0 :         ASSERT(0 == ret, ("crypt_and_tag() error code: %i\n", ret));
     455              : 
     456            0 :         ASSERT(0 == memcmp(output, test_output[i], test_input_len[i]),
     457              :                ("failure (wrong output)\n"));
     458              : 
     459            0 :         ASSERT(0 == memcmp(mac, test_mac[i], 16U),
     460              :                ("failure (wrong MAC)\n"));
     461              : 
     462            0 :         mbedtls_chachapoly_free(&ctx);
     463              : 
     464            0 :         if (verbose != 0) {
     465            0 :             mbedtls_printf("passed\n");
     466              :         }
     467              :     }
     468              : 
     469            0 :     if (verbose != 0) {
     470            0 :         mbedtls_printf("\n");
     471              :     }
     472              : 
     473            0 :     return 0;
     474              : }
     475              : 
     476              : #endif /* MBEDTLS_SELF_TEST */
     477              : 
     478              : #endif /* MBEDTLS_CHACHAPOLY_C */
        

Generated by: LCOV version 2.0-1