]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/opencrypto/xform_chacha20_poly1305.c
ktls: Inline ktls_cleanup() into ktls_destroy().
[FreeBSD/FreeBSD.git] / sys / opencrypto / xform_chacha20_poly1305.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2020 Netflix Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <opencrypto/xform_auth.h>
29 #include <opencrypto/xform_enc.h>
30
31 #include <sodium/crypto_core_hchacha20.h>
32 #include <sodium/crypto_onetimeauth_poly1305.h>
33 #include <sodium/crypto_stream_chacha20.h>
34
35 struct chacha20_poly1305_ctx {
36         struct crypto_onetimeauth_poly1305_state auth;
37         const void *key;
38         uint32_t ic;
39         bool ietf;
40         char nonce[CHACHA20_POLY1305_IV_LEN];
41 };
42
43 struct xchacha20_poly1305_ctx {
44         struct chacha20_poly1305_ctx base_ctx;  /* must be first */
45         const void *key;
46         char derived_key[CHACHA20_POLY1305_KEY];
47 };
48
49 static int
50 chacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len)
51 {
52         struct chacha20_poly1305_ctx *ctx = vctx;
53
54         if (len != CHACHA20_POLY1305_KEY)
55                 return (EINVAL);
56
57         ctx->key = key;
58         return (0);
59 }
60
61 static void
62 chacha20_poly1305_reinit(void *vctx, const uint8_t *iv, size_t ivlen)
63 {
64         struct chacha20_poly1305_ctx *ctx = vctx;
65         char block[CHACHA20_NATIVE_BLOCK_LEN];
66
67         KASSERT(ivlen == 8 || ivlen == sizeof(ctx->nonce),
68             ("%s: invalid nonce length", __func__));
69
70         memcpy(ctx->nonce, iv, ivlen);
71         ctx->ietf = (ivlen == CHACHA20_POLY1305_IV_LEN);
72
73         /* Block 0 is used for the poly1305 key. */
74         if (ctx->ietf)
75                 crypto_stream_chacha20_ietf(block, sizeof(block), iv, ctx->key);
76         else
77                 crypto_stream_chacha20(block, sizeof(block), iv, ctx->key);
78         crypto_onetimeauth_poly1305_init(&ctx->auth, block);
79         explicit_bzero(block, sizeof(block));
80
81         /* Start with block 1 for ciphertext. */
82         ctx->ic = 1;
83 }
84
85 static void
86 chacha20_poly1305_crypt(void *vctx, const uint8_t *in, uint8_t *out)
87 {
88         struct chacha20_poly1305_ctx *ctx = vctx;
89         int error __diagused;
90
91         if (ctx->ietf)
92                 error = crypto_stream_chacha20_ietf_xor_ic(out, in,
93                     CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key);
94         else
95                 error = crypto_stream_chacha20_xor_ic(out, in,
96                     CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key);
97         KASSERT(error == 0, ("%s failed: %d", __func__, error));
98         ctx->ic++;
99 }
100
101 static void
102 chacha20_poly1305_crypt_multi(void *vctx, const uint8_t *in, uint8_t *out, size_t len)
103 {
104         struct chacha20_poly1305_ctx *ctx = vctx;
105         int error __diagused;
106
107         KASSERT(len % CHACHA20_NATIVE_BLOCK_LEN == 0, ("%s: invalid length",
108             __func__));
109         if (ctx->ietf)
110                 error = crypto_stream_chacha20_ietf_xor_ic(out, in, len,
111                     ctx->nonce, ctx->ic, ctx->key);
112         else
113                 error = crypto_stream_chacha20_xor_ic(out, in, len, ctx->nonce,
114                     ctx->ic, ctx->key);
115         KASSERT(error == 0, ("%s failed: %d", __func__, error));
116         ctx->ic += len / CHACHA20_NATIVE_BLOCK_LEN;
117 }
118
119 static void
120 chacha20_poly1305_crypt_last(void *vctx, const uint8_t *in, uint8_t *out,
121     size_t len)
122 {
123         struct chacha20_poly1305_ctx *ctx = vctx;
124
125         int error __diagused;
126
127         if (ctx->ietf)
128                 error = crypto_stream_chacha20_ietf_xor_ic(out, in, len,
129                     ctx->nonce, ctx->ic, ctx->key);
130         else
131                 error = crypto_stream_chacha20_xor_ic(out, in, len, ctx->nonce,
132                     ctx->ic, ctx->key);
133         KASSERT(error == 0, ("%s failed: %d", __func__, error));
134 }
135
136 static int
137 chacha20_poly1305_update(void *vctx, const void *data, u_int len)
138 {
139         struct chacha20_poly1305_ctx *ctx = vctx;
140
141         crypto_onetimeauth_poly1305_update(&ctx->auth, data, len);
142         return (0);
143 }
144
145 static void
146 chacha20_poly1305_final(uint8_t *digest, void *vctx)
147 {
148         struct chacha20_poly1305_ctx *ctx = vctx;
149
150         crypto_onetimeauth_poly1305_final(&ctx->auth, digest);
151 }
152
153 const struct enc_xform enc_xform_chacha20_poly1305 = {
154         .type = CRYPTO_CHACHA20_POLY1305,
155         .name = "ChaCha20-Poly1305",
156         .ctxsize = sizeof(struct chacha20_poly1305_ctx),
157         .blocksize = 1,
158         .native_blocksize = CHACHA20_NATIVE_BLOCK_LEN,
159         .ivsize = CHACHA20_POLY1305_IV_LEN,
160         .minkey = CHACHA20_POLY1305_KEY,
161         .maxkey = CHACHA20_POLY1305_KEY,
162         .macsize = POLY1305_HASH_LEN,
163         .setkey = chacha20_poly1305_setkey,
164         .reinit = chacha20_poly1305_reinit,
165         .encrypt = chacha20_poly1305_crypt,
166         .decrypt = chacha20_poly1305_crypt,
167         .encrypt_multi = chacha20_poly1305_crypt_multi,
168         .decrypt_multi = chacha20_poly1305_crypt_multi,
169         .encrypt_last = chacha20_poly1305_crypt_last,
170         .decrypt_last = chacha20_poly1305_crypt_last,
171         .update = chacha20_poly1305_update,
172         .final = chacha20_poly1305_final,
173 };
174
175 static int
176 xchacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len)
177 {
178         struct xchacha20_poly1305_ctx *ctx = vctx;
179
180         if (len != XCHACHA20_POLY1305_KEY)
181                 return (EINVAL);
182
183         ctx->key = key;
184         ctx->base_ctx.key = ctx->derived_key;
185         return (0);
186 }
187
188 static void
189 xchacha20_poly1305_reinit(void *vctx, const uint8_t *iv, size_t ivlen)
190 {
191         struct xchacha20_poly1305_ctx *ctx = vctx;
192         char nonce[CHACHA20_POLY1305_IV_LEN];
193
194         KASSERT(ivlen == XCHACHA20_POLY1305_IV_LEN,
195             ("%s: invalid nonce length", __func__));
196
197         /*
198          * Use HChaCha20 to derive the internal key used for
199          * ChaCha20-Poly1305.
200          */
201         crypto_core_hchacha20(ctx->derived_key, iv, ctx->key, NULL);
202
203         memset(nonce, 0, 4);
204         memcpy(nonce + 4, iv + crypto_core_hchacha20_INPUTBYTES,
205             sizeof(nonce) - 4);
206         chacha20_poly1305_reinit(&ctx->base_ctx, nonce, sizeof(nonce));
207         explicit_bzero(nonce, sizeof(nonce));
208 }
209
210 const struct enc_xform enc_xform_xchacha20_poly1305 = {
211         .type = CRYPTO_XCHACHA20_POLY1305,
212         .name = "XChaCha20-Poly1305",
213         .ctxsize = sizeof(struct xchacha20_poly1305_ctx),
214         .blocksize = 1,
215         .native_blocksize = CHACHA20_NATIVE_BLOCK_LEN,
216         .ivsize = XCHACHA20_POLY1305_IV_LEN,
217         .minkey = XCHACHA20_POLY1305_KEY,
218         .maxkey = XCHACHA20_POLY1305_KEY,
219         .macsize = POLY1305_HASH_LEN,
220         .setkey = xchacha20_poly1305_setkey,
221         .reinit = xchacha20_poly1305_reinit,
222         .encrypt = chacha20_poly1305_crypt,
223         .decrypt = chacha20_poly1305_crypt,
224         .encrypt_multi = chacha20_poly1305_crypt_multi,
225         .decrypt_multi = chacha20_poly1305_crypt_multi,
226         .encrypt_last = chacha20_poly1305_crypt_last,
227         .decrypt_last = chacha20_poly1305_crypt_last,
228         .update = chacha20_poly1305_update,
229         .final = chacha20_poly1305_final,
230 };