Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/opencrypto/xform_chacha20_poly1305.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
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
};
231
232