xref: /freebsd/sys/crypto/openssl/ossl_chacha20.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
192aecd1eSJohn Baldwin /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
392aecd1eSJohn Baldwin  *
492aecd1eSJohn Baldwin  * Copyright (c) 2020 Netflix, Inc
592aecd1eSJohn Baldwin  *
692aecd1eSJohn Baldwin  * Redistribution and use in source and binary forms, with or without
792aecd1eSJohn Baldwin  * modification, are permitted provided that the following conditions
892aecd1eSJohn Baldwin  * are met:
992aecd1eSJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
1092aecd1eSJohn Baldwin  *    notice, this list of conditions and the following disclaimer,
1192aecd1eSJohn Baldwin  *    without modification.
1292aecd1eSJohn Baldwin  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1392aecd1eSJohn Baldwin  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1492aecd1eSJohn Baldwin  *    redistribution must be conditioned upon including a substantially
1592aecd1eSJohn Baldwin  *    similar Disclaimer requirement for further binary redistribution.
1692aecd1eSJohn Baldwin  *
1792aecd1eSJohn Baldwin  * NO WARRANTY
1892aecd1eSJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1992aecd1eSJohn Baldwin  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2092aecd1eSJohn Baldwin  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2192aecd1eSJohn Baldwin  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2292aecd1eSJohn Baldwin  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2392aecd1eSJohn Baldwin  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2492aecd1eSJohn Baldwin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2592aecd1eSJohn Baldwin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2692aecd1eSJohn Baldwin  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2792aecd1eSJohn Baldwin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2892aecd1eSJohn Baldwin  * THE POSSIBILITY OF SUCH DAMAGES.
2992aecd1eSJohn Baldwin  */
3092aecd1eSJohn Baldwin 
3192aecd1eSJohn Baldwin #include <sys/types.h>
3292aecd1eSJohn Baldwin #include <sys/endian.h>
3392aecd1eSJohn Baldwin #include <sys/malloc.h>
3492aecd1eSJohn Baldwin #include <sys/time.h>
3592aecd1eSJohn Baldwin 
3692aecd1eSJohn Baldwin #include <opencrypto/cryptodev.h>
3792aecd1eSJohn Baldwin 
3892aecd1eSJohn Baldwin #include <crypto/openssl/ossl.h>
3992aecd1eSJohn Baldwin #include <crypto/openssl/ossl_chacha.h>
40197ff4c3SKornel Duleba #include <crypto/openssl/ossl_cipher.h>
4178991a93SJohn Baldwin #include <crypto/openssl/ossl_poly1305.h>
4292aecd1eSJohn Baldwin 
43197ff4c3SKornel Duleba static ossl_cipher_process_t ossl_chacha20;
44197ff4c3SKornel Duleba 
45197ff4c3SKornel Duleba struct ossl_cipher ossl_cipher_chacha20 = {
46197ff4c3SKornel Duleba 	.type = CRYPTO_CHACHA20,
47197ff4c3SKornel Duleba 	.blocksize = CHACHA_BLK_SIZE,
48197ff4c3SKornel Duleba 	.ivsize = CHACHA_CTR_SIZE,
49197ff4c3SKornel Duleba 
50197ff4c3SKornel Duleba 	.set_encrypt_key = NULL,
51197ff4c3SKornel Duleba 	.set_decrypt_key = NULL,
52197ff4c3SKornel Duleba 	.process = ossl_chacha20
53197ff4c3SKornel Duleba };
54197ff4c3SKornel Duleba 
55197ff4c3SKornel Duleba static int
ossl_chacha20(struct ossl_session_cipher * s,struct cryptop * crp,const struct crypto_session_params * csp)56197ff4c3SKornel Duleba ossl_chacha20(struct ossl_session_cipher *s, struct cryptop *crp,
57197ff4c3SKornel Duleba     const struct crypto_session_params *csp)
5892aecd1eSJohn Baldwin {
5992aecd1eSJohn Baldwin 	_Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4];
6092aecd1eSJohn Baldwin 	unsigned int counter[CHACHA_CTR_SIZE / 4];
6192aecd1eSJohn Baldwin 	unsigned char block[CHACHA_BLK_SIZE];
6292aecd1eSJohn Baldwin 	struct crypto_buffer_cursor cc_in, cc_out;
6392aecd1eSJohn Baldwin 	const unsigned char *in, *inseg, *cipher_key;
6492aecd1eSJohn Baldwin 	unsigned char *out, *outseg;
6592aecd1eSJohn Baldwin 	size_t resid, todo, inlen, outlen;
6692aecd1eSJohn Baldwin 	uint32_t next_counter;
6792aecd1eSJohn Baldwin 	u_int i;
6892aecd1eSJohn Baldwin 
6992aecd1eSJohn Baldwin 	if (crp->crp_cipher_key != NULL)
7092aecd1eSJohn Baldwin 		cipher_key = crp->crp_cipher_key;
7192aecd1eSJohn Baldwin 	else
7292aecd1eSJohn Baldwin 		cipher_key = csp->csp_cipher_key;
7392aecd1eSJohn Baldwin 	for (i = 0; i < nitems(key); i++)
7492aecd1eSJohn Baldwin 		key[i] = CHACHA_U8TOU32(cipher_key + i * 4);
7592aecd1eSJohn Baldwin 	crypto_read_iv(crp, counter);
7692aecd1eSJohn Baldwin 	for (i = 0; i < nitems(counter); i++)
7792aecd1eSJohn Baldwin 		counter[i] = le32toh(counter[i]);
7892aecd1eSJohn Baldwin 
7992aecd1eSJohn Baldwin 	resid = crp->crp_payload_length;
8092aecd1eSJohn Baldwin 	crypto_cursor_init(&cc_in, &crp->crp_buf);
8192aecd1eSJohn Baldwin 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
821c09320dSJohn Baldwin 	inseg = crypto_cursor_segment(&cc_in, &inlen);
8392aecd1eSJohn Baldwin 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
8492aecd1eSJohn Baldwin 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
8592aecd1eSJohn Baldwin 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
8692aecd1eSJohn Baldwin 	} else
8792aecd1eSJohn Baldwin 		cc_out = cc_in;
881c09320dSJohn Baldwin 	outseg = crypto_cursor_segment(&cc_out, &outlen);
8992aecd1eSJohn Baldwin 	while (resid >= CHACHA_BLK_SIZE) {
9092aecd1eSJohn Baldwin 		if (inlen < CHACHA_BLK_SIZE) {
9192aecd1eSJohn Baldwin 			crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block);
9292aecd1eSJohn Baldwin 			in = block;
9392aecd1eSJohn Baldwin 			inlen = CHACHA_BLK_SIZE;
9492aecd1eSJohn Baldwin 		} else
9592aecd1eSJohn Baldwin 			in = inseg;
9692aecd1eSJohn Baldwin 		if (outlen < CHACHA_BLK_SIZE) {
9792aecd1eSJohn Baldwin 			out = block;
9892aecd1eSJohn Baldwin 			outlen = CHACHA_BLK_SIZE;
9992aecd1eSJohn Baldwin 		} else
10092aecd1eSJohn Baldwin 			out = outseg;
10192aecd1eSJohn Baldwin 
10292aecd1eSJohn Baldwin 		/* Figure out how many blocks we can encrypt/decrypt at once. */
103d2e076c3SJohn Baldwin 		todo = rounddown(MIN(resid, MIN(inlen, outlen)),
104d2e076c3SJohn Baldwin 		    CHACHA_BLK_SIZE);
10592aecd1eSJohn Baldwin 
10692aecd1eSJohn Baldwin #ifdef __LP64__
10792aecd1eSJohn Baldwin 		/* ChaCha20_ctr32() assumes length is <= 4GB. */
10892aecd1eSJohn Baldwin 		todo = (uint32_t)todo;
10992aecd1eSJohn Baldwin #endif
11092aecd1eSJohn Baldwin 
11192aecd1eSJohn Baldwin 		/* Truncate if the 32-bit counter would roll over. */
11292aecd1eSJohn Baldwin 		next_counter = counter[0] + todo / CHACHA_BLK_SIZE;
11392aecd1eSJohn Baldwin 		if (next_counter < counter[0]) {
11492aecd1eSJohn Baldwin 			todo -= next_counter * CHACHA_BLK_SIZE;
11592aecd1eSJohn Baldwin 			next_counter = 0;
11692aecd1eSJohn Baldwin 		}
11792aecd1eSJohn Baldwin 
11892aecd1eSJohn Baldwin 		ChaCha20_ctr32(out, in, todo, key, counter);
11992aecd1eSJohn Baldwin 
12092aecd1eSJohn Baldwin 		counter[0] = next_counter;
12192aecd1eSJohn Baldwin 		if (counter[0] == 0)
12292aecd1eSJohn Baldwin 			counter[1]++;
12392aecd1eSJohn Baldwin 
12492aecd1eSJohn Baldwin 		if (out == block) {
12592aecd1eSJohn Baldwin 			crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block);
1261c09320dSJohn Baldwin 			outseg = crypto_cursor_segment(&cc_out, &outlen);
12792aecd1eSJohn Baldwin 		} else {
12892aecd1eSJohn Baldwin 			crypto_cursor_advance(&cc_out, todo);
12992aecd1eSJohn Baldwin 			outseg += todo;
13092aecd1eSJohn Baldwin 			outlen -= todo;
13192aecd1eSJohn Baldwin 		}
13292aecd1eSJohn Baldwin 		if (in == block) {
1331c09320dSJohn Baldwin 			inseg = crypto_cursor_segment(&cc_in, &inlen);
13492aecd1eSJohn Baldwin 		} else {
13592aecd1eSJohn Baldwin 			crypto_cursor_advance(&cc_in, todo);
13692aecd1eSJohn Baldwin 			inseg += todo;
13792aecd1eSJohn Baldwin 			inlen -= todo;
13892aecd1eSJohn Baldwin 		}
13992aecd1eSJohn Baldwin 		resid -= todo;
14092aecd1eSJohn Baldwin 	}
14192aecd1eSJohn Baldwin 
14292aecd1eSJohn Baldwin 	if (resid > 0) {
14392aecd1eSJohn Baldwin 		memset(block, 0, sizeof(block));
14492aecd1eSJohn Baldwin 		crypto_cursor_copydata(&cc_in, resid, block);
14592aecd1eSJohn Baldwin 		ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter);
14692aecd1eSJohn Baldwin 		crypto_cursor_copyback(&cc_out, resid, block);
14792aecd1eSJohn Baldwin 	}
14892aecd1eSJohn Baldwin 
14992aecd1eSJohn Baldwin 	explicit_bzero(block, sizeof(block));
15092aecd1eSJohn Baldwin 	explicit_bzero(counter, sizeof(counter));
15192aecd1eSJohn Baldwin 	explicit_bzero(key, sizeof(key));
15292aecd1eSJohn Baldwin 	return (0);
15392aecd1eSJohn Baldwin }
15478991a93SJohn Baldwin 
15578991a93SJohn Baldwin int
ossl_chacha20_poly1305_encrypt(struct cryptop * crp,const struct crypto_session_params * csp)15678991a93SJohn Baldwin ossl_chacha20_poly1305_encrypt(struct cryptop *crp,
15778991a93SJohn Baldwin     const struct crypto_session_params *csp)
15878991a93SJohn Baldwin {
15978991a93SJohn Baldwin 	_Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4];
16078991a93SJohn Baldwin 	unsigned int counter[CHACHA_CTR_SIZE / 4];
16178991a93SJohn Baldwin 	_Alignas(8) unsigned char block[CHACHA_BLK_SIZE];
16278991a93SJohn Baldwin 	unsigned char tag[POLY1305_HASH_LEN];
16378991a93SJohn Baldwin 	POLY1305 auth_ctx;
16478991a93SJohn Baldwin 	struct crypto_buffer_cursor cc_in, cc_out;
16578991a93SJohn Baldwin 	const unsigned char *in, *inseg, *cipher_key;
16678991a93SJohn Baldwin 	unsigned char *out, *outseg;
16778991a93SJohn Baldwin 	size_t resid, todo, inlen, outlen;
16878991a93SJohn Baldwin 	uint32_t next_counter;
16978991a93SJohn Baldwin 	u_int i;
17078991a93SJohn Baldwin 
17178991a93SJohn Baldwin 	if (crp->crp_cipher_key != NULL)
17278991a93SJohn Baldwin 		cipher_key = crp->crp_cipher_key;
17378991a93SJohn Baldwin 	else
17478991a93SJohn Baldwin 		cipher_key = csp->csp_cipher_key;
17578991a93SJohn Baldwin 	for (i = 0; i < nitems(key); i++)
17678991a93SJohn Baldwin 		key[i] = CHACHA_U8TOU32(cipher_key + i * 4);
17778991a93SJohn Baldwin 
17842dcd395SJohn Baldwin 	memset(counter, 0, sizeof(counter));
17942dcd395SJohn Baldwin 	crypto_read_iv(crp, counter + (CHACHA_CTR_SIZE - csp->csp_ivlen) / 4);
18078991a93SJohn Baldwin 	for (i = 1; i < nitems(counter); i++)
18178991a93SJohn Baldwin 		counter[i] = le32toh(counter[i]);
18278991a93SJohn Baldwin 
18378991a93SJohn Baldwin 	/* Block 0 is used to generate the poly1305 key. */
18478991a93SJohn Baldwin 	counter[0] = 0;
18578991a93SJohn Baldwin 
18678991a93SJohn Baldwin 	memset(block, 0, sizeof(block));
18778991a93SJohn Baldwin 	ChaCha20_ctr32(block, block, sizeof(block), key, counter);
18878991a93SJohn Baldwin 	Poly1305_Init(&auth_ctx, block);
18978991a93SJohn Baldwin 
19078991a93SJohn Baldwin 	/* MAC the AAD. */
19178991a93SJohn Baldwin 	if (crp->crp_aad != NULL)
19278991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, crp->crp_aad, crp->crp_aad_length);
19378991a93SJohn Baldwin 	else
19478991a93SJohn Baldwin 		crypto_apply(crp, crp->crp_aad_start, crp->crp_aad_length,
19578991a93SJohn Baldwin 		    ossl_poly1305_update, &auth_ctx);
19678991a93SJohn Baldwin 	if (crp->crp_aad_length % 16 != 0) {
19778991a93SJohn Baldwin 		/* padding1 */
19878991a93SJohn Baldwin 		memset(block, 0, 16);
19978991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, block,
20078991a93SJohn Baldwin 		    16 - crp->crp_aad_length % 16);
20178991a93SJohn Baldwin 	}
20278991a93SJohn Baldwin 
20378991a93SJohn Baldwin 	/* Encryption starts with block 1. */
20478991a93SJohn Baldwin 	counter[0] = 1;
20578991a93SJohn Baldwin 
20678991a93SJohn Baldwin 	/* Do encryption with MAC */
20778991a93SJohn Baldwin 	resid = crp->crp_payload_length;
20878991a93SJohn Baldwin 	crypto_cursor_init(&cc_in, &crp->crp_buf);
20978991a93SJohn Baldwin 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
2101c09320dSJohn Baldwin 	inseg = crypto_cursor_segment(&cc_in, &inlen);
21178991a93SJohn Baldwin 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
21278991a93SJohn Baldwin 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
21378991a93SJohn Baldwin 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
21478991a93SJohn Baldwin 	} else
21578991a93SJohn Baldwin 		cc_out = cc_in;
2161c09320dSJohn Baldwin 	outseg = crypto_cursor_segment(&cc_out, &outlen);
21778991a93SJohn Baldwin 	while (resid >= CHACHA_BLK_SIZE) {
21878991a93SJohn Baldwin 		if (inlen < CHACHA_BLK_SIZE) {
21978991a93SJohn Baldwin 			crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block);
22078991a93SJohn Baldwin 			in = block;
22178991a93SJohn Baldwin 			inlen = CHACHA_BLK_SIZE;
22278991a93SJohn Baldwin 		} else
22378991a93SJohn Baldwin 			in = inseg;
22478991a93SJohn Baldwin 		if (outlen < CHACHA_BLK_SIZE) {
22578991a93SJohn Baldwin 			out = block;
22678991a93SJohn Baldwin 			outlen = CHACHA_BLK_SIZE;
22778991a93SJohn Baldwin 		} else
22878991a93SJohn Baldwin 			out = outseg;
22978991a93SJohn Baldwin 
23078991a93SJohn Baldwin 		/* Figure out how many blocks we can encrypt/decrypt at once. */
231d2e076c3SJohn Baldwin 		todo = rounddown(MIN(resid, MIN(inlen, outlen)),
232d2e076c3SJohn Baldwin 		    CHACHA_BLK_SIZE);
23378991a93SJohn Baldwin 
23478991a93SJohn Baldwin #ifdef __LP64__
23578991a93SJohn Baldwin 		/* ChaCha20_ctr32() assumes length is <= 4GB. */
23678991a93SJohn Baldwin 		todo = (uint32_t)todo;
23778991a93SJohn Baldwin #endif
23878991a93SJohn Baldwin 
23978991a93SJohn Baldwin 		/* Truncate if the 32-bit counter would roll over. */
24078991a93SJohn Baldwin 		next_counter = counter[0] + todo / CHACHA_BLK_SIZE;
24142dcd395SJohn Baldwin 		if (csp->csp_ivlen == 8 && next_counter < counter[0]) {
24278991a93SJohn Baldwin 			todo -= next_counter * CHACHA_BLK_SIZE;
24378991a93SJohn Baldwin 			next_counter = 0;
24478991a93SJohn Baldwin 		}
24578991a93SJohn Baldwin 
24678991a93SJohn Baldwin 		ChaCha20_ctr32(out, in, todo, key, counter);
24778991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, out, todo);
24878991a93SJohn Baldwin 
24978991a93SJohn Baldwin 		counter[0] = next_counter;
25042dcd395SJohn Baldwin 		if (csp->csp_ivlen == 8 && counter[0] == 0)
25178991a93SJohn Baldwin 			counter[1]++;
25278991a93SJohn Baldwin 
25378991a93SJohn Baldwin 		if (out == block) {
25478991a93SJohn Baldwin 			crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block);
2551c09320dSJohn Baldwin 			outseg = crypto_cursor_segment(&cc_out, &outlen);
25678991a93SJohn Baldwin 		} else {
25778991a93SJohn Baldwin 			crypto_cursor_advance(&cc_out, todo);
25878991a93SJohn Baldwin 			outseg += todo;
25978991a93SJohn Baldwin 			outlen -= todo;
26078991a93SJohn Baldwin 		}
26178991a93SJohn Baldwin 		if (in == block) {
2621c09320dSJohn Baldwin 			inseg = crypto_cursor_segment(&cc_in, &inlen);
26378991a93SJohn Baldwin 		} else {
26478991a93SJohn Baldwin 			crypto_cursor_advance(&cc_in, todo);
26578991a93SJohn Baldwin 			inseg += todo;
26678991a93SJohn Baldwin 			inlen -= todo;
26778991a93SJohn Baldwin 		}
26878991a93SJohn Baldwin 		resid -= todo;
26978991a93SJohn Baldwin 	}
27078991a93SJohn Baldwin 
27178991a93SJohn Baldwin 	if (resid > 0) {
27278991a93SJohn Baldwin 		memset(block, 0, sizeof(block));
27378991a93SJohn Baldwin 		crypto_cursor_copydata(&cc_in, resid, block);
27478991a93SJohn Baldwin 		ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter);
27578991a93SJohn Baldwin 		crypto_cursor_copyback(&cc_out, resid, block);
27678991a93SJohn Baldwin 
27778991a93SJohn Baldwin 		/* padding2 */
27878991a93SJohn Baldwin 		todo = roundup2(resid, 16);
27978991a93SJohn Baldwin 		memset(block + resid, 0, todo - resid);
28078991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, block, todo);
28178991a93SJohn Baldwin 	}
28278991a93SJohn Baldwin 
28378991a93SJohn Baldwin 	/* lengths */
28478991a93SJohn Baldwin 	le64enc(block, crp->crp_aad_length);
28578991a93SJohn Baldwin 	le64enc(block + 8, crp->crp_payload_length);
28678991a93SJohn Baldwin 	Poly1305_Update(&auth_ctx, block, sizeof(uint64_t) * 2);
28778991a93SJohn Baldwin 
28878991a93SJohn Baldwin 	Poly1305_Final(&auth_ctx, tag);
28978991a93SJohn Baldwin 	crypto_copyback(crp, crp->crp_digest_start, csp->csp_auth_mlen == 0 ?
29078991a93SJohn Baldwin 	    POLY1305_HASH_LEN : csp->csp_auth_mlen, tag);
29178991a93SJohn Baldwin 
29278991a93SJohn Baldwin 	explicit_bzero(&auth_ctx, sizeof(auth_ctx));
29378991a93SJohn Baldwin 	explicit_bzero(tag, sizeof(tag));
29478991a93SJohn Baldwin 	explicit_bzero(block, sizeof(block));
29578991a93SJohn Baldwin 	explicit_bzero(counter, sizeof(counter));
29678991a93SJohn Baldwin 	explicit_bzero(key, sizeof(key));
29778991a93SJohn Baldwin 	return (0);
29878991a93SJohn Baldwin }
29978991a93SJohn Baldwin 
30078991a93SJohn Baldwin 
30178991a93SJohn Baldwin int
ossl_chacha20_poly1305_decrypt(struct cryptop * crp,const struct crypto_session_params * csp)30278991a93SJohn Baldwin ossl_chacha20_poly1305_decrypt(struct cryptop *crp,
30378991a93SJohn Baldwin     const struct crypto_session_params *csp)
30478991a93SJohn Baldwin {
30578991a93SJohn Baldwin 	_Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4];
30678991a93SJohn Baldwin 	unsigned int counter[CHACHA_CTR_SIZE / 4];
30778991a93SJohn Baldwin 	_Alignas(8) unsigned char block[CHACHA_BLK_SIZE];
30878991a93SJohn Baldwin 	unsigned char tag[POLY1305_HASH_LEN], tag2[POLY1305_HASH_LEN];
30978991a93SJohn Baldwin 	struct poly1305_context auth_ctx;
31078991a93SJohn Baldwin 	struct crypto_buffer_cursor cc_in, cc_out;
31178991a93SJohn Baldwin 	const unsigned char *in, *inseg, *cipher_key;
31278991a93SJohn Baldwin 	unsigned char *out, *outseg;
31378991a93SJohn Baldwin 	size_t resid, todo, inlen, outlen;
31478991a93SJohn Baldwin 	uint32_t next_counter;
31578991a93SJohn Baldwin 	int error;
31678991a93SJohn Baldwin 	u_int i, mlen;
31778991a93SJohn Baldwin 
31878991a93SJohn Baldwin 	if (crp->crp_cipher_key != NULL)
31978991a93SJohn Baldwin 		cipher_key = crp->crp_cipher_key;
32078991a93SJohn Baldwin 	else
32178991a93SJohn Baldwin 		cipher_key = csp->csp_cipher_key;
32278991a93SJohn Baldwin 	for (i = 0; i < nitems(key); i++)
32378991a93SJohn Baldwin 		key[i] = CHACHA_U8TOU32(cipher_key + i * 4);
32478991a93SJohn Baldwin 
32542dcd395SJohn Baldwin 	memset(counter, 0, sizeof(counter));
32642dcd395SJohn Baldwin 	crypto_read_iv(crp, counter + (CHACHA_CTR_SIZE - csp->csp_ivlen) / 4);
32778991a93SJohn Baldwin 	for (i = 1; i < nitems(counter); i++)
32878991a93SJohn Baldwin 		counter[i] = le32toh(counter[i]);
32978991a93SJohn Baldwin 
33078991a93SJohn Baldwin 	/* Block 0 is used to generate the poly1305 key. */
33178991a93SJohn Baldwin 	counter[0] = 0;
33278991a93SJohn Baldwin 
33378991a93SJohn Baldwin 	memset(block, 0, sizeof(block));
33478991a93SJohn Baldwin 	ChaCha20_ctr32(block, block, sizeof(block), key, counter);
33578991a93SJohn Baldwin 	Poly1305_Init(&auth_ctx, block);
33678991a93SJohn Baldwin 
33778991a93SJohn Baldwin 	/* MAC the AAD. */
33878991a93SJohn Baldwin 	if (crp->crp_aad != NULL)
33978991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, crp->crp_aad, crp->crp_aad_length);
34078991a93SJohn Baldwin 	else
34178991a93SJohn Baldwin 		crypto_apply(crp, crp->crp_aad_start, crp->crp_aad_length,
34278991a93SJohn Baldwin 		    ossl_poly1305_update, &auth_ctx);
34378991a93SJohn Baldwin 	if (crp->crp_aad_length % 16 != 0) {
34478991a93SJohn Baldwin 		/* padding1 */
34578991a93SJohn Baldwin 		memset(block, 0, 16);
34678991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, block,
34778991a93SJohn Baldwin 		    16 - crp->crp_aad_length % 16);
34878991a93SJohn Baldwin 	}
34978991a93SJohn Baldwin 
35078991a93SJohn Baldwin 	/* Mac the ciphertext. */
35178991a93SJohn Baldwin 	crypto_apply(crp, crp->crp_payload_start, crp->crp_payload_length,
35278991a93SJohn Baldwin 	    ossl_poly1305_update, &auth_ctx);
35378991a93SJohn Baldwin 	if (crp->crp_payload_length % 16 != 0) {
35478991a93SJohn Baldwin 		/* padding2 */
35578991a93SJohn Baldwin 		memset(block, 0, 16);
35678991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, block,
35778991a93SJohn Baldwin 		    16 - crp->crp_payload_length % 16);
35878991a93SJohn Baldwin 	}
35978991a93SJohn Baldwin 
36078991a93SJohn Baldwin 	/* lengths */
36178991a93SJohn Baldwin 	le64enc(block, crp->crp_aad_length);
36278991a93SJohn Baldwin 	le64enc(block + 8, crp->crp_payload_length);
36378991a93SJohn Baldwin 	Poly1305_Update(&auth_ctx, block, sizeof(uint64_t) * 2);
36478991a93SJohn Baldwin 
36578991a93SJohn Baldwin 	Poly1305_Final(&auth_ctx, tag);
36678991a93SJohn Baldwin 	mlen = csp->csp_auth_mlen == 0 ? POLY1305_HASH_LEN : csp->csp_auth_mlen;
36778991a93SJohn Baldwin 	crypto_copydata(crp, crp->crp_digest_start, mlen, tag2);
36878991a93SJohn Baldwin 	if (timingsafe_bcmp(tag, tag2, mlen) != 0) {
36978991a93SJohn Baldwin 		error = EBADMSG;
37078991a93SJohn Baldwin 		goto out;
37178991a93SJohn Baldwin 	}
37278991a93SJohn Baldwin 
37378991a93SJohn Baldwin 	/* Decryption starts with block 1. */
37478991a93SJohn Baldwin 	counter[0] = 1;
37578991a93SJohn Baldwin 
37678991a93SJohn Baldwin 	resid = crp->crp_payload_length;
37778991a93SJohn Baldwin 	crypto_cursor_init(&cc_in, &crp->crp_buf);
37878991a93SJohn Baldwin 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
3791c09320dSJohn Baldwin 	inseg = crypto_cursor_segment(&cc_in, &inlen);
38078991a93SJohn Baldwin 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
38178991a93SJohn Baldwin 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
38278991a93SJohn Baldwin 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
38378991a93SJohn Baldwin 	} else
38478991a93SJohn Baldwin 		cc_out = cc_in;
3851c09320dSJohn Baldwin 	outseg = crypto_cursor_segment(&cc_out, &outlen);
38678991a93SJohn Baldwin 	while (resid >= CHACHA_BLK_SIZE) {
38778991a93SJohn Baldwin 		if (inlen < CHACHA_BLK_SIZE) {
38878991a93SJohn Baldwin 			crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block);
38978991a93SJohn Baldwin 			in = block;
39078991a93SJohn Baldwin 			inlen = CHACHA_BLK_SIZE;
39178991a93SJohn Baldwin 		} else
39278991a93SJohn Baldwin 			in = inseg;
39378991a93SJohn Baldwin 		if (outlen < CHACHA_BLK_SIZE) {
39478991a93SJohn Baldwin 			out = block;
39578991a93SJohn Baldwin 			outlen = CHACHA_BLK_SIZE;
39678991a93SJohn Baldwin 		} else
39778991a93SJohn Baldwin 			out = outseg;
39878991a93SJohn Baldwin 
39978991a93SJohn Baldwin 		/* Figure out how many blocks we can encrypt/decrypt at once. */
400d2e076c3SJohn Baldwin 		todo = rounddown(MIN(resid, MIN(inlen, outlen)),
401d2e076c3SJohn Baldwin 		    CHACHA_BLK_SIZE);
40278991a93SJohn Baldwin 
40378991a93SJohn Baldwin #ifdef __LP64__
40478991a93SJohn Baldwin 		/* ChaCha20_ctr32() assumes length is <= 4GB. */
40578991a93SJohn Baldwin 		todo = (uint32_t)todo;
40678991a93SJohn Baldwin #endif
40778991a93SJohn Baldwin 
40878991a93SJohn Baldwin 		/* Truncate if the 32-bit counter would roll over. */
40978991a93SJohn Baldwin 		next_counter = counter[0] + todo / CHACHA_BLK_SIZE;
41042dcd395SJohn Baldwin 		if (csp->csp_ivlen == 8 && next_counter < counter[0]) {
41178991a93SJohn Baldwin 			todo -= next_counter * CHACHA_BLK_SIZE;
41278991a93SJohn Baldwin 			next_counter = 0;
41378991a93SJohn Baldwin 		}
41478991a93SJohn Baldwin 
41578991a93SJohn Baldwin 		ChaCha20_ctr32(out, in, todo, key, counter);
41678991a93SJohn Baldwin 
41778991a93SJohn Baldwin 		counter[0] = next_counter;
41842dcd395SJohn Baldwin 		if (csp->csp_ivlen == 8 && counter[0] == 0)
41978991a93SJohn Baldwin 			counter[1]++;
42078991a93SJohn Baldwin 
42178991a93SJohn Baldwin 		if (out == block) {
42278991a93SJohn Baldwin 			crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block);
4231c09320dSJohn Baldwin 			outseg = crypto_cursor_segment(&cc_out, &outlen);
42478991a93SJohn Baldwin 		} else {
42578991a93SJohn Baldwin 			crypto_cursor_advance(&cc_out, todo);
42678991a93SJohn Baldwin 			outseg += todo;
42778991a93SJohn Baldwin 			outlen -= todo;
42878991a93SJohn Baldwin 		}
42978991a93SJohn Baldwin 		if (in == block) {
4301c09320dSJohn Baldwin 			inseg = crypto_cursor_segment(&cc_in, &inlen);
43178991a93SJohn Baldwin 		} else {
43278991a93SJohn Baldwin 			crypto_cursor_advance(&cc_in, todo);
43378991a93SJohn Baldwin 			inseg += todo;
43478991a93SJohn Baldwin 			inlen -= todo;
43578991a93SJohn Baldwin 		}
43678991a93SJohn Baldwin 		resid -= todo;
43778991a93SJohn Baldwin 	}
43878991a93SJohn Baldwin 
43978991a93SJohn Baldwin 	if (resid > 0) {
44078991a93SJohn Baldwin 		memset(block, 0, sizeof(block));
44178991a93SJohn Baldwin 		crypto_cursor_copydata(&cc_in, resid, block);
44278991a93SJohn Baldwin 		ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter);
44378991a93SJohn Baldwin 		crypto_cursor_copyback(&cc_out, resid, block);
44478991a93SJohn Baldwin 	}
44578991a93SJohn Baldwin 
44678991a93SJohn Baldwin 	error = 0;
44778991a93SJohn Baldwin out:
44878991a93SJohn Baldwin 	explicit_bzero(&auth_ctx, sizeof(auth_ctx));
44978991a93SJohn Baldwin 	explicit_bzero(tag, sizeof(tag));
45078991a93SJohn Baldwin 	explicit_bzero(block, sizeof(block));
45178991a93SJohn Baldwin 	explicit_bzero(counter, sizeof(counter));
45278991a93SJohn Baldwin 	explicit_bzero(key, sizeof(key));
45378991a93SJohn Baldwin 	return (error);
45478991a93SJohn Baldwin }
455