Coverage Report

Created: 2024-11-21 07:03

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