1fc8fc743SJohn Baldwin /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fc8fc743SJohn Baldwin *
4fc8fc743SJohn Baldwin * Copyright (c) 2020 Netflix Inc.
5fc8fc743SJohn Baldwin *
6fc8fc743SJohn Baldwin * Redistribution and use in source and binary forms, with or without
7fc8fc743SJohn Baldwin * modification, are permitted provided that the following conditions
8fc8fc743SJohn Baldwin * are met:
9fc8fc743SJohn Baldwin * 1. Redistributions of source code must retain the above copyright
10fc8fc743SJohn Baldwin * notice, this list of conditions and the following disclaimer.
11fc8fc743SJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright
12fc8fc743SJohn Baldwin * notice, this list of conditions and the following disclaimer in the
13fc8fc743SJohn Baldwin * documentation and/or other materials provided with the distribution.
14fc8fc743SJohn Baldwin *
15fc8fc743SJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16fc8fc743SJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17fc8fc743SJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18fc8fc743SJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19fc8fc743SJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20fc8fc743SJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21fc8fc743SJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22fc8fc743SJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23fc8fc743SJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24fc8fc743SJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25fc8fc743SJohn Baldwin * SUCH DAMAGE.
26fc8fc743SJohn Baldwin */
27fc8fc743SJohn Baldwin
28dd2e1352SJohn Baldwin #include <opencrypto/xform_auth.h>
29fc8fc743SJohn Baldwin #include <opencrypto/xform_enc.h>
30fc8fc743SJohn Baldwin
318f35841fSJohn Baldwin #include <sodium/crypto_core_hchacha20.h>
32dd2e1352SJohn Baldwin #include <sodium/crypto_onetimeauth_poly1305.h>
33dd2e1352SJohn Baldwin #include <sodium/crypto_stream_chacha20.h>
34dd2e1352SJohn Baldwin
35ab91fb6cSJohn Baldwin struct chacha20_poly1305_ctx {
36ab91fb6cSJohn Baldwin struct crypto_onetimeauth_poly1305_state auth;
37dd2e1352SJohn Baldwin const void *key;
38dd2e1352SJohn Baldwin uint32_t ic;
3942dcd395SJohn Baldwin bool ietf;
40dd2e1352SJohn Baldwin char nonce[CHACHA20_POLY1305_IV_LEN];
41dd2e1352SJohn Baldwin };
42dd2e1352SJohn Baldwin
438f35841fSJohn Baldwin struct xchacha20_poly1305_ctx {
448f35841fSJohn Baldwin struct chacha20_poly1305_ctx base_ctx; /* must be first */
458f35841fSJohn Baldwin const void *key;
468f35841fSJohn Baldwin char derived_key[CHACHA20_POLY1305_KEY];
478f35841fSJohn Baldwin };
488f35841fSJohn Baldwin
49dd2e1352SJohn Baldwin static int
chacha20_poly1305_setkey(void * vctx,const uint8_t * key,int len)50dd2e1352SJohn Baldwin chacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len)
51dd2e1352SJohn Baldwin {
52ab91fb6cSJohn Baldwin struct chacha20_poly1305_ctx *ctx = vctx;
53dd2e1352SJohn Baldwin
54dd2e1352SJohn Baldwin if (len != CHACHA20_POLY1305_KEY)
55dd2e1352SJohn Baldwin return (EINVAL);
56dd2e1352SJohn Baldwin
57dd2e1352SJohn Baldwin ctx->key = key;
58dd2e1352SJohn Baldwin return (0);
59dd2e1352SJohn Baldwin }
60dd2e1352SJohn Baldwin
61dd2e1352SJohn Baldwin static void
chacha20_poly1305_reinit(void * vctx,const uint8_t * iv,size_t ivlen)621833d604SJohn Baldwin chacha20_poly1305_reinit(void *vctx, const uint8_t *iv, size_t ivlen)
63dd2e1352SJohn Baldwin {
64ab91fb6cSJohn Baldwin struct chacha20_poly1305_ctx *ctx = vctx;
65ab91fb6cSJohn Baldwin char block[CHACHA20_NATIVE_BLOCK_LEN];
66dd2e1352SJohn Baldwin
67442ad83eSJohn Baldwin KASSERT(ivlen == 8 || ivlen == sizeof(ctx->nonce),
681833d604SJohn Baldwin ("%s: invalid nonce length", __func__));
691833d604SJohn Baldwin
7042dcd395SJohn Baldwin memcpy(ctx->nonce, iv, ivlen);
7142dcd395SJohn Baldwin ctx->ietf = (ivlen == CHACHA20_POLY1305_IV_LEN);
72ab91fb6cSJohn Baldwin
73ab91fb6cSJohn Baldwin /* Block 0 is used for the poly1305 key. */
74ab91fb6cSJohn Baldwin if (ctx->ietf)
75ab91fb6cSJohn Baldwin crypto_stream_chacha20_ietf(block, sizeof(block), iv, ctx->key);
76ab91fb6cSJohn Baldwin else
77ab91fb6cSJohn Baldwin crypto_stream_chacha20(block, sizeof(block), iv, ctx->key);
78ab91fb6cSJohn Baldwin crypto_onetimeauth_poly1305_init(&ctx->auth, block);
79ab91fb6cSJohn Baldwin explicit_bzero(block, sizeof(block));
80ab91fb6cSJohn Baldwin
81ab91fb6cSJohn Baldwin /* Start with block 1 for ciphertext. */
82dd2e1352SJohn Baldwin ctx->ic = 1;
83dd2e1352SJohn Baldwin }
84dd2e1352SJohn Baldwin
85dd2e1352SJohn Baldwin static void
chacha20_poly1305_crypt(void * vctx,const uint8_t * in,uint8_t * out)86dd2e1352SJohn Baldwin chacha20_poly1305_crypt(void *vctx, const uint8_t *in, uint8_t *out)
87dd2e1352SJohn Baldwin {
88ab91fb6cSJohn Baldwin struct chacha20_poly1305_ctx *ctx = vctx;
895a052b61SScott Long int error __diagused;
90dd2e1352SJohn Baldwin
9142dcd395SJohn Baldwin if (ctx->ietf)
92dd2e1352SJohn Baldwin error = crypto_stream_chacha20_ietf_xor_ic(out, in,
93dd2e1352SJohn Baldwin CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key);
9442dcd395SJohn Baldwin else
9542dcd395SJohn Baldwin error = crypto_stream_chacha20_xor_ic(out, in,
9642dcd395SJohn Baldwin CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key);
97dd2e1352SJohn Baldwin KASSERT(error == 0, ("%s failed: %d", __func__, error));
98dd2e1352SJohn Baldwin ctx->ic++;
99dd2e1352SJohn Baldwin }
100dd2e1352SJohn Baldwin
101dd2e1352SJohn Baldwin static void
chacha20_poly1305_crypt_multi(void * vctx,const uint8_t * in,uint8_t * out,size_t len)102d7f0b3ceSJohn Baldwin chacha20_poly1305_crypt_multi(void *vctx, const uint8_t *in, uint8_t *out, size_t len)
103d7f0b3ceSJohn Baldwin {
104d7f0b3ceSJohn Baldwin struct chacha20_poly1305_ctx *ctx = vctx;
105d7f0b3ceSJohn Baldwin int error __diagused;
106d7f0b3ceSJohn Baldwin
107d7f0b3ceSJohn Baldwin KASSERT(len % CHACHA20_NATIVE_BLOCK_LEN == 0, ("%s: invalid length",
108d7f0b3ceSJohn Baldwin __func__));
109d7f0b3ceSJohn Baldwin if (ctx->ietf)
110d7f0b3ceSJohn Baldwin error = crypto_stream_chacha20_ietf_xor_ic(out, in, len,
111d7f0b3ceSJohn Baldwin ctx->nonce, ctx->ic, ctx->key);
112d7f0b3ceSJohn Baldwin else
113d7f0b3ceSJohn Baldwin error = crypto_stream_chacha20_xor_ic(out, in, len, ctx->nonce,
114d7f0b3ceSJohn Baldwin ctx->ic, ctx->key);
115d7f0b3ceSJohn Baldwin KASSERT(error == 0, ("%s failed: %d", __func__, error));
116d7f0b3ceSJohn Baldwin ctx->ic += len / CHACHA20_NATIVE_BLOCK_LEN;
117d7f0b3ceSJohn Baldwin }
118d7f0b3ceSJohn Baldwin
119d7f0b3ceSJohn Baldwin static void
chacha20_poly1305_crypt_last(void * vctx,const uint8_t * in,uint8_t * out,size_t len)120dd2e1352SJohn Baldwin chacha20_poly1305_crypt_last(void *vctx, const uint8_t *in, uint8_t *out,
121dd2e1352SJohn Baldwin size_t len)
122dd2e1352SJohn Baldwin {
123ab91fb6cSJohn Baldwin struct chacha20_poly1305_ctx *ctx = vctx;
124dd2e1352SJohn Baldwin
1255a052b61SScott Long int error __diagused;
126dd2e1352SJohn Baldwin
12742dcd395SJohn Baldwin if (ctx->ietf)
12842dcd395SJohn Baldwin error = crypto_stream_chacha20_ietf_xor_ic(out, in, len,
12942dcd395SJohn Baldwin ctx->nonce, ctx->ic, ctx->key);
13042dcd395SJohn Baldwin else
13142dcd395SJohn Baldwin error = crypto_stream_chacha20_xor_ic(out, in, len, ctx->nonce,
132dd2e1352SJohn Baldwin ctx->ic, ctx->key);
133dd2e1352SJohn Baldwin KASSERT(error == 0, ("%s failed: %d", __func__, error));
134dd2e1352SJohn Baldwin }
135dd2e1352SJohn Baldwin
136ab91fb6cSJohn Baldwin static int
chacha20_poly1305_update(void * vctx,const void * data,u_int len)137ab91fb6cSJohn Baldwin chacha20_poly1305_update(void *vctx, const void *data, u_int len)
138ab91fb6cSJohn Baldwin {
139ab91fb6cSJohn Baldwin struct chacha20_poly1305_ctx *ctx = vctx;
140ab91fb6cSJohn Baldwin
141ab91fb6cSJohn Baldwin crypto_onetimeauth_poly1305_update(&ctx->auth, data, len);
142ab91fb6cSJohn Baldwin return (0);
143ab91fb6cSJohn Baldwin }
144ab91fb6cSJohn Baldwin
145ab91fb6cSJohn Baldwin static void
chacha20_poly1305_final(uint8_t * digest,void * vctx)146ab91fb6cSJohn Baldwin chacha20_poly1305_final(uint8_t *digest, void *vctx)
147ab91fb6cSJohn Baldwin {
148ab91fb6cSJohn Baldwin struct chacha20_poly1305_ctx *ctx = vctx;
149ab91fb6cSJohn Baldwin
150ab91fb6cSJohn Baldwin crypto_onetimeauth_poly1305_final(&ctx->auth, digest);
151ab91fb6cSJohn Baldwin }
152ab91fb6cSJohn Baldwin
153d8787d4fSMark Johnston const struct enc_xform enc_xform_chacha20_poly1305 = {
154fc8fc743SJohn Baldwin .type = CRYPTO_CHACHA20_POLY1305,
155fc8fc743SJohn Baldwin .name = "ChaCha20-Poly1305",
156ab91fb6cSJohn Baldwin .ctxsize = sizeof(struct chacha20_poly1305_ctx),
157fc8fc743SJohn Baldwin .blocksize = 1,
158dd2e1352SJohn Baldwin .native_blocksize = CHACHA20_NATIVE_BLOCK_LEN,
159fc8fc743SJohn Baldwin .ivsize = CHACHA20_POLY1305_IV_LEN,
160fc8fc743SJohn Baldwin .minkey = CHACHA20_POLY1305_KEY,
161fc8fc743SJohn Baldwin .maxkey = CHACHA20_POLY1305_KEY,
162ab91fb6cSJohn Baldwin .macsize = POLY1305_HASH_LEN,
163dd2e1352SJohn Baldwin .setkey = chacha20_poly1305_setkey,
164dd2e1352SJohn Baldwin .reinit = chacha20_poly1305_reinit,
165d7f0b3ceSJohn Baldwin .encrypt = chacha20_poly1305_crypt,
166d7f0b3ceSJohn Baldwin .decrypt = chacha20_poly1305_crypt,
167d7f0b3ceSJohn Baldwin .encrypt_multi = chacha20_poly1305_crypt_multi,
168d7f0b3ceSJohn Baldwin .decrypt_multi = chacha20_poly1305_crypt_multi,
169dd2e1352SJohn Baldwin .encrypt_last = chacha20_poly1305_crypt_last,
170dd2e1352SJohn Baldwin .decrypt_last = chacha20_poly1305_crypt_last,
171ab91fb6cSJohn Baldwin .update = chacha20_poly1305_update,
172ab91fb6cSJohn Baldwin .final = chacha20_poly1305_final,
173dd2e1352SJohn Baldwin };
1748f35841fSJohn Baldwin
1758f35841fSJohn Baldwin static int
xchacha20_poly1305_setkey(void * vctx,const uint8_t * key,int len)1768f35841fSJohn Baldwin xchacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len)
1778f35841fSJohn Baldwin {
1788f35841fSJohn Baldwin struct xchacha20_poly1305_ctx *ctx = vctx;
1798f35841fSJohn Baldwin
1808f35841fSJohn Baldwin if (len != XCHACHA20_POLY1305_KEY)
1818f35841fSJohn Baldwin return (EINVAL);
1828f35841fSJohn Baldwin
1838f35841fSJohn Baldwin ctx->key = key;
1848f35841fSJohn Baldwin ctx->base_ctx.key = ctx->derived_key;
1858f35841fSJohn Baldwin return (0);
1868f35841fSJohn Baldwin }
1878f35841fSJohn Baldwin
1888f35841fSJohn Baldwin static void
xchacha20_poly1305_reinit(void * vctx,const uint8_t * iv,size_t ivlen)1898f35841fSJohn Baldwin xchacha20_poly1305_reinit(void *vctx, const uint8_t *iv, size_t ivlen)
1908f35841fSJohn Baldwin {
1918f35841fSJohn Baldwin struct xchacha20_poly1305_ctx *ctx = vctx;
1928f35841fSJohn Baldwin char nonce[CHACHA20_POLY1305_IV_LEN];
1938f35841fSJohn Baldwin
1948f35841fSJohn Baldwin KASSERT(ivlen == XCHACHA20_POLY1305_IV_LEN,
1958f35841fSJohn Baldwin ("%s: invalid nonce length", __func__));
1968f35841fSJohn Baldwin
1978f35841fSJohn Baldwin /*
1988f35841fSJohn Baldwin * Use HChaCha20 to derive the internal key used for
1998f35841fSJohn Baldwin * ChaCha20-Poly1305.
2008f35841fSJohn Baldwin */
2018f35841fSJohn Baldwin crypto_core_hchacha20(ctx->derived_key, iv, ctx->key, NULL);
2028f35841fSJohn Baldwin
2038f35841fSJohn Baldwin memset(nonce, 0, 4);
2048f35841fSJohn Baldwin memcpy(nonce + 4, iv + crypto_core_hchacha20_INPUTBYTES,
2058f35841fSJohn Baldwin sizeof(nonce) - 4);
2068f35841fSJohn Baldwin chacha20_poly1305_reinit(&ctx->base_ctx, nonce, sizeof(nonce));
2078f35841fSJohn Baldwin explicit_bzero(nonce, sizeof(nonce));
2088f35841fSJohn Baldwin }
2098f35841fSJohn Baldwin
2108f35841fSJohn Baldwin const struct enc_xform enc_xform_xchacha20_poly1305 = {
2118f35841fSJohn Baldwin .type = CRYPTO_XCHACHA20_POLY1305,
2128f35841fSJohn Baldwin .name = "XChaCha20-Poly1305",
2138f35841fSJohn Baldwin .ctxsize = sizeof(struct xchacha20_poly1305_ctx),
2148f35841fSJohn Baldwin .blocksize = 1,
2158f35841fSJohn Baldwin .native_blocksize = CHACHA20_NATIVE_BLOCK_LEN,
2168f35841fSJohn Baldwin .ivsize = XCHACHA20_POLY1305_IV_LEN,
2178f35841fSJohn Baldwin .minkey = XCHACHA20_POLY1305_KEY,
2188f35841fSJohn Baldwin .maxkey = XCHACHA20_POLY1305_KEY,
2198f35841fSJohn Baldwin .macsize = POLY1305_HASH_LEN,
2208f35841fSJohn Baldwin .setkey = xchacha20_poly1305_setkey,
2218f35841fSJohn Baldwin .reinit = xchacha20_poly1305_reinit,
222d7f0b3ceSJohn Baldwin .encrypt = chacha20_poly1305_crypt,
223d7f0b3ceSJohn Baldwin .decrypt = chacha20_poly1305_crypt,
224d7f0b3ceSJohn Baldwin .encrypt_multi = chacha20_poly1305_crypt_multi,
225d7f0b3ceSJohn Baldwin .decrypt_multi = chacha20_poly1305_crypt_multi,
2268f35841fSJohn Baldwin .encrypt_last = chacha20_poly1305_crypt_last,
2278f35841fSJohn Baldwin .decrypt_last = chacha20_poly1305_crypt_last,
2288f35841fSJohn Baldwin .update = chacha20_poly1305_update,
2298f35841fSJohn Baldwin .final = chacha20_poly1305_final,
2308f35841fSJohn Baldwin };
231