xref: /freebsd/sys/opencrypto/xform_chacha20_poly1305.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
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