Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/crypto/chacha20_poly1305.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2021 The FreeBSD Foundation
5
*
6
* This software was developed by Ararat River Consulting, LLC under
7
* sponsorship from the FreeBSD Foundation.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
* SUCH DAMAGE.
29
*/
30
31
#include <sys/endian.h>
32
#include <crypto/chacha20_poly1305.h>
33
#include <opencrypto/xform_enc.h>
34
35
static const uint8_t zeroes[POLY1305_BLOCK_LEN];
36
37
void
38
chacha20_poly1305_encrypt(uint8_t *dst, const uint8_t *src,
39
const size_t src_len, const uint8_t *aad, const size_t aad_len,
40
const uint8_t *nonce, const size_t nonce_len, const uint8_t *key)
41
{
42
const struct enc_xform *exf;
43
void *ctx;
44
size_t resid, todo;
45
uint64_t lengths[2];
46
47
exf = &enc_xform_chacha20_poly1305;
48
ctx = __builtin_alloca(exf->ctxsize);
49
exf->setkey(ctx, key, CHACHA20_POLY1305_KEY);
50
exf->reinit(ctx, nonce, nonce_len);
51
52
exf->update(ctx, aad, aad_len);
53
if (aad_len % POLY1305_BLOCK_LEN != 0)
54
exf->update(ctx, zeroes,
55
POLY1305_BLOCK_LEN - aad_len % POLY1305_BLOCK_LEN);
56
57
resid = src_len;
58
todo = rounddown2(resid, CHACHA20_NATIVE_BLOCK_LEN);
59
if (todo > 0) {
60
exf->encrypt_multi(ctx, src, dst, todo);
61
exf->update(ctx, dst, todo);
62
src += todo;
63
dst += todo;
64
resid -= todo;
65
}
66
if (resid > 0) {
67
exf->encrypt_last(ctx, src, dst, resid);
68
exf->update(ctx, dst, resid);
69
dst += resid;
70
if (resid % POLY1305_BLOCK_LEN != 0)
71
exf->update(ctx, zeroes,
72
POLY1305_BLOCK_LEN - resid % POLY1305_BLOCK_LEN);
73
}
74
75
lengths[0] = htole64(aad_len);
76
lengths[1] = htole64(src_len);
77
exf->update(ctx, lengths, sizeof(lengths));
78
exf->final(dst, ctx);
79
80
explicit_bzero(ctx, exf->ctxsize);
81
explicit_bzero(lengths, sizeof(lengths));
82
}
83
84
bool
85
chacha20_poly1305_decrypt(uint8_t *dst, const uint8_t *src,
86
const size_t src_len, const uint8_t *aad, const size_t aad_len,
87
const uint8_t *nonce, const size_t nonce_len, const uint8_t *key)
88
{
89
const struct enc_xform *exf;
90
void *ctx;
91
size_t resid, todo;
92
union {
93
uint64_t lengths[2];
94
char tag[POLY1305_HASH_LEN];
95
} u;
96
bool result;
97
98
if (src_len < POLY1305_HASH_LEN)
99
return (false);
100
resid = src_len - POLY1305_HASH_LEN;
101
102
exf = &enc_xform_chacha20_poly1305;
103
ctx = __builtin_alloca(exf->ctxsize);
104
exf->setkey(ctx, key, CHACHA20_POLY1305_KEY);
105
exf->reinit(ctx, nonce, nonce_len);
106
107
exf->update(ctx, aad, aad_len);
108
if (aad_len % POLY1305_BLOCK_LEN != 0)
109
exf->update(ctx, zeroes,
110
POLY1305_BLOCK_LEN - aad_len % POLY1305_BLOCK_LEN);
111
exf->update(ctx, src, resid);
112
if (resid % POLY1305_BLOCK_LEN != 0)
113
exf->update(ctx, zeroes,
114
POLY1305_BLOCK_LEN - resid % POLY1305_BLOCK_LEN);
115
116
u.lengths[0] = htole64(aad_len);
117
u.lengths[1] = htole64(resid);
118
exf->update(ctx, u.lengths, sizeof(u.lengths));
119
exf->final(u.tag, ctx);
120
result = (timingsafe_bcmp(u.tag, src + resid, POLY1305_HASH_LEN) == 0);
121
if (!result)
122
goto out;
123
124
todo = rounddown2(resid, CHACHA20_NATIVE_BLOCK_LEN);
125
if (todo > 0) {
126
exf->decrypt_multi(ctx, src, dst, todo);
127
src += todo;
128
dst += todo;
129
resid -= todo;
130
}
131
if (resid > 0)
132
exf->decrypt_last(ctx, src, dst, resid);
133
134
out:
135
explicit_bzero(ctx, exf->ctxsize);
136
explicit_bzero(&u, sizeof(u));
137
return (result);
138
}
139
140
void
141
xchacha20_poly1305_encrypt(uint8_t *dst, const uint8_t *src,
142
const size_t src_len, const uint8_t *aad, const size_t aad_len,
143
const uint8_t *nonce, const uint8_t *key)
144
{
145
const struct enc_xform *exf;
146
void *ctx;
147
size_t resid, todo;
148
uint64_t lengths[2];
149
150
exf = &enc_xform_xchacha20_poly1305;
151
ctx = __builtin_alloca(exf->ctxsize);
152
exf->setkey(ctx, key, XCHACHA20_POLY1305_KEY);
153
exf->reinit(ctx, nonce, XCHACHA20_POLY1305_IV_LEN);
154
155
exf->update(ctx, aad, aad_len);
156
if (aad_len % POLY1305_BLOCK_LEN != 0)
157
exf->update(ctx, zeroes,
158
POLY1305_BLOCK_LEN - aad_len % POLY1305_BLOCK_LEN);
159
160
resid = src_len;
161
todo = rounddown2(resid, CHACHA20_NATIVE_BLOCK_LEN);
162
if (todo > 0) {
163
exf->encrypt_multi(ctx, src, dst, todo);
164
exf->update(ctx, dst, todo);
165
src += todo;
166
dst += todo;
167
resid -= todo;
168
}
169
if (resid > 0) {
170
exf->encrypt_last(ctx, src, dst, resid);
171
exf->update(ctx, dst, resid);
172
dst += resid;
173
if (resid % POLY1305_BLOCK_LEN != 0)
174
exf->update(ctx, zeroes,
175
POLY1305_BLOCK_LEN - resid % POLY1305_BLOCK_LEN);
176
}
177
178
lengths[0] = htole64(aad_len);
179
lengths[1] = htole64(src_len);
180
exf->update(ctx, lengths, sizeof(lengths));
181
exf->final(dst, ctx);
182
183
explicit_bzero(ctx, exf->ctxsize);
184
explicit_bzero(lengths, sizeof(lengths));
185
}
186
187
bool
188
xchacha20_poly1305_decrypt(uint8_t *dst, const uint8_t *src,
189
const size_t src_len, const uint8_t *aad, const size_t aad_len,
190
const uint8_t *nonce, const uint8_t *key)
191
{
192
const struct enc_xform *exf;
193
void *ctx;
194
size_t resid, todo;
195
union {
196
uint64_t lengths[2];
197
char tag[POLY1305_HASH_LEN];
198
} u;
199
bool result;
200
201
if (src_len < POLY1305_HASH_LEN)
202
return (false);
203
resid = src_len - POLY1305_HASH_LEN;
204
205
exf = &enc_xform_xchacha20_poly1305;
206
ctx = __builtin_alloca(exf->ctxsize);
207
exf->setkey(ctx, key, XCHACHA20_POLY1305_KEY);
208
exf->reinit(ctx, nonce, XCHACHA20_POLY1305_IV_LEN);
209
210
exf->update(ctx, aad, aad_len);
211
if (aad_len % POLY1305_BLOCK_LEN != 0)
212
exf->update(ctx, zeroes,
213
POLY1305_BLOCK_LEN - aad_len % POLY1305_BLOCK_LEN);
214
exf->update(ctx, src, resid);
215
if (resid % POLY1305_BLOCK_LEN != 0)
216
exf->update(ctx, zeroes,
217
POLY1305_BLOCK_LEN - resid % POLY1305_BLOCK_LEN);
218
219
u.lengths[0] = htole64(aad_len);
220
u.lengths[1] = htole64(resid);
221
exf->update(ctx, u.lengths, sizeof(u.lengths));
222
exf->final(u.tag, ctx);
223
result = (timingsafe_bcmp(u.tag, src + resid, POLY1305_HASH_LEN) == 0);
224
if (!result)
225
goto out;
226
227
todo = rounddown2(resid, CHACHA20_NATIVE_BLOCK_LEN);
228
if (todo > 0) {
229
exf->decrypt_multi(ctx, src, dst, todo);
230
src += todo;
231
dst += todo;
232
resid -= todo;
233
}
234
if (resid > 0)
235
exf->decrypt_last(ctx, src, dst, resid);
236
237
out:
238
explicit_bzero(ctx, exf->ctxsize);
239
explicit_bzero(&u, sizeof(u));
240
return (result);
241
}
242
243