Coverage Report

Created: 2025-07-01 06:54

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