Coverage Report

Created: 2024-01-20 12:33

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