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