16f63b8faSAaron LI /*
26f63b8faSAaron LI * Copyright (c) 2015 Mike Belopuhov
3117b0b40SAaron LI * Copyright (c) 2023-2024 Aaron LI <aly@aaronly.me>
46f63b8faSAaron LI *
56f63b8faSAaron LI * Permission to use, copy, modify, and distribute this software for any
66f63b8faSAaron LI * purpose with or without fee is hereby granted, provided that the above
76f63b8faSAaron LI * copyright notice and this permission notice appear in all copies.
86f63b8faSAaron LI *
96f63b8faSAaron LI * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
106f63b8faSAaron LI * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
116f63b8faSAaron LI * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
126f63b8faSAaron LI * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
136f63b8faSAaron LI * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
146f63b8faSAaron LI * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
156f63b8faSAaron LI * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
166f63b8faSAaron LI */
176f63b8faSAaron LI
186f63b8faSAaron LI #include <sys/param.h>
196f63b8faSAaron LI #include <sys/systm.h>
206f63b8faSAaron LI #include <sys/endian.h>
2137273911SAaron LI #include <sys/mbuf.h>
226f63b8faSAaron LI
236f63b8faSAaron LI #include <crypto/chachapoly.h>
246f63b8faSAaron LI #include <crypto/chacha20/chacha.h>
256f63b8faSAaron LI #include <crypto/poly1305/poly1305.h>
266f63b8faSAaron LI
276f63b8faSAaron LI
2859e2d684SAaron LI struct chacha20poly1305_ctx {
2959e2d684SAaron LI struct chacha_ctx chacha;
3059e2d684SAaron LI poly1305_state poly;
3159e2d684SAaron LI uint8_t tag[CHACHA20POLY1305_AUTHTAG_SIZE];
3259e2d684SAaron LI size_t ad_len;
3359e2d684SAaron LI size_t data_len;
3459e2d684SAaron LI int flags;
3559e2d684SAaron LI #define F_MODE_ENCRYPTION 0x001 /* encryption operation */
3659e2d684SAaron LI #define F_INITIALIZED 0x002 /* context initialized */
3759e2d684SAaron LI #define F_AD_DONE 0x004 /* no more additional data */
3859e2d684SAaron LI };
3959e2d684SAaron LI
406f63b8faSAaron LI #define PADDING_SIZE 16
416f63b8faSAaron LI #define PADDING_LEN(len) \
426f63b8faSAaron LI ((PADDING_SIZE - ((len) & (PADDING_SIZE - 1))) & (PADDING_SIZE - 1))
436f63b8faSAaron LI
446f63b8faSAaron LI static const uint8_t pad0[PADDING_SIZE] = { 0 };
456f63b8faSAaron LI
466f63b8faSAaron LI
4759e2d684SAaron LI static void
_chacha20poly1305_init(struct chacha20poly1305_ctx * ctx,bool enc_mode,const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],const uint8_t key[CHACHA20POLY1305_KEY_SIZE])4859e2d684SAaron LI _chacha20poly1305_init(struct chacha20poly1305_ctx *ctx, bool enc_mode,
496f63b8faSAaron LI const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],
506f63b8faSAaron LI const uint8_t key[CHACHA20POLY1305_KEY_SIZE])
516f63b8faSAaron LI {
526f63b8faSAaron LI uint8_t poly_key[CHACHA20POLY1305_KEY_SIZE];
536f63b8faSAaron LI uint8_t nonce64[CHACHA_NONCELEN], counter64[CHACHA_CTRLEN];
546f63b8faSAaron LI
5559e2d684SAaron LI bzero(ctx, sizeof(*ctx));
566f63b8faSAaron LI bzero(poly_key, sizeof(poly_key));
576f63b8faSAaron LI bzero(nonce64, sizeof(nonce64));
586f63b8faSAaron LI bzero(counter64, sizeof(counter64));
596f63b8faSAaron LI
606f63b8faSAaron LI /*
616f63b8faSAaron LI * The original ChaCha uses a 64-bit nonce and a 64-bit counter,
6259e2d684SAaron LI * but the IETF version is modified to use a 96-bit nonce and
636f63b8faSAaron LI * a 32-bit counter. (RFC 8439)
646f63b8faSAaron LI */
656f63b8faSAaron LI memcpy(counter64 + 4, nonce, 4);
666f63b8faSAaron LI memcpy(nonce64, nonce + 4, 8);
676f63b8faSAaron LI
686f63b8faSAaron LI /* Generate the Poly1305 one-time key. */
6959e2d684SAaron LI chacha_keysetup(&ctx->chacha, key, CHACHA20POLY1305_KEY_SIZE * 8);
7059e2d684SAaron LI chacha_ivsetup(&ctx->chacha, nonce64, counter64);
7159e2d684SAaron LI chacha_encrypt_bytes(&ctx->chacha, poly_key, poly_key,
7259e2d684SAaron LI sizeof(poly_key));
736f63b8faSAaron LI
7459e2d684SAaron LI /* Initialize the authenticator. */
7559e2d684SAaron LI poly1305_init(&ctx->poly, poly_key);
7659e2d684SAaron LI
7759e2d684SAaron LI ctx->flags |= (enc_mode ? F_MODE_ENCRYPTION : 0);
7859e2d684SAaron LI ctx->flags |= F_INITIALIZED;
7959e2d684SAaron LI }
8059e2d684SAaron LI
8159e2d684SAaron LI /*
82117b0b40SAaron LI * Authenticate the additional data (AD).
8359e2d684SAaron LI *
84117b0b40SAaron LI * This function may be called zero, one or more times to pass successive
85117b0b40SAaron LI * fragments of the AD, but must be done before processing any cipher data,
86117b0b40SAaron LI * i.e., calling _chacha20poly1305_update().
87117b0b40SAaron LI */
88117b0b40SAaron LI static void
_chacha20poly1305_update_ad(struct chacha20poly1305_ctx * ctx,const uint8_t * ad,size_t ad_len)89117b0b40SAaron LI _chacha20poly1305_update_ad(struct chacha20poly1305_ctx *ctx,
90117b0b40SAaron LI const uint8_t *ad, size_t ad_len)
91117b0b40SAaron LI {
92117b0b40SAaron LI KKASSERT((ctx->flags & F_INITIALIZED) != 0);
93117b0b40SAaron LI KKASSERT((ctx->flags & F_AD_DONE) == 0);
94117b0b40SAaron LI
95117b0b40SAaron LI if (ad_len == 0 || ad == NULL)
96117b0b40SAaron LI return;
97117b0b40SAaron LI
98117b0b40SAaron LI poly1305_update(&ctx->poly, ad, ad_len);
99117b0b40SAaron LI ctx->ad_len += ad_len;
100117b0b40SAaron LI }
101117b0b40SAaron LI
102117b0b40SAaron LI /*
103117b0b40SAaron LI * Encrypt/decrypt the cipher data (i.e., plaintext or ciphertext).
10459e2d684SAaron LI *
10559e2d684SAaron LI * NOTE: The cipher data must be complete blocks. This requirement is
10659e2d684SAaron LI * placed to help easily implement the in-place encryption/
10759e2d684SAaron LI * decryption for data in non-contiguous buffers (e.g., mbuf chain).
10859e2d684SAaron LI */
10959e2d684SAaron LI static void
_chacha20poly1305_update(struct chacha20poly1305_ctx * ctx,uint8_t * out,const uint8_t * in,size_t in_len)11059e2d684SAaron LI _chacha20poly1305_update(struct chacha20poly1305_ctx *ctx,
11159e2d684SAaron LI uint8_t *out, const uint8_t *in, size_t in_len)
11259e2d684SAaron LI {
11359e2d684SAaron LI KKASSERT((ctx->flags & F_INITIALIZED) != 0);
114117b0b40SAaron LI KKASSERT(in_len == 0 || (in_len > 0 && out != NULL));
115117b0b40SAaron LI KKASSERT(in_len % CHACHA_BLOCKLEN == 0); /* must be complete blocks */
11659e2d684SAaron LI
11759e2d684SAaron LI if ((ctx->flags & F_AD_DONE) == 0) {
11859e2d684SAaron LI poly1305_update(&ctx->poly, pad0, PADDING_LEN(ctx->ad_len));
11959e2d684SAaron LI ctx->flags |= F_AD_DONE;
12059e2d684SAaron LI }
12159e2d684SAaron LI
122117b0b40SAaron LI if (in_len == 0 || in == NULL)
123117b0b40SAaron LI return;
124117b0b40SAaron LI
12559e2d684SAaron LI /* Swap the Poly1305/ChaCha order to support in-place operation. */
12659e2d684SAaron LI if (ctx->flags & F_MODE_ENCRYPTION) {
12759e2d684SAaron LI chacha_encrypt_bytes(&ctx->chacha, in, out, in_len);
12859e2d684SAaron LI poly1305_update(&ctx->poly, out, in_len);
12959e2d684SAaron LI } else {
13059e2d684SAaron LI poly1305_update(&ctx->poly, in, in_len);
13159e2d684SAaron LI chacha_encrypt_bytes(&ctx->chacha, in, out, in_len);
13259e2d684SAaron LI }
13359e2d684SAaron LI
13459e2d684SAaron LI ctx->data_len += in_len;
13559e2d684SAaron LI }
13659e2d684SAaron LI
13759e2d684SAaron LI /*
13859e2d684SAaron LI * Process the last cipher block, which can be empty, complete or incomplete.
13959e2d684SAaron LI *
14059e2d684SAaron LI * In the encryption mode, the tag is calculated and is available via
14159e2d684SAaron LI * 'ctx->tag'. Let the caller get the tag and append to the output, because
14259e2d684SAaron LI * the allocated tag space may not directly follow the output buffer; e.g.,
14359e2d684SAaron LI * the tag is allocated on a separate mbuf.
14459e2d684SAaron LI *
14559e2d684SAaron LI * In the decryption mode, the caller must set the expected tag in
14659e2d684SAaron LI * 'ctx->tag' before calling this function. The tag will be verified and
14759e2d684SAaron LI * a boolean is returned to indicate whether the tag matches.
14859e2d684SAaron LI */
14959e2d684SAaron LI static bool
_chacha20poly1305_final(struct chacha20poly1305_ctx * ctx,uint8_t * out,const uint8_t * in,size_t in_len)15059e2d684SAaron LI _chacha20poly1305_final(struct chacha20poly1305_ctx *ctx,
15159e2d684SAaron LI uint8_t *out, const uint8_t *in, size_t in_len)
15259e2d684SAaron LI {
15359e2d684SAaron LI uint64_t lens[2];
15459e2d684SAaron LI uint8_t tag[CHACHA20POLY1305_AUTHTAG_SIZE];
15559e2d684SAaron LI bool ret;
15659e2d684SAaron LI
15759e2d684SAaron LI KKASSERT((ctx->flags & F_INITIALIZED) != 0);
158117b0b40SAaron LI KKASSERT(in_len == 0 || (in_len > 0 && out != NULL));
15959e2d684SAaron LI KKASSERT(in_len <= CHACHA_BLOCKLEN);
16059e2d684SAaron LI
161*aebcea9cSAaron LI /* Handle the case that no _update() was called. */
16259e2d684SAaron LI if (ctx->ad_len > 0 && (ctx->flags & F_AD_DONE) == 0) {
16359e2d684SAaron LI KKASSERT(ctx->data_len == 0);
16459e2d684SAaron LI poly1305_update(&ctx->poly, pad0, PADDING_LEN(ctx->ad_len));
16559e2d684SAaron LI ctx->flags |= F_AD_DONE;
16659e2d684SAaron LI }
16759e2d684SAaron LI
168117b0b40SAaron LI if (in_len > 0) {
16959e2d684SAaron LI if (ctx->flags & F_MODE_ENCRYPTION) {
17059e2d684SAaron LI chacha_encrypt_bytes(&ctx->chacha, in, out, in_len);
17159e2d684SAaron LI poly1305_update(&ctx->poly, out, in_len);
17259e2d684SAaron LI } else {
17359e2d684SAaron LI poly1305_update(&ctx->poly, in, in_len);
17459e2d684SAaron LI chacha_encrypt_bytes(&ctx->chacha, in, out, in_len);
17559e2d684SAaron LI }
176*aebcea9cSAaron LI /*
177*aebcea9cSAaron LI * Only need to pad the last chunk, because the data chunks
178*aebcea9cSAaron LI * processed by _update() are complete blocks.
179*aebcea9cSAaron LI */
18059e2d684SAaron LI poly1305_update(&ctx->poly, pad0, PADDING_LEN(in_len));
18159e2d684SAaron LI ctx->data_len += in_len;
182117b0b40SAaron LI }
1836f63b8faSAaron LI
1846f63b8faSAaron LI /* Calculate the tag. */
18559e2d684SAaron LI lens[0] = htole64(ctx->ad_len);
18659e2d684SAaron LI lens[1] = htole64(ctx->data_len);
18759e2d684SAaron LI poly1305_update(&ctx->poly, (uint8_t *)lens, sizeof(lens));
18859e2d684SAaron LI poly1305_finish(&ctx->poly, tag);
1896f63b8faSAaron LI
19059e2d684SAaron LI if (ctx->flags & F_MODE_ENCRYPTION) {
19159e2d684SAaron LI ret = true;
19259e2d684SAaron LI explicit_bzero(ctx, sizeof(*ctx));
19359e2d684SAaron LI memcpy(ctx->tag, tag, sizeof(tag));
19459e2d684SAaron LI } else {
19559e2d684SAaron LI ret = (timingsafe_bcmp(ctx->tag, tag, sizeof(tag)) == 0);
19659e2d684SAaron LI explicit_bzero(ctx, sizeof(*ctx));
19759e2d684SAaron LI }
19859e2d684SAaron LI
19959e2d684SAaron LI return (ret);
20059e2d684SAaron LI }
20159e2d684SAaron LI
20259e2d684SAaron LI /*-------------------------------------------------------------------*/
20359e2d684SAaron LI
20459e2d684SAaron LI void
chacha20poly1305_encrypt(uint8_t * dst,const uint8_t * src,size_t src_len,const uint8_t * ad,size_t ad_len,const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],const uint8_t key[CHACHA20POLY1305_KEY_SIZE])20559e2d684SAaron LI chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len,
20659e2d684SAaron LI const uint8_t *ad, size_t ad_len,
20759e2d684SAaron LI const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],
20859e2d684SAaron LI const uint8_t key[CHACHA20POLY1305_KEY_SIZE])
20959e2d684SAaron LI {
21059e2d684SAaron LI struct chacha20poly1305_ctx ctx;
21159e2d684SAaron LI size_t len;
21259e2d684SAaron LI
21359e2d684SAaron LI _chacha20poly1305_init(&ctx, true, nonce, key);
21459e2d684SAaron LI
215117b0b40SAaron LI _chacha20poly1305_update_ad(&ctx, ad, ad_len);
21659e2d684SAaron LI
21759e2d684SAaron LI len = rounddown2(src_len, CHACHA_BLOCKLEN);
21859e2d684SAaron LI _chacha20poly1305_update(&ctx, dst, src, len);
21959e2d684SAaron LI
22059e2d684SAaron LI _chacha20poly1305_final(&ctx, dst + len, src + len, src_len - len);
22159e2d684SAaron LI memcpy(dst + src_len, ctx.tag, sizeof(ctx.tag));
2226f63b8faSAaron LI }
2236f63b8faSAaron LI
2246f63b8faSAaron LI bool
chacha20poly1305_decrypt(uint8_t * dst,const uint8_t * src,size_t src_len,const uint8_t * ad,size_t ad_len,const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],const uint8_t key[CHACHA20POLY1305_KEY_SIZE])2256f63b8faSAaron LI chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len,
2266f63b8faSAaron LI const uint8_t *ad, size_t ad_len,
2276f63b8faSAaron LI const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],
2286f63b8faSAaron LI const uint8_t key[CHACHA20POLY1305_KEY_SIZE])
2296f63b8faSAaron LI {
23059e2d684SAaron LI struct chacha20poly1305_ctx ctx;
23159e2d684SAaron LI size_t data_len, len;
2326f63b8faSAaron LI
23359e2d684SAaron LI if (src_len < sizeof(ctx.tag))
2346f63b8faSAaron LI return (false);
2356f63b8faSAaron LI
23659e2d684SAaron LI _chacha20poly1305_init(&ctx, false, nonce, key);
2376f63b8faSAaron LI
238117b0b40SAaron LI _chacha20poly1305_update_ad(&ctx, ad, ad_len);
2396f63b8faSAaron LI
24059e2d684SAaron LI data_len = src_len - sizeof(ctx.tag);
24159e2d684SAaron LI len = rounddown2(data_len, CHACHA_BLOCKLEN);
24259e2d684SAaron LI _chacha20poly1305_update(&ctx, dst, src, len);
2436f63b8faSAaron LI
24459e2d684SAaron LI memcpy(ctx.tag, src + data_len, sizeof(ctx.tag));
24559e2d684SAaron LI return _chacha20poly1305_final(&ctx, dst + len, src + len,
24659e2d684SAaron LI data_len - len);
2476f63b8faSAaron LI }
2486f63b8faSAaron LI
24959e2d684SAaron LI /*-------------------------------------------------------------------*/
2506f63b8faSAaron LI
2516f63b8faSAaron LI /*
2526f63b8faSAaron LI * XChaCha: eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305
2536f63b8faSAaron LI * RFC draft: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha
2546f63b8faSAaron LI */
2556f63b8faSAaron LI void
xchacha20poly1305_encrypt(uint8_t * dst,const uint8_t * src,size_t src_len,const uint8_t * ad,size_t ad_len,const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE],const uint8_t key[CHACHA20POLY1305_KEY_SIZE])2566f63b8faSAaron LI xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len,
2576f63b8faSAaron LI const uint8_t *ad, size_t ad_len,
2586f63b8faSAaron LI const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE],
2596f63b8faSAaron LI const uint8_t key[CHACHA20POLY1305_KEY_SIZE])
2606f63b8faSAaron LI {
2616f63b8faSAaron LI uint8_t derived_key[CHACHA20POLY1305_KEY_SIZE];
2626f63b8faSAaron LI uint8_t derived_nonce[CHACHA20POLY1305_NONCE_SIZE];
2636f63b8faSAaron LI
2646f63b8faSAaron LI /* Derive a subkey using the first 16 bytes of the nonce. */
2656f63b8faSAaron LI hchacha20(derived_key, nonce, key);
2666f63b8faSAaron LI
2676f63b8faSAaron LI /* Prefix the remaining 8 bytes of the nonce with 4 NUL bytes. */
2686f63b8faSAaron LI bzero(derived_nonce, sizeof(derived_nonce));
2696f63b8faSAaron LI memcpy(derived_nonce + 4, nonce + 16, 8);
2706f63b8faSAaron LI
2716f63b8faSAaron LI chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len,
2726f63b8faSAaron LI derived_nonce, derived_key);
2736f63b8faSAaron LI
2746f63b8faSAaron LI explicit_bzero(derived_key, sizeof(derived_key));
2756f63b8faSAaron LI }
2766f63b8faSAaron LI
2776f63b8faSAaron LI bool
xchacha20poly1305_decrypt(uint8_t * dst,const uint8_t * src,size_t src_len,const uint8_t * ad,size_t ad_len,const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE],const uint8_t key[CHACHA20POLY1305_KEY_SIZE])2786f63b8faSAaron LI xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len,
2796f63b8faSAaron LI const uint8_t *ad, size_t ad_len,
2806f63b8faSAaron LI const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE],
2816f63b8faSAaron LI const uint8_t key[CHACHA20POLY1305_KEY_SIZE])
2826f63b8faSAaron LI {
2836f63b8faSAaron LI uint8_t derived_key[CHACHA20POLY1305_KEY_SIZE];
2846f63b8faSAaron LI uint8_t derived_nonce[CHACHA20POLY1305_NONCE_SIZE];
2856f63b8faSAaron LI bool ret;
2866f63b8faSAaron LI
2876f63b8faSAaron LI hchacha20(derived_key, nonce, key);
2886f63b8faSAaron LI
2896f63b8faSAaron LI bzero(derived_nonce, sizeof(derived_nonce));
2906f63b8faSAaron LI memcpy(derived_nonce + 4, nonce + 16, 8);
2916f63b8faSAaron LI
2926f63b8faSAaron LI ret = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len,
2936f63b8faSAaron LI derived_nonce, derived_key);
2946f63b8faSAaron LI
2956f63b8faSAaron LI explicit_bzero(derived_key, sizeof(derived_key));
2966f63b8faSAaron LI return (ret);
2976f63b8faSAaron LI }
29837273911SAaron LI
29937273911SAaron LI /*-------------------------------------------------------------------*/
30037273911SAaron LI
30137273911SAaron LI static int
_chacha20poly1305_mbuf(struct chacha20poly1305_ctx * ctx,struct mbuf * m,int len)30237273911SAaron LI _chacha20poly1305_mbuf(struct chacha20poly1305_ctx *ctx,
30337273911SAaron LI struct mbuf *m, int len)
30437273911SAaron LI {
30537273911SAaron LI uint8_t block[CHACHA_BLOCKLEN], *p;
30637273911SAaron LI int off, blen, ret;
30737273911SAaron LI
30837273911SAaron LI off = 0;
30937273911SAaron LI while (len >= (int)sizeof(block)) {
31037273911SAaron LI if (m->m_len == off) {
31137273911SAaron LI off = 0;
31237273911SAaron LI m = m->m_next;
31337273911SAaron LI /* Skip possibly empty mbufs. */
31437273911SAaron LI while (m != NULL && m->m_len == 0)
31537273911SAaron LI m = m->m_next;
31637273911SAaron LI if (m == NULL)
31737273911SAaron LI return (EINVAL); /* because len > 0 */
31837273911SAaron LI }
31937273911SAaron LI
32037273911SAaron LI if (m->m_len >= off + sizeof(block)) {
32137273911SAaron LI p = mtod(m, uint8_t *) + off;
32237273911SAaron LI blen = rounddown2(MIN(len, m->m_len - off),
32337273911SAaron LI sizeof(block));
32437273911SAaron LI _chacha20poly1305_update(ctx, p, p, blen);
32537273911SAaron LI
32637273911SAaron LI off += blen;
32737273911SAaron LI len -= blen;
32837273911SAaron LI } else {
32937273911SAaron LI /* Insufficient data at the end; do some copying. */
33037273911SAaron LI m_copydata(m, off, sizeof(block), block);
33137273911SAaron LI _chacha20poly1305_update(ctx, block, block,
33237273911SAaron LI sizeof(block));
33337273911SAaron LI m_copyback(m, off, sizeof(block), block);
33437273911SAaron LI
33537273911SAaron LI /* Advance pointer. */
33637273911SAaron LI m = m_getptr(m, off + sizeof(block), &off);
33737273911SAaron LI if (m == NULL)
33837273911SAaron LI return (EINVAL);
33937273911SAaron LI
34037273911SAaron LI len -= (int)sizeof(block);
34137273911SAaron LI }
34237273911SAaron LI }
34337273911SAaron LI
34437273911SAaron LI m_copydata(m, off, len, block); /* len may be 0 */
34537273911SAaron LI if (ctx->flags & F_MODE_ENCRYPTION) {
34637273911SAaron LI ret = _chacha20poly1305_final(ctx, block, block, len) ?
34737273911SAaron LI 0 : EBADMSG;
34837273911SAaron LI m_copyback(m, off + len, sizeof(ctx->tag), ctx->tag);
34937273911SAaron LI } else {
35037273911SAaron LI m_copydata(m, off + len, sizeof(ctx->tag), ctx->tag);
35137273911SAaron LI ret = _chacha20poly1305_final(ctx, block, block, len) ?
35237273911SAaron LI 0 : EBADMSG;
35337273911SAaron LI }
35437273911SAaron LI m_copyback(m, off, len, block);
35537273911SAaron LI
35637273911SAaron LI return (ret);
35737273911SAaron LI }
35837273911SAaron LI
35937273911SAaron LI int
chacha20poly1305_encrypt_mbuf(struct mbuf * m,const uint8_t * ad,size_t ad_len,const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],const uint8_t key[CHACHA20POLY1305_KEY_SIZE])36037273911SAaron LI chacha20poly1305_encrypt_mbuf(struct mbuf *m, const uint8_t *ad, size_t ad_len,
36137273911SAaron LI const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],
36237273911SAaron LI const uint8_t key[CHACHA20POLY1305_KEY_SIZE])
36337273911SAaron LI {
36437273911SAaron LI static const uint8_t blank_tag[CHACHA20POLY1305_AUTHTAG_SIZE] = { 0 };
36537273911SAaron LI struct chacha20poly1305_ctx ctx;
36637273911SAaron LI int len;
36737273911SAaron LI
36837273911SAaron LI M_ASSERTPKTHDR(m);
36937273911SAaron LI len = m->m_pkthdr.len;
37037273911SAaron LI
37137273911SAaron LI if (!m_append(m, sizeof(blank_tag), blank_tag))
37237273911SAaron LI return (ENOMEM);
37337273911SAaron LI
37437273911SAaron LI _chacha20poly1305_init(&ctx, true, nonce, key);
37537273911SAaron LI
376117b0b40SAaron LI _chacha20poly1305_update_ad(&ctx, ad, ad_len);
37737273911SAaron LI
37837273911SAaron LI return _chacha20poly1305_mbuf(&ctx, m, len);
37937273911SAaron LI }
38037273911SAaron LI
38137273911SAaron LI int
chacha20poly1305_decrypt_mbuf(struct mbuf * m,const uint8_t * ad,size_t ad_len,const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],const uint8_t key[CHACHA20POLY1305_KEY_SIZE])38237273911SAaron LI chacha20poly1305_decrypt_mbuf(struct mbuf *m, const uint8_t *ad, size_t ad_len,
38337273911SAaron LI const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE],
38437273911SAaron LI const uint8_t key[CHACHA20POLY1305_KEY_SIZE])
38537273911SAaron LI {
38637273911SAaron LI struct chacha20poly1305_ctx ctx;
38737273911SAaron LI int len, ret;
38837273911SAaron LI
38937273911SAaron LI M_ASSERTPKTHDR(m);
39037273911SAaron LI len = m->m_pkthdr.len - CHACHA20POLY1305_AUTHTAG_SIZE;
39137273911SAaron LI if (len < 0)
39237273911SAaron LI return (EBADMSG);
39337273911SAaron LI
39437273911SAaron LI _chacha20poly1305_init(&ctx, false, nonce, key);
39537273911SAaron LI
396117b0b40SAaron LI _chacha20poly1305_update_ad(&ctx, ad, ad_len);
39737273911SAaron LI
39837273911SAaron LI ret = _chacha20poly1305_mbuf(&ctx, m, len);
39937273911SAaron LI if (ret == 0)
40037273911SAaron LI m_adj(m, -CHACHA20POLY1305_AUTHTAG_SIZE);
40137273911SAaron LI
40237273911SAaron LI return (ret);
40337273911SAaron LI }
404