quickjs-tart

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

chachapoly.c (14504B)


      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 static int chachapoly_pad_aad(mbedtls_chachapoly_context *ctx)
     35 {
     36     uint32_t partial_block_len = (uint32_t) (ctx->aad_len % 16U);
     37     unsigned char zeroes[15];
     38 
     39     if (partial_block_len == 0U) {
     40         return 0;
     41     }
     42 
     43     memset(zeroes, 0, sizeof(zeroes));
     44 
     45     return mbedtls_poly1305_update(&ctx->poly1305_ctx,
     46                                    zeroes,
     47                                    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 static int chachapoly_pad_ciphertext(mbedtls_chachapoly_context *ctx)
     56 {
     57     uint32_t partial_block_len = (uint32_t) (ctx->ciphertext_len % 16U);
     58     unsigned char zeroes[15];
     59 
     60     if (partial_block_len == 0U) {
     61         return 0;
     62     }
     63 
     64     memset(zeroes, 0, sizeof(zeroes));
     65     return mbedtls_poly1305_update(&ctx->poly1305_ctx,
     66                                    zeroes,
     67                                    16U - partial_block_len);
     68 }
     69 
     70 void mbedtls_chachapoly_init(mbedtls_chachapoly_context *ctx)
     71 {
     72     mbedtls_chacha20_init(&ctx->chacha20_ctx);
     73     mbedtls_poly1305_init(&ctx->poly1305_ctx);
     74     ctx->aad_len        = 0U;
     75     ctx->ciphertext_len = 0U;
     76     ctx->state          = CHACHAPOLY_STATE_INIT;
     77     ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
     78 }
     79 
     80 void mbedtls_chachapoly_free(mbedtls_chachapoly_context *ctx)
     81 {
     82     if (ctx == NULL) {
     83         return;
     84     }
     85 
     86     mbedtls_chacha20_free(&ctx->chacha20_ctx);
     87     mbedtls_poly1305_free(&ctx->poly1305_ctx);
     88     ctx->aad_len        = 0U;
     89     ctx->ciphertext_len = 0U;
     90     ctx->state          = CHACHAPOLY_STATE_INIT;
     91     ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
     92 }
     93 
     94 int mbedtls_chachapoly_setkey(mbedtls_chachapoly_context *ctx,
     95                               const unsigned char key[32])
     96 {
     97     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     98 
     99     ret = mbedtls_chacha20_setkey(&ctx->chacha20_ctx, key);
    100 
    101     return ret;
    102 }
    103 
    104 int mbedtls_chachapoly_starts(mbedtls_chachapoly_context *ctx,
    105                               const unsigned char nonce[12],
    106                               mbedtls_chachapoly_mode_t mode)
    107 {
    108     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     ret = mbedtls_chacha20_starts(&ctx->chacha20_ctx, nonce, 0U);
    113     if (ret != 0) {
    114         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     memset(poly1305_key, 0, sizeof(poly1305_key));
    123     ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, sizeof(poly1305_key),
    124                                   poly1305_key, poly1305_key);
    125     if (ret != 0) {
    126         goto cleanup;
    127     }
    128 
    129     ret = mbedtls_poly1305_starts(&ctx->poly1305_ctx, poly1305_key);
    130 
    131     if (ret == 0) {
    132         ctx->aad_len        = 0U;
    133         ctx->ciphertext_len = 0U;
    134         ctx->state          = CHACHAPOLY_STATE_AAD;
    135         ctx->mode           = mode;
    136     }
    137 
    138 cleanup:
    139     mbedtls_platform_zeroize(poly1305_key, 64U);
    140     return ret;
    141 }
    142 
    143 int mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context *ctx,
    144                                   const unsigned char *aad,
    145                                   size_t aad_len)
    146 {
    147     if (ctx->state != CHACHAPOLY_STATE_AAD) {
    148         return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
    149     }
    150 
    151     ctx->aad_len += aad_len;
    152 
    153     return mbedtls_poly1305_update(&ctx->poly1305_ctx, aad, aad_len);
    154 }
    155 
    156 int mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx,
    157                               size_t len,
    158                               const unsigned char *input,
    159                               unsigned char *output)
    160 {
    161     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    162 
    163     if ((ctx->state != CHACHAPOLY_STATE_AAD) &&
    164         (ctx->state != CHACHAPOLY_STATE_CIPHERTEXT)) {
    165         return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
    166     }
    167 
    168     if (ctx->state == CHACHAPOLY_STATE_AAD) {
    169         ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
    170 
    171         ret = chachapoly_pad_aad(ctx);
    172         if (ret != 0) {
    173             return ret;
    174         }
    175     }
    176 
    177     ctx->ciphertext_len += len;
    178 
    179     if (ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT) {
    180         ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);
    181         if (ret != 0) {
    182             return ret;
    183         }
    184 
    185         ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, output, len);
    186         if (ret != 0) {
    187             return ret;
    188         }
    189     } else { /* DECRYPT */
    190         ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, input, len);
    191         if (ret != 0) {
    192             return ret;
    193         }
    194 
    195         ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);
    196         if (ret != 0) {
    197             return ret;
    198         }
    199     }
    200 
    201     return 0;
    202 }
    203 
    204 int mbedtls_chachapoly_finish(mbedtls_chachapoly_context *ctx,
    205                               unsigned char mac[16])
    206 {
    207     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    208     unsigned char len_block[16];
    209 
    210     if (ctx->state == CHACHAPOLY_STATE_INIT) {
    211         return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
    212     }
    213 
    214     if (ctx->state == CHACHAPOLY_STATE_AAD) {
    215         ret = chachapoly_pad_aad(ctx);
    216         if (ret != 0) {
    217             return ret;
    218         }
    219     } else if (ctx->state == CHACHAPOLY_STATE_CIPHERTEXT) {
    220         ret = chachapoly_pad_ciphertext(ctx);
    221         if (ret != 0) {
    222             return ret;
    223         }
    224     }
    225 
    226     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     MBEDTLS_PUT_UINT64_LE(ctx->aad_len, len_block, 0);
    232     MBEDTLS_PUT_UINT64_LE(ctx->ciphertext_len, len_block, 8);
    233 
    234     ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, len_block, 16U);
    235     if (ret != 0) {
    236         return ret;
    237     }
    238 
    239     ret = mbedtls_poly1305_finish(&ctx->poly1305_ctx, mac);
    240 
    241     return ret;
    242 }
    243 
    244 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     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    255 
    256     ret = mbedtls_chachapoly_starts(ctx, nonce, mode);
    257     if (ret != 0) {
    258         goto cleanup;
    259     }
    260 
    261     ret = mbedtls_chachapoly_update_aad(ctx, aad, aad_len);
    262     if (ret != 0) {
    263         goto cleanup;
    264     }
    265 
    266     ret = mbedtls_chachapoly_update(ctx, length, input, output);
    267     if (ret != 0) {
    268         goto cleanup;
    269     }
    270 
    271     ret = mbedtls_chachapoly_finish(ctx, tag);
    272 
    273 cleanup:
    274     return ret;
    275 }
    276 
    277 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     return chachapoly_crypt_and_tag(ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
    287                                     length, nonce, aad, aad_len,
    288                                     input, output, tag);
    289 }
    290 
    291 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     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    301     unsigned char check_tag[16];
    302     int diff;
    303 
    304     if ((ret = chachapoly_crypt_and_tag(ctx,
    305                                         MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
    306                                         aad, aad_len, input, output, check_tag)) != 0) {
    307         return ret;
    308     }
    309 
    310     /* Check tag in "constant-time" */
    311     diff = mbedtls_ct_memcmp(tag, check_tag, sizeof(check_tag));
    312 
    313     if (diff != 0) {
    314         mbedtls_platform_zeroize(output, length);
    315         return MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED;
    316     }
    317 
    318     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 int mbedtls_chachapoly_self_test(int verbose)
    428 {
    429     mbedtls_chachapoly_context ctx;
    430     unsigned i;
    431     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    432     unsigned char output[200];
    433     unsigned char mac[16];
    434 
    435     for (i = 0U; i < 1U; i++) {
    436         if (verbose != 0) {
    437             mbedtls_printf("  ChaCha20-Poly1305 test %u ", i);
    438         }
    439 
    440         mbedtls_chachapoly_init(&ctx);
    441 
    442         ret = mbedtls_chachapoly_setkey(&ctx, test_key[i]);
    443         ASSERT(0 == ret, ("setkey() error code: %i\n", ret));
    444 
    445         ret = mbedtls_chachapoly_encrypt_and_tag(&ctx,
    446                                                  test_input_len[i],
    447                                                  test_nonce[i],
    448                                                  test_aad[i],
    449                                                  test_aad_len[i],
    450                                                  test_input[i],
    451                                                  output,
    452                                                  mac);
    453 
    454         ASSERT(0 == ret, ("crypt_and_tag() error code: %i\n", ret));
    455 
    456         ASSERT(0 == memcmp(output, test_output[i], test_input_len[i]),
    457                ("failure (wrong output)\n"));
    458 
    459         ASSERT(0 == memcmp(mac, test_mac[i], 16U),
    460                ("failure (wrong MAC)\n"));
    461 
    462         mbedtls_chachapoly_free(&ctx);
    463 
    464         if (verbose != 0) {
    465             mbedtls_printf("passed\n");
    466         }
    467     }
    468 
    469     if (verbose != 0) {
    470         mbedtls_printf("\n");
    471     }
    472 
    473     return 0;
    474 }
    475 
    476 #endif /* MBEDTLS_SELF_TEST */
    477 
    478 #endif /* MBEDTLS_CHACHAPOLY_C */