1 /* $OpenBSD: e_chacha20poly1305.c,v 1.36 2024/05/22 14:02:08 tb Exp $ */
2
3 /*
4 * Copyright (c) 2022 Joel Sing <jsing@openbsd.org>
5 * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org>
6 * Copyright (c) 2014, Google Inc.
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
15 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
17 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 #include <limits.h>
22 #include <stdint.h>
23 #include <string.h>
24
25 #include <openssl/opensslconf.h>
26
27 #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
28
29 #include <openssl/err.h>
30 #include <openssl/evp.h>
31 #include <openssl/chacha.h>
32 #include <openssl/poly1305.h>
33
34 #include "bytestring.h"
35 #include "evp_local.h"
36
37 #define POLY1305_TAG_LEN 16
38
39 #define CHACHA20_CONSTANT_LEN 4
40 #define CHACHA20_IV_LEN 8
41 #define CHACHA20_NONCE_LEN (CHACHA20_CONSTANT_LEN + CHACHA20_IV_LEN)
42 #define XCHACHA20_NONCE_LEN 24
43
44 struct aead_chacha20_poly1305_ctx {
45 unsigned char key[32];
46 unsigned char tag_len;
47 };
48
49 static int
aead_chacha20_poly1305_init(EVP_AEAD_CTX * ctx,const unsigned char * key,size_t key_len,size_t tag_len)50 aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const unsigned char *key,
51 size_t key_len, size_t tag_len)
52 {
53 struct aead_chacha20_poly1305_ctx *c20_ctx;
54
55 if (tag_len == 0)
56 tag_len = POLY1305_TAG_LEN;
57
58 if (tag_len > POLY1305_TAG_LEN) {
59 EVPerror(EVP_R_TOO_LARGE);
60 return 0;
61 }
62
63 /* Internal error - EVP_AEAD_CTX_init should catch this. */
64 if (key_len != sizeof(c20_ctx->key))
65 return 0;
66
67 c20_ctx = malloc(sizeof(struct aead_chacha20_poly1305_ctx));
68 if (c20_ctx == NULL)
69 return 0;
70
71 memcpy(&c20_ctx->key[0], key, key_len);
72 c20_ctx->tag_len = tag_len;
73 ctx->aead_state = c20_ctx;
74
75 return 1;
76 }
77
78 static void
aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX * ctx)79 aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx)
80 {
81 struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
82
83 freezero(c20_ctx, sizeof(*c20_ctx));
84 }
85
86 static void
poly1305_update_with_length(poly1305_state * poly1305,const unsigned char * data,size_t data_len)87 poly1305_update_with_length(poly1305_state *poly1305,
88 const unsigned char *data, size_t data_len)
89 {
90 size_t j = data_len;
91 unsigned char length_bytes[8];
92 unsigned i;
93
94 for (i = 0; i < sizeof(length_bytes); i++) {
95 length_bytes[i] = j;
96 j >>= 8;
97 }
98
99 if (data != NULL)
100 CRYPTO_poly1305_update(poly1305, data, data_len);
101 CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes));
102 }
103
104 static void
poly1305_pad16(poly1305_state * poly1305,size_t data_len)105 poly1305_pad16(poly1305_state *poly1305, size_t data_len)
106 {
107 static const unsigned char zero_pad16[16];
108 size_t pad_len;
109
110 /* pad16() is defined in RFC 8439 2.8.1. */
111 if ((pad_len = data_len % 16) == 0)
112 return;
113
114 CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len);
115 }
116
117 static void
poly1305_update_with_pad16(poly1305_state * poly1305,const unsigned char * data,size_t data_len)118 poly1305_update_with_pad16(poly1305_state *poly1305,
119 const unsigned char *data, size_t data_len)
120 {
121 CRYPTO_poly1305_update(poly1305, data, data_len);
122 poly1305_pad16(poly1305, data_len);
123 }
124
125 static int
aead_chacha20_poly1305_seal(const EVP_AEAD_CTX * ctx,unsigned char * out,size_t * out_len,size_t max_out_len,const unsigned char * nonce,size_t nonce_len,const unsigned char * in,size_t in_len,const unsigned char * ad,size_t ad_len)126 aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
127 size_t *out_len, size_t max_out_len, const unsigned char *nonce,
128 size_t nonce_len, const unsigned char *in, size_t in_len,
129 const unsigned char *ad, size_t ad_len)
130 {
131 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
132 unsigned char poly1305_key[32];
133 poly1305_state poly1305;
134 const unsigned char *iv;
135 uint64_t ctr;
136
137 if (max_out_len < in_len + c20_ctx->tag_len) {
138 EVPerror(EVP_R_BUFFER_TOO_SMALL);
139 return 0;
140 }
141
142 if (nonce_len != ctx->aead->nonce_len) {
143 EVPerror(EVP_R_IV_TOO_LARGE);
144 return 0;
145 }
146
147 ctr = (uint64_t)((uint32_t)(nonce[0]) | (uint32_t)(nonce[1]) << 8 |
148 (uint32_t)(nonce[2]) << 16 | (uint32_t)(nonce[3]) << 24) << 32;
149 iv = nonce + CHACHA20_CONSTANT_LEN;
150
151 memset(poly1305_key, 0, sizeof(poly1305_key));
152 CRYPTO_chacha_20(poly1305_key, poly1305_key,
153 sizeof(poly1305_key), c20_ctx->key, iv, ctr);
154
155 CRYPTO_poly1305_init(&poly1305, poly1305_key);
156 poly1305_update_with_pad16(&poly1305, ad, ad_len);
157 CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, iv, ctr + 1);
158 poly1305_update_with_pad16(&poly1305, out, in_len);
159 poly1305_update_with_length(&poly1305, NULL, ad_len);
160 poly1305_update_with_length(&poly1305, NULL, in_len);
161
162 if (c20_ctx->tag_len != POLY1305_TAG_LEN) {
163 unsigned char tag[POLY1305_TAG_LEN];
164 CRYPTO_poly1305_finish(&poly1305, tag);
165 memcpy(out + in_len, tag, c20_ctx->tag_len);
166 *out_len = in_len + c20_ctx->tag_len;
167 return 1;
168 }
169
170 CRYPTO_poly1305_finish(&poly1305, out + in_len);
171 *out_len = in_len + POLY1305_TAG_LEN;
172 return 1;
173 }
174
175 static int
aead_chacha20_poly1305_open(const EVP_AEAD_CTX * ctx,unsigned char * out,size_t * out_len,size_t max_out_len,const unsigned char * nonce,size_t nonce_len,const unsigned char * in,size_t in_len,const unsigned char * ad,size_t ad_len)176 aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
177 size_t *out_len, size_t max_out_len, const unsigned char *nonce,
178 size_t nonce_len, const unsigned char *in, size_t in_len,
179 const unsigned char *ad, size_t ad_len)
180 {
181 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
182 unsigned char mac[POLY1305_TAG_LEN];
183 unsigned char poly1305_key[32];
184 const unsigned char *iv = nonce;
185 poly1305_state poly1305;
186 size_t plaintext_len;
187 uint64_t ctr = 0;
188
189 if (in_len < c20_ctx->tag_len) {
190 EVPerror(EVP_R_BAD_DECRYPT);
191 return 0;
192 }
193
194 if (nonce_len != ctx->aead->nonce_len) {
195 EVPerror(EVP_R_IV_TOO_LARGE);
196 return 0;
197 }
198
199 plaintext_len = in_len - c20_ctx->tag_len;
200
201 if (max_out_len < plaintext_len) {
202 EVPerror(EVP_R_BUFFER_TOO_SMALL);
203 return 0;
204 }
205
206 ctr = (uint64_t)((uint32_t)(nonce[0]) | (uint32_t)(nonce[1]) << 8 |
207 (uint32_t)(nonce[2]) << 16 | (uint32_t)(nonce[3]) << 24) << 32;
208 iv = nonce + CHACHA20_CONSTANT_LEN;
209
210 memset(poly1305_key, 0, sizeof(poly1305_key));
211 CRYPTO_chacha_20(poly1305_key, poly1305_key,
212 sizeof(poly1305_key), c20_ctx->key, iv, ctr);
213
214 CRYPTO_poly1305_init(&poly1305, poly1305_key);
215 poly1305_update_with_pad16(&poly1305, ad, ad_len);
216 poly1305_update_with_pad16(&poly1305, in, plaintext_len);
217 poly1305_update_with_length(&poly1305, NULL, ad_len);
218 poly1305_update_with_length(&poly1305, NULL, plaintext_len);
219
220 CRYPTO_poly1305_finish(&poly1305, mac);
221
222 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
223 EVPerror(EVP_R_BAD_DECRYPT);
224 return 0;
225 }
226
227 CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, iv, ctr + 1);
228 *out_len = plaintext_len;
229 return 1;
230 }
231
232 static int
aead_xchacha20_poly1305_seal(const EVP_AEAD_CTX * ctx,unsigned char * out,size_t * out_len,size_t max_out_len,const unsigned char * nonce,size_t nonce_len,const unsigned char * in,size_t in_len,const unsigned char * ad,size_t ad_len)233 aead_xchacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
234 size_t *out_len, size_t max_out_len, const unsigned char *nonce,
235 size_t nonce_len, const unsigned char *in, size_t in_len,
236 const unsigned char *ad, size_t ad_len)
237 {
238 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
239 unsigned char poly1305_key[32];
240 unsigned char subkey[32];
241 poly1305_state poly1305;
242
243 if (max_out_len < in_len + c20_ctx->tag_len) {
244 EVPerror(EVP_R_BUFFER_TOO_SMALL);
245 return 0;
246 }
247
248 if (nonce_len != ctx->aead->nonce_len) {
249 EVPerror(EVP_R_IV_TOO_LARGE);
250 return 0;
251 }
252
253 CRYPTO_hchacha_20(subkey, c20_ctx->key, nonce);
254
255 CRYPTO_chacha_20(out, in, in_len, subkey, nonce + 16, 1);
256
257 memset(poly1305_key, 0, sizeof(poly1305_key));
258 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
259 subkey, nonce + 16, 0);
260
261 CRYPTO_poly1305_init(&poly1305, poly1305_key);
262 poly1305_update_with_pad16(&poly1305, ad, ad_len);
263 poly1305_update_with_pad16(&poly1305, out, in_len);
264 poly1305_update_with_length(&poly1305, NULL, ad_len);
265 poly1305_update_with_length(&poly1305, NULL, in_len);
266
267 if (c20_ctx->tag_len != POLY1305_TAG_LEN) {
268 unsigned char tag[POLY1305_TAG_LEN];
269 CRYPTO_poly1305_finish(&poly1305, tag);
270 memcpy(out + in_len, tag, c20_ctx->tag_len);
271 *out_len = in_len + c20_ctx->tag_len;
272 return 1;
273 }
274
275 CRYPTO_poly1305_finish(&poly1305, out + in_len);
276 *out_len = in_len + POLY1305_TAG_LEN;
277 return 1;
278 }
279
280 static int
aead_xchacha20_poly1305_open(const EVP_AEAD_CTX * ctx,unsigned char * out,size_t * out_len,size_t max_out_len,const unsigned char * nonce,size_t nonce_len,const unsigned char * in,size_t in_len,const unsigned char * ad,size_t ad_len)281 aead_xchacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
282 size_t *out_len, size_t max_out_len, const unsigned char *nonce,
283 size_t nonce_len, const unsigned char *in, size_t in_len,
284 const unsigned char *ad, size_t ad_len)
285 {
286 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
287 unsigned char mac[POLY1305_TAG_LEN];
288 unsigned char poly1305_key[32];
289 unsigned char subkey[32];
290 poly1305_state poly1305;
291 size_t plaintext_len;
292
293 if (in_len < c20_ctx->tag_len) {
294 EVPerror(EVP_R_BAD_DECRYPT);
295 return 0;
296 }
297
298 if (nonce_len != ctx->aead->nonce_len) {
299 EVPerror(EVP_R_IV_TOO_LARGE);
300 return 0;
301 }
302
303 plaintext_len = in_len - c20_ctx->tag_len;
304
305 if (max_out_len < plaintext_len) {
306 EVPerror(EVP_R_BUFFER_TOO_SMALL);
307 return 0;
308 }
309
310 CRYPTO_hchacha_20(subkey, c20_ctx->key, nonce);
311
312 memset(poly1305_key, 0, sizeof(poly1305_key));
313 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
314 subkey, nonce + 16, 0);
315
316 CRYPTO_poly1305_init(&poly1305, poly1305_key);
317 poly1305_update_with_pad16(&poly1305, ad, ad_len);
318 poly1305_update_with_pad16(&poly1305, in, plaintext_len);
319 poly1305_update_with_length(&poly1305, NULL, ad_len);
320 poly1305_update_with_length(&poly1305, NULL, plaintext_len);
321
322 CRYPTO_poly1305_finish(&poly1305, mac);
323 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
324 EVPerror(EVP_R_BAD_DECRYPT);
325 return 0;
326 }
327
328 CRYPTO_chacha_20(out, in, plaintext_len, subkey, nonce + 16, 1);
329
330 *out_len = plaintext_len;
331 return 1;
332 }
333
334 /* RFC 8439 */
335 static const EVP_AEAD aead_chacha20_poly1305 = {
336 .key_len = 32,
337 .nonce_len = CHACHA20_NONCE_LEN,
338 .overhead = POLY1305_TAG_LEN,
339 .max_tag_len = POLY1305_TAG_LEN,
340
341 .init = aead_chacha20_poly1305_init,
342 .cleanup = aead_chacha20_poly1305_cleanup,
343 .seal = aead_chacha20_poly1305_seal,
344 .open = aead_chacha20_poly1305_open,
345 };
346
347 const EVP_AEAD *
EVP_aead_chacha20_poly1305(void)348 EVP_aead_chacha20_poly1305(void)
349 {
350 return &aead_chacha20_poly1305;
351 }
352 LCRYPTO_ALIAS(EVP_aead_chacha20_poly1305);
353
354 static const EVP_AEAD aead_xchacha20_poly1305 = {
355 .key_len = 32,
356 .nonce_len = XCHACHA20_NONCE_LEN,
357 .overhead = POLY1305_TAG_LEN,
358 .max_tag_len = POLY1305_TAG_LEN,
359
360 .init = aead_chacha20_poly1305_init,
361 .cleanup = aead_chacha20_poly1305_cleanup,
362 .seal = aead_xchacha20_poly1305_seal,
363 .open = aead_xchacha20_poly1305_open,
364 };
365
366 const EVP_AEAD *
EVP_aead_xchacha20_poly1305(void)367 EVP_aead_xchacha20_poly1305(void)
368 {
369 return &aead_xchacha20_poly1305;
370 }
371 LCRYPTO_ALIAS(EVP_aead_xchacha20_poly1305);
372
373 struct chacha20_poly1305_ctx {
374 ChaCha_ctx chacha;
375 poly1305_state poly1305;
376
377 unsigned char key[32];
378 unsigned char nonce[CHACHA20_NONCE_LEN];
379 size_t nonce_len;
380 unsigned char tag[POLY1305_TAG_LEN];
381 size_t tag_len;
382
383 size_t ad_len;
384 size_t in_len;
385
386 int in_ad;
387 int started;
388 };
389
390 static int
chacha20_poly1305_init(EVP_CIPHER_CTX * ctx,const unsigned char * key,const unsigned char * iv,int encrypt)391 chacha20_poly1305_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
392 const unsigned char *iv, int encrypt)
393 {
394 struct chacha20_poly1305_ctx *cpx = ctx->cipher_data;
395 uint8_t *data;
396 CBB cbb;
397 int ret = 0;
398
399 memset(&cbb, 0, sizeof(cbb));
400
401 if (key == NULL && iv == NULL)
402 goto done;
403
404 cpx->started = 0;
405
406 if (key != NULL)
407 memcpy(cpx->key, key, sizeof(cpx->key));
408
409 if (iv != NULL) {
410 /*
411 * Left zero pad if configured nonce length is less than ChaCha
412 * nonce length.
413 */
414 if (!CBB_init_fixed(&cbb, cpx->nonce, sizeof(cpx->nonce)))
415 goto err;
416 if (!CBB_add_space(&cbb, &data, sizeof(cpx->nonce) - cpx->nonce_len))
417 goto err;
418 if (!CBB_add_bytes(&cbb, iv, cpx->nonce_len))
419 goto err;
420 if (!CBB_finish(&cbb, NULL, NULL))
421 goto err;
422 }
423
424 done:
425 ret = 1;
426
427 err:
428 CBB_cleanup(&cbb);
429
430 return ret;
431 }
432
433 static int
chacha20_poly1305_cipher(EVP_CIPHER_CTX * ctx,unsigned char * out,const unsigned char * in,size_t len)434 chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
435 const unsigned char *in, size_t len)
436 {
437 struct chacha20_poly1305_ctx *cpx = ctx->cipher_data;
438
439 /*
440 * Since we're making AEAD work within the constraints of EVP_CIPHER...
441 * If in is non-NULL then this is an update, while if in is NULL then
442 * this is a final. If in is non-NULL but out is NULL, then the input
443 * being provided is associated data. Plus we have to handle encryption
444 * (sealing) and decryption (opening) in the same function.
445 */
446
447 if (!cpx->started) {
448 unsigned char poly1305_key[32];
449 const unsigned char *iv;
450 uint64_t ctr;
451
452 ctr = (uint64_t)((uint32_t)(cpx->nonce[0]) |
453 (uint32_t)(cpx->nonce[1]) << 8 |
454 (uint32_t)(cpx->nonce[2]) << 16 |
455 (uint32_t)(cpx->nonce[3]) << 24) << 32;
456 iv = cpx->nonce + CHACHA20_CONSTANT_LEN;
457
458 ChaCha_set_key(&cpx->chacha, cpx->key, 8 * sizeof(cpx->key));
459 ChaCha_set_iv(&cpx->chacha, iv, NULL);
460
461 /* See chacha.c for details re handling of counter. */
462 cpx->chacha.input[12] = (uint32_t)ctr;
463 cpx->chacha.input[13] = (uint32_t)(ctr >> 32);
464
465 memset(poly1305_key, 0, sizeof(poly1305_key));
466 ChaCha(&cpx->chacha, poly1305_key, poly1305_key,
467 sizeof(poly1305_key));
468 CRYPTO_poly1305_init(&cpx->poly1305, poly1305_key);
469
470 /* Mark remaining key block as used. */
471 cpx->chacha.unused = 0;
472
473 cpx->ad_len = 0;
474 cpx->in_len = 0;
475 cpx->in_ad = 0;
476
477 cpx->started = 1;
478 }
479
480 if (len > SIZE_MAX - cpx->in_len) {
481 EVPerror(EVP_R_TOO_LARGE);
482 return -1;
483 }
484
485 /* Disallow authenticated data after plaintext/ciphertext. */
486 if (cpx->in_len > 0 && in != NULL && out == NULL)
487 return -1;
488
489 if (cpx->in_ad && (in == NULL || out != NULL)) {
490 poly1305_pad16(&cpx->poly1305, cpx->ad_len);
491 cpx->in_ad = 0;
492 }
493
494 /* Update with AD or plaintext/ciphertext. */
495 if (in != NULL) {
496 if (!ctx->encrypt || out == NULL)
497 CRYPTO_poly1305_update(&cpx->poly1305, in, len);
498 if (out == NULL) {
499 cpx->ad_len += len;
500 cpx->in_ad = 1;
501 } else {
502 ChaCha(&cpx->chacha, out, in, len);
503 cpx->in_len += len;
504 }
505 if (ctx->encrypt && out != NULL)
506 CRYPTO_poly1305_update(&cpx->poly1305, out, len);
507
508 return len;
509 }
510
511 /* Final. */
512 poly1305_pad16(&cpx->poly1305, cpx->in_len);
513 poly1305_update_with_length(&cpx->poly1305, NULL, cpx->ad_len);
514 poly1305_update_with_length(&cpx->poly1305, NULL, cpx->in_len);
515
516 if (ctx->encrypt) {
517 CRYPTO_poly1305_finish(&cpx->poly1305, cpx->tag);
518 cpx->tag_len = sizeof(cpx->tag);
519 } else {
520 unsigned char tag[POLY1305_TAG_LEN];
521
522 /* Ensure that a tag has been provided. */
523 if (cpx->tag_len <= 0)
524 return -1;
525
526 CRYPTO_poly1305_finish(&cpx->poly1305, tag);
527 if (timingsafe_memcmp(tag, cpx->tag, cpx->tag_len) != 0)
528 return -1;
529 }
530
531 cpx->started = 0;
532
533 return len;
534 }
535
536 static int
chacha20_poly1305_cleanup(EVP_CIPHER_CTX * ctx)537 chacha20_poly1305_cleanup(EVP_CIPHER_CTX *ctx)
538 {
539 struct chacha20_poly1305_ctx *cpx = ctx->cipher_data;
540
541 explicit_bzero(cpx, sizeof(*cpx));
542
543 return 1;
544 }
545
546 static int
chacha20_poly1305_ctrl(EVP_CIPHER_CTX * ctx,int type,int arg,void * ptr)547 chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
548 {
549 struct chacha20_poly1305_ctx *cpx = ctx->cipher_data;
550
551 switch (type) {
552 case EVP_CTRL_INIT:
553 memset(cpx, 0, sizeof(*cpx));
554 cpx->nonce_len = sizeof(cpx->nonce);
555 return 1;
556
557 case EVP_CTRL_AEAD_GET_IVLEN:
558 if (cpx->nonce_len > INT_MAX)
559 return 0;
560 *(int *)ptr = (int)cpx->nonce_len;
561 return 1;
562
563 case EVP_CTRL_AEAD_SET_IVLEN:
564 if (arg <= 0 || arg > sizeof(cpx->nonce))
565 return 0;
566 cpx->nonce_len = arg;
567 return 1;
568
569 case EVP_CTRL_AEAD_SET_TAG:
570 if (ctx->encrypt)
571 return 0;
572 if (arg <= 0 || arg > sizeof(cpx->tag))
573 return 0;
574 if (ptr != NULL) {
575 memcpy(cpx->tag, ptr, arg);
576 cpx->tag_len = arg;
577 }
578 return 1;
579
580 case EVP_CTRL_AEAD_GET_TAG:
581 if (!ctx->encrypt)
582 return 0;
583 if (arg <= 0 || arg > cpx->tag_len)
584 return 0;
585 memcpy(ptr, cpx->tag, arg);
586 return 1;
587
588 case EVP_CTRL_AEAD_SET_IV_FIXED:
589 if (arg != sizeof(cpx->nonce))
590 return 0;
591 memcpy(cpx->nonce, ptr, arg);
592 return 1;
593 }
594
595 return 0;
596 }
597
598 static const EVP_CIPHER cipher_chacha20_poly1305 = {
599 .nid = NID_chacha20_poly1305,
600 .block_size = 1,
601 .key_len = 32,
602 .iv_len = 12,
603 .flags = EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
604 EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_IV_LENGTH |
605 EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_CUSTOM_CIPHER |
606 EVP_CIPH_FLAG_DEFAULT_ASN1,
607 .init = chacha20_poly1305_init,
608 .do_cipher = chacha20_poly1305_cipher,
609 .cleanup = chacha20_poly1305_cleanup,
610 .ctx_size = sizeof(struct chacha20_poly1305_ctx),
611 .ctrl = chacha20_poly1305_ctrl,
612 };
613
614 const EVP_CIPHER *
EVP_chacha20_poly1305(void)615 EVP_chacha20_poly1305(void)
616 {
617 return &cipher_chacha20_poly1305;
618 }
619 LCRYPTO_ALIAS(EVP_chacha20_poly1305);
620
621 #endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */
622