Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/mbedtls/library/chachapoly.c
9898 views
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 */
479
480