diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/libcrypto/evp/e_chacha20poly1305.c | 621 |
1 files changed, 0 insertions, 621 deletions
diff --git a/src/lib/libcrypto/evp/e_chacha20poly1305.c b/src/lib/libcrypto/evp/e_chacha20poly1305.c deleted file mode 100644 index d176569f90..0000000000 --- a/src/lib/libcrypto/evp/e_chacha20poly1305.c +++ /dev/null | |||
@@ -1,621 +0,0 @@ | |||
1 | /* $OpenBSD: e_chacha20poly1305.c,v 1.37 2024/12/20 20:05:29 schwarze 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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 * | ||
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 * | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 -1; | ||
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 * | ||
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 */ | ||