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