xref: /freebsd/sys/crypto/openssl/ossl_chacha20.c (revision 1c09320d5833fef8a4b6cc0091883fd47ea1eb1b)
192aecd1eSJohn Baldwin /*-
292aecd1eSJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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>
4078991a93SJohn Baldwin #include <crypto/openssl/ossl_poly1305.h>
4192aecd1eSJohn Baldwin 
4292aecd1eSJohn Baldwin int
4392aecd1eSJohn Baldwin ossl_chacha20(struct cryptop *crp, const struct crypto_session_params *csp)
4492aecd1eSJohn Baldwin {
4592aecd1eSJohn Baldwin 	_Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4];
4692aecd1eSJohn Baldwin 	unsigned int counter[CHACHA_CTR_SIZE / 4];
4792aecd1eSJohn Baldwin 	unsigned char block[CHACHA_BLK_SIZE];
4892aecd1eSJohn Baldwin 	struct crypto_buffer_cursor cc_in, cc_out;
4992aecd1eSJohn Baldwin 	const unsigned char *in, *inseg, *cipher_key;
5092aecd1eSJohn Baldwin 	unsigned char *out, *outseg;
5192aecd1eSJohn Baldwin 	size_t resid, todo, inlen, outlen;
5292aecd1eSJohn Baldwin 	uint32_t next_counter;
5392aecd1eSJohn Baldwin 	u_int i;
5492aecd1eSJohn Baldwin 
5592aecd1eSJohn Baldwin 	if (crp->crp_cipher_key != NULL)
5692aecd1eSJohn Baldwin 		cipher_key = crp->crp_cipher_key;
5792aecd1eSJohn Baldwin 	else
5892aecd1eSJohn Baldwin 		cipher_key = csp->csp_cipher_key;
5992aecd1eSJohn Baldwin 	for (i = 0; i < nitems(key); i++)
6092aecd1eSJohn Baldwin 		key[i] = CHACHA_U8TOU32(cipher_key + i * 4);
6192aecd1eSJohn Baldwin 	crypto_read_iv(crp, counter);
6292aecd1eSJohn Baldwin 	for (i = 0; i < nitems(counter); i++)
6392aecd1eSJohn Baldwin 		counter[i] = le32toh(counter[i]);
6492aecd1eSJohn Baldwin 
6592aecd1eSJohn Baldwin 	resid = crp->crp_payload_length;
6692aecd1eSJohn Baldwin 	crypto_cursor_init(&cc_in, &crp->crp_buf);
6792aecd1eSJohn Baldwin 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
68*1c09320dSJohn Baldwin 	inseg = crypto_cursor_segment(&cc_in, &inlen);
6992aecd1eSJohn Baldwin 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
7092aecd1eSJohn Baldwin 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
7192aecd1eSJohn Baldwin 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
7292aecd1eSJohn Baldwin 	} else
7392aecd1eSJohn Baldwin 		cc_out = cc_in;
74*1c09320dSJohn Baldwin 	outseg = crypto_cursor_segment(&cc_out, &outlen);
7592aecd1eSJohn Baldwin 	while (resid >= CHACHA_BLK_SIZE) {
7692aecd1eSJohn Baldwin 		if (inlen < CHACHA_BLK_SIZE) {
7792aecd1eSJohn Baldwin 			crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block);
7892aecd1eSJohn Baldwin 			in = block;
7992aecd1eSJohn Baldwin 			inlen = CHACHA_BLK_SIZE;
8092aecd1eSJohn Baldwin 		} else
8192aecd1eSJohn Baldwin 			in = inseg;
8292aecd1eSJohn Baldwin 		if (outlen < CHACHA_BLK_SIZE) {
8392aecd1eSJohn Baldwin 			out = block;
8492aecd1eSJohn Baldwin 			outlen = CHACHA_BLK_SIZE;
8592aecd1eSJohn Baldwin 		} else
8692aecd1eSJohn Baldwin 			out = outseg;
8792aecd1eSJohn Baldwin 
8892aecd1eSJohn Baldwin 		/* Figure out how many blocks we can encrypt/decrypt at once. */
89d2e076c3SJohn Baldwin 		todo = rounddown(MIN(resid, MIN(inlen, outlen)),
90d2e076c3SJohn Baldwin 		    CHACHA_BLK_SIZE);
9192aecd1eSJohn Baldwin 
9292aecd1eSJohn Baldwin #ifdef __LP64__
9392aecd1eSJohn Baldwin 		/* ChaCha20_ctr32() assumes length is <= 4GB. */
9492aecd1eSJohn Baldwin 		todo = (uint32_t)todo;
9592aecd1eSJohn Baldwin #endif
9692aecd1eSJohn Baldwin 
9792aecd1eSJohn Baldwin 		/* Truncate if the 32-bit counter would roll over. */
9892aecd1eSJohn Baldwin 		next_counter = counter[0] + todo / CHACHA_BLK_SIZE;
9992aecd1eSJohn Baldwin 		if (next_counter < counter[0]) {
10092aecd1eSJohn Baldwin 			todo -= next_counter * CHACHA_BLK_SIZE;
10192aecd1eSJohn Baldwin 			next_counter = 0;
10292aecd1eSJohn Baldwin 		}
10392aecd1eSJohn Baldwin 
10492aecd1eSJohn Baldwin 		ChaCha20_ctr32(out, in, todo, key, counter);
10592aecd1eSJohn Baldwin 
10692aecd1eSJohn Baldwin 		counter[0] = next_counter;
10792aecd1eSJohn Baldwin 		if (counter[0] == 0)
10892aecd1eSJohn Baldwin 			counter[1]++;
10992aecd1eSJohn Baldwin 
11092aecd1eSJohn Baldwin 		if (out == block) {
11192aecd1eSJohn Baldwin 			crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block);
112*1c09320dSJohn Baldwin 			outseg = crypto_cursor_segment(&cc_out, &outlen);
11392aecd1eSJohn Baldwin 		} else {
11492aecd1eSJohn Baldwin 			crypto_cursor_advance(&cc_out, todo);
11592aecd1eSJohn Baldwin 			outseg += todo;
11692aecd1eSJohn Baldwin 			outlen -= todo;
11792aecd1eSJohn Baldwin 		}
11892aecd1eSJohn Baldwin 		if (in == block) {
119*1c09320dSJohn Baldwin 			inseg = crypto_cursor_segment(&cc_in, &inlen);
12092aecd1eSJohn Baldwin 		} else {
12192aecd1eSJohn Baldwin 			crypto_cursor_advance(&cc_in, todo);
12292aecd1eSJohn Baldwin 			inseg += todo;
12392aecd1eSJohn Baldwin 			inlen -= todo;
12492aecd1eSJohn Baldwin 		}
12592aecd1eSJohn Baldwin 		resid -= todo;
12692aecd1eSJohn Baldwin 	}
12792aecd1eSJohn Baldwin 
12892aecd1eSJohn Baldwin 	if (resid > 0) {
12992aecd1eSJohn Baldwin 		memset(block, 0, sizeof(block));
13092aecd1eSJohn Baldwin 		crypto_cursor_copydata(&cc_in, resid, block);
13192aecd1eSJohn Baldwin 		ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter);
13292aecd1eSJohn Baldwin 		crypto_cursor_copyback(&cc_out, resid, block);
13392aecd1eSJohn Baldwin 	}
13492aecd1eSJohn Baldwin 
13592aecd1eSJohn Baldwin 	explicit_bzero(block, sizeof(block));
13692aecd1eSJohn Baldwin 	explicit_bzero(counter, sizeof(counter));
13792aecd1eSJohn Baldwin 	explicit_bzero(key, sizeof(key));
13892aecd1eSJohn Baldwin 	return (0);
13992aecd1eSJohn Baldwin }
14078991a93SJohn Baldwin 
14178991a93SJohn Baldwin int
14278991a93SJohn Baldwin ossl_chacha20_poly1305_encrypt(struct cryptop *crp,
14378991a93SJohn Baldwin     const struct crypto_session_params *csp)
14478991a93SJohn Baldwin {
14578991a93SJohn Baldwin 	_Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4];
14678991a93SJohn Baldwin 	unsigned int counter[CHACHA_CTR_SIZE / 4];
14778991a93SJohn Baldwin 	_Alignas(8) unsigned char block[CHACHA_BLK_SIZE];
14878991a93SJohn Baldwin 	unsigned char tag[POLY1305_HASH_LEN];
14978991a93SJohn Baldwin 	POLY1305 auth_ctx;
15078991a93SJohn Baldwin 	struct crypto_buffer_cursor cc_in, cc_out;
15178991a93SJohn Baldwin 	const unsigned char *in, *inseg, *cipher_key;
15278991a93SJohn Baldwin 	unsigned char *out, *outseg;
15378991a93SJohn Baldwin 	size_t resid, todo, inlen, outlen;
15478991a93SJohn Baldwin 	uint32_t next_counter;
15578991a93SJohn Baldwin 	u_int i;
15678991a93SJohn Baldwin 
15778991a93SJohn Baldwin 	if (crp->crp_cipher_key != NULL)
15878991a93SJohn Baldwin 		cipher_key = crp->crp_cipher_key;
15978991a93SJohn Baldwin 	else
16078991a93SJohn Baldwin 		cipher_key = csp->csp_cipher_key;
16178991a93SJohn Baldwin 	for (i = 0; i < nitems(key); i++)
16278991a93SJohn Baldwin 		key[i] = CHACHA_U8TOU32(cipher_key + i * 4);
16378991a93SJohn Baldwin 
16478991a93SJohn Baldwin 	crypto_read_iv(crp, counter + 1);
16578991a93SJohn Baldwin 	for (i = 1; i < nitems(counter); i++)
16678991a93SJohn Baldwin 		counter[i] = le32toh(counter[i]);
16778991a93SJohn Baldwin 
16878991a93SJohn Baldwin 	/* Block 0 is used to generate the poly1305 key. */
16978991a93SJohn Baldwin 	counter[0] = 0;
17078991a93SJohn Baldwin 
17178991a93SJohn Baldwin 	memset(block, 0, sizeof(block));
17278991a93SJohn Baldwin 	ChaCha20_ctr32(block, block, sizeof(block), key, counter);
17378991a93SJohn Baldwin 	Poly1305_Init(&auth_ctx, block);
17478991a93SJohn Baldwin 
17578991a93SJohn Baldwin 	/* MAC the AAD. */
17678991a93SJohn Baldwin 	if (crp->crp_aad != NULL)
17778991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, crp->crp_aad, crp->crp_aad_length);
17878991a93SJohn Baldwin 	else
17978991a93SJohn Baldwin 		crypto_apply(crp, crp->crp_aad_start, crp->crp_aad_length,
18078991a93SJohn Baldwin 		    ossl_poly1305_update, &auth_ctx);
18178991a93SJohn Baldwin 	if (crp->crp_aad_length % 16 != 0) {
18278991a93SJohn Baldwin 		/* padding1 */
18378991a93SJohn Baldwin 		memset(block, 0, 16);
18478991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, block,
18578991a93SJohn Baldwin 		    16 - crp->crp_aad_length % 16);
18678991a93SJohn Baldwin 	}
18778991a93SJohn Baldwin 
18878991a93SJohn Baldwin 	/* Encryption starts with block 1. */
18978991a93SJohn Baldwin 	counter[0] = 1;
19078991a93SJohn Baldwin 
19178991a93SJohn Baldwin 	/* Do encryption with MAC */
19278991a93SJohn Baldwin 	resid = crp->crp_payload_length;
19378991a93SJohn Baldwin 	crypto_cursor_init(&cc_in, &crp->crp_buf);
19478991a93SJohn Baldwin 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
195*1c09320dSJohn Baldwin 	inseg = crypto_cursor_segment(&cc_in, &inlen);
19678991a93SJohn Baldwin 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
19778991a93SJohn Baldwin 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
19878991a93SJohn Baldwin 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
19978991a93SJohn Baldwin 	} else
20078991a93SJohn Baldwin 		cc_out = cc_in;
201*1c09320dSJohn Baldwin 	outseg = crypto_cursor_segment(&cc_out, &outlen);
20278991a93SJohn Baldwin 	while (resid >= CHACHA_BLK_SIZE) {
20378991a93SJohn Baldwin 		if (inlen < CHACHA_BLK_SIZE) {
20478991a93SJohn Baldwin 			crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block);
20578991a93SJohn Baldwin 			in = block;
20678991a93SJohn Baldwin 			inlen = CHACHA_BLK_SIZE;
20778991a93SJohn Baldwin 		} else
20878991a93SJohn Baldwin 			in = inseg;
20978991a93SJohn Baldwin 		if (outlen < CHACHA_BLK_SIZE) {
21078991a93SJohn Baldwin 			out = block;
21178991a93SJohn Baldwin 			outlen = CHACHA_BLK_SIZE;
21278991a93SJohn Baldwin 		} else
21378991a93SJohn Baldwin 			out = outseg;
21478991a93SJohn Baldwin 
21578991a93SJohn Baldwin 		/* Figure out how many blocks we can encrypt/decrypt at once. */
216d2e076c3SJohn Baldwin 		todo = rounddown(MIN(resid, MIN(inlen, outlen)),
217d2e076c3SJohn Baldwin 		    CHACHA_BLK_SIZE);
21878991a93SJohn Baldwin 
21978991a93SJohn Baldwin #ifdef __LP64__
22078991a93SJohn Baldwin 		/* ChaCha20_ctr32() assumes length is <= 4GB. */
22178991a93SJohn Baldwin 		todo = (uint32_t)todo;
22278991a93SJohn Baldwin #endif
22378991a93SJohn Baldwin 
22478991a93SJohn Baldwin 		/* Truncate if the 32-bit counter would roll over. */
22578991a93SJohn Baldwin 		next_counter = counter[0] + todo / CHACHA_BLK_SIZE;
22678991a93SJohn Baldwin 		if (next_counter < counter[0]) {
22778991a93SJohn Baldwin 			todo -= next_counter * CHACHA_BLK_SIZE;
22878991a93SJohn Baldwin 			next_counter = 0;
22978991a93SJohn Baldwin 		}
23078991a93SJohn Baldwin 
23178991a93SJohn Baldwin 		ChaCha20_ctr32(out, in, todo, key, counter);
23278991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, out, todo);
23378991a93SJohn Baldwin 
23478991a93SJohn Baldwin 		counter[0] = next_counter;
23578991a93SJohn Baldwin 		if (counter[0] == 0)
23678991a93SJohn Baldwin 			counter[1]++;
23778991a93SJohn Baldwin 
23878991a93SJohn Baldwin 		if (out == block) {
23978991a93SJohn Baldwin 			crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block);
240*1c09320dSJohn Baldwin 			outseg = crypto_cursor_segment(&cc_out, &outlen);
24178991a93SJohn Baldwin 		} else {
24278991a93SJohn Baldwin 			crypto_cursor_advance(&cc_out, todo);
24378991a93SJohn Baldwin 			outseg += todo;
24478991a93SJohn Baldwin 			outlen -= todo;
24578991a93SJohn Baldwin 		}
24678991a93SJohn Baldwin 		if (in == block) {
247*1c09320dSJohn Baldwin 			inseg = crypto_cursor_segment(&cc_in, &inlen);
24878991a93SJohn Baldwin 		} else {
24978991a93SJohn Baldwin 			crypto_cursor_advance(&cc_in, todo);
25078991a93SJohn Baldwin 			inseg += todo;
25178991a93SJohn Baldwin 			inlen -= todo;
25278991a93SJohn Baldwin 		}
25378991a93SJohn Baldwin 		resid -= todo;
25478991a93SJohn Baldwin 	}
25578991a93SJohn Baldwin 
25678991a93SJohn Baldwin 	if (resid > 0) {
25778991a93SJohn Baldwin 		memset(block, 0, sizeof(block));
25878991a93SJohn Baldwin 		crypto_cursor_copydata(&cc_in, resid, block);
25978991a93SJohn Baldwin 		ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter);
26078991a93SJohn Baldwin 		crypto_cursor_copyback(&cc_out, resid, block);
26178991a93SJohn Baldwin 
26278991a93SJohn Baldwin 		/* padding2 */
26378991a93SJohn Baldwin 		todo = roundup2(resid, 16);
26478991a93SJohn Baldwin 		memset(block + resid, 0, todo - resid);
26578991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, block, todo);
26678991a93SJohn Baldwin 	}
26778991a93SJohn Baldwin 
26878991a93SJohn Baldwin 	/* lengths */
26978991a93SJohn Baldwin 	le64enc(block, crp->crp_aad_length);
27078991a93SJohn Baldwin 	le64enc(block + 8, crp->crp_payload_length);
27178991a93SJohn Baldwin 	Poly1305_Update(&auth_ctx, block, sizeof(uint64_t) * 2);
27278991a93SJohn Baldwin 
27378991a93SJohn Baldwin 	Poly1305_Final(&auth_ctx, tag);
27478991a93SJohn Baldwin 	crypto_copyback(crp, crp->crp_digest_start, csp->csp_auth_mlen == 0 ?
27578991a93SJohn Baldwin 	    POLY1305_HASH_LEN : csp->csp_auth_mlen, tag);
27678991a93SJohn Baldwin 
27778991a93SJohn Baldwin 	explicit_bzero(&auth_ctx, sizeof(auth_ctx));
27878991a93SJohn Baldwin 	explicit_bzero(tag, sizeof(tag));
27978991a93SJohn Baldwin 	explicit_bzero(block, sizeof(block));
28078991a93SJohn Baldwin 	explicit_bzero(counter, sizeof(counter));
28178991a93SJohn Baldwin 	explicit_bzero(key, sizeof(key));
28278991a93SJohn Baldwin 	return (0);
28378991a93SJohn Baldwin }
28478991a93SJohn Baldwin 
28578991a93SJohn Baldwin 
28678991a93SJohn Baldwin int
28778991a93SJohn Baldwin ossl_chacha20_poly1305_decrypt(struct cryptop *crp,
28878991a93SJohn Baldwin     const struct crypto_session_params *csp)
28978991a93SJohn Baldwin {
29078991a93SJohn Baldwin 	_Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4];
29178991a93SJohn Baldwin 	unsigned int counter[CHACHA_CTR_SIZE / 4];
29278991a93SJohn Baldwin 	_Alignas(8) unsigned char block[CHACHA_BLK_SIZE];
29378991a93SJohn Baldwin 	unsigned char tag[POLY1305_HASH_LEN], tag2[POLY1305_HASH_LEN];
29478991a93SJohn Baldwin 	struct poly1305_context auth_ctx;
29578991a93SJohn Baldwin 	struct crypto_buffer_cursor cc_in, cc_out;
29678991a93SJohn Baldwin 	const unsigned char *in, *inseg, *cipher_key;
29778991a93SJohn Baldwin 	unsigned char *out, *outseg;
29878991a93SJohn Baldwin 	size_t resid, todo, inlen, outlen;
29978991a93SJohn Baldwin 	uint32_t next_counter;
30078991a93SJohn Baldwin 	int error;
30178991a93SJohn Baldwin 	u_int i, mlen;
30278991a93SJohn Baldwin 
30378991a93SJohn Baldwin 	if (crp->crp_cipher_key != NULL)
30478991a93SJohn Baldwin 		cipher_key = crp->crp_cipher_key;
30578991a93SJohn Baldwin 	else
30678991a93SJohn Baldwin 		cipher_key = csp->csp_cipher_key;
30778991a93SJohn Baldwin 	for (i = 0; i < nitems(key); i++)
30878991a93SJohn Baldwin 		key[i] = CHACHA_U8TOU32(cipher_key + i * 4);
30978991a93SJohn Baldwin 
31078991a93SJohn Baldwin 	crypto_read_iv(crp, counter + 1);
31178991a93SJohn Baldwin 	for (i = 1; i < nitems(counter); i++)
31278991a93SJohn Baldwin 		counter[i] = le32toh(counter[i]);
31378991a93SJohn Baldwin 
31478991a93SJohn Baldwin 	/* Block 0 is used to generate the poly1305 key. */
31578991a93SJohn Baldwin 	counter[0] = 0;
31678991a93SJohn Baldwin 
31778991a93SJohn Baldwin 	memset(block, 0, sizeof(block));
31878991a93SJohn Baldwin 	ChaCha20_ctr32(block, block, sizeof(block), key, counter);
31978991a93SJohn Baldwin 	Poly1305_Init(&auth_ctx, block);
32078991a93SJohn Baldwin 
32178991a93SJohn Baldwin 	/* MAC the AAD. */
32278991a93SJohn Baldwin 	if (crp->crp_aad != NULL)
32378991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, crp->crp_aad, crp->crp_aad_length);
32478991a93SJohn Baldwin 	else
32578991a93SJohn Baldwin 		crypto_apply(crp, crp->crp_aad_start, crp->crp_aad_length,
32678991a93SJohn Baldwin 		    ossl_poly1305_update, &auth_ctx);
32778991a93SJohn Baldwin 	if (crp->crp_aad_length % 16 != 0) {
32878991a93SJohn Baldwin 		/* padding1 */
32978991a93SJohn Baldwin 		memset(block, 0, 16);
33078991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, block,
33178991a93SJohn Baldwin 		    16 - crp->crp_aad_length % 16);
33278991a93SJohn Baldwin 	}
33378991a93SJohn Baldwin 
33478991a93SJohn Baldwin 	/* Mac the ciphertext. */
33578991a93SJohn Baldwin 	crypto_apply(crp, crp->crp_payload_start, crp->crp_payload_length,
33678991a93SJohn Baldwin 	    ossl_poly1305_update, &auth_ctx);
33778991a93SJohn Baldwin 	if (crp->crp_payload_length % 16 != 0) {
33878991a93SJohn Baldwin 		/* padding2 */
33978991a93SJohn Baldwin 		memset(block, 0, 16);
34078991a93SJohn Baldwin 		Poly1305_Update(&auth_ctx, block,
34178991a93SJohn Baldwin 		    16 - crp->crp_payload_length % 16);
34278991a93SJohn Baldwin 	}
34378991a93SJohn Baldwin 
34478991a93SJohn Baldwin 	/* lengths */
34578991a93SJohn Baldwin 	le64enc(block, crp->crp_aad_length);
34678991a93SJohn Baldwin 	le64enc(block + 8, crp->crp_payload_length);
34778991a93SJohn Baldwin 	Poly1305_Update(&auth_ctx, block, sizeof(uint64_t) * 2);
34878991a93SJohn Baldwin 
34978991a93SJohn Baldwin 	Poly1305_Final(&auth_ctx, tag);
35078991a93SJohn Baldwin 	mlen = csp->csp_auth_mlen == 0 ? POLY1305_HASH_LEN : csp->csp_auth_mlen;
35178991a93SJohn Baldwin 	crypto_copydata(crp, crp->crp_digest_start, mlen, tag2);
35278991a93SJohn Baldwin 	if (timingsafe_bcmp(tag, tag2, mlen) != 0) {
35378991a93SJohn Baldwin 		error = EBADMSG;
35478991a93SJohn Baldwin 		goto out;
35578991a93SJohn Baldwin 	}
35678991a93SJohn Baldwin 
35778991a93SJohn Baldwin 	/* Decryption starts with block 1. */
35878991a93SJohn Baldwin 	counter[0] = 1;
35978991a93SJohn Baldwin 
36078991a93SJohn Baldwin 	resid = crp->crp_payload_length;
36178991a93SJohn Baldwin 	crypto_cursor_init(&cc_in, &crp->crp_buf);
36278991a93SJohn Baldwin 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
363*1c09320dSJohn Baldwin 	inseg = crypto_cursor_segment(&cc_in, &inlen);
36478991a93SJohn Baldwin 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
36578991a93SJohn Baldwin 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
36678991a93SJohn Baldwin 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
36778991a93SJohn Baldwin 	} else
36878991a93SJohn Baldwin 		cc_out = cc_in;
369*1c09320dSJohn Baldwin 	outseg = crypto_cursor_segment(&cc_out, &outlen);
37078991a93SJohn Baldwin 	while (resid >= CHACHA_BLK_SIZE) {
37178991a93SJohn Baldwin 		if (inlen < CHACHA_BLK_SIZE) {
37278991a93SJohn Baldwin 			crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block);
37378991a93SJohn Baldwin 			in = block;
37478991a93SJohn Baldwin 			inlen = CHACHA_BLK_SIZE;
37578991a93SJohn Baldwin 		} else
37678991a93SJohn Baldwin 			in = inseg;
37778991a93SJohn Baldwin 		if (outlen < CHACHA_BLK_SIZE) {
37878991a93SJohn Baldwin 			out = block;
37978991a93SJohn Baldwin 			outlen = CHACHA_BLK_SIZE;
38078991a93SJohn Baldwin 		} else
38178991a93SJohn Baldwin 			out = outseg;
38278991a93SJohn Baldwin 
38378991a93SJohn Baldwin 		/* Figure out how many blocks we can encrypt/decrypt at once. */
384d2e076c3SJohn Baldwin 		todo = rounddown(MIN(resid, MIN(inlen, outlen)),
385d2e076c3SJohn Baldwin 		    CHACHA_BLK_SIZE);
38678991a93SJohn Baldwin 
38778991a93SJohn Baldwin #ifdef __LP64__
38878991a93SJohn Baldwin 		/* ChaCha20_ctr32() assumes length is <= 4GB. */
38978991a93SJohn Baldwin 		todo = (uint32_t)todo;
39078991a93SJohn Baldwin #endif
39178991a93SJohn Baldwin 
39278991a93SJohn Baldwin 		/* Truncate if the 32-bit counter would roll over. */
39378991a93SJohn Baldwin 		next_counter = counter[0] + todo / CHACHA_BLK_SIZE;
39478991a93SJohn Baldwin 		if (next_counter < counter[0]) {
39578991a93SJohn Baldwin 			todo -= next_counter * CHACHA_BLK_SIZE;
39678991a93SJohn Baldwin 			next_counter = 0;
39778991a93SJohn Baldwin 		}
39878991a93SJohn Baldwin 
39978991a93SJohn Baldwin 		ChaCha20_ctr32(out, in, todo, key, counter);
40078991a93SJohn Baldwin 
40178991a93SJohn Baldwin 		counter[0] = next_counter;
40278991a93SJohn Baldwin 		if (counter[0] == 0)
40378991a93SJohn Baldwin 			counter[1]++;
40478991a93SJohn Baldwin 
40578991a93SJohn Baldwin 		if (out == block) {
40678991a93SJohn Baldwin 			crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block);
407*1c09320dSJohn Baldwin 			outseg = crypto_cursor_segment(&cc_out, &outlen);
40878991a93SJohn Baldwin 		} else {
40978991a93SJohn Baldwin 			crypto_cursor_advance(&cc_out, todo);
41078991a93SJohn Baldwin 			outseg += todo;
41178991a93SJohn Baldwin 			outlen -= todo;
41278991a93SJohn Baldwin 		}
41378991a93SJohn Baldwin 		if (in == block) {
414*1c09320dSJohn Baldwin 			inseg = crypto_cursor_segment(&cc_in, &inlen);
41578991a93SJohn Baldwin 		} else {
41678991a93SJohn Baldwin 			crypto_cursor_advance(&cc_in, todo);
41778991a93SJohn Baldwin 			inseg += todo;
41878991a93SJohn Baldwin 			inlen -= todo;
41978991a93SJohn Baldwin 		}
42078991a93SJohn Baldwin 		resid -= todo;
42178991a93SJohn Baldwin 	}
42278991a93SJohn Baldwin 
42378991a93SJohn Baldwin 	if (resid > 0) {
42478991a93SJohn Baldwin 		memset(block, 0, sizeof(block));
42578991a93SJohn Baldwin 		crypto_cursor_copydata(&cc_in, resid, block);
42678991a93SJohn Baldwin 		ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter);
42778991a93SJohn Baldwin 		crypto_cursor_copyback(&cc_out, resid, block);
42878991a93SJohn Baldwin 	}
42978991a93SJohn Baldwin 
43078991a93SJohn Baldwin 	error = 0;
43178991a93SJohn Baldwin out:
43278991a93SJohn Baldwin 	explicit_bzero(&auth_ctx, sizeof(auth_ctx));
43378991a93SJohn Baldwin 	explicit_bzero(tag, sizeof(tag));
43478991a93SJohn Baldwin 	explicit_bzero(block, sizeof(block));
43578991a93SJohn Baldwin 	explicit_bzero(counter, sizeof(counter));
43678991a93SJohn Baldwin 	explicit_bzero(key, sizeof(key));
43778991a93SJohn Baldwin 	return (error);
43878991a93SJohn Baldwin }
439