Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/crypto/aead.c
26131 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* AEAD: Authenticated Encryption with Associated Data
4
*
5
* This file provides API support for AEAD algorithms.
6
*
7
* Copyright (c) 2007-2015 Herbert Xu <[email protected]>
8
*/
9
10
#include <crypto/internal/aead.h>
11
#include <linux/cryptouser.h>
12
#include <linux/errno.h>
13
#include <linux/init.h>
14
#include <linux/kernel.h>
15
#include <linux/module.h>
16
#include <linux/slab.h>
17
#include <linux/seq_file.h>
18
#include <linux/string.h>
19
#include <linux/string_choices.h>
20
#include <net/netlink.h>
21
22
#include "internal.h"
23
24
static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
25
unsigned int keylen)
26
{
27
unsigned long alignmask = crypto_aead_alignmask(tfm);
28
int ret;
29
u8 *buffer, *alignbuffer;
30
unsigned long absize;
31
32
absize = keylen + alignmask;
33
buffer = kmalloc(absize, GFP_ATOMIC);
34
if (!buffer)
35
return -ENOMEM;
36
37
alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
38
memcpy(alignbuffer, key, keylen);
39
ret = crypto_aead_alg(tfm)->setkey(tfm, alignbuffer, keylen);
40
kfree_sensitive(buffer);
41
return ret;
42
}
43
44
int crypto_aead_setkey(struct crypto_aead *tfm,
45
const u8 *key, unsigned int keylen)
46
{
47
unsigned long alignmask = crypto_aead_alignmask(tfm);
48
int err;
49
50
if ((unsigned long)key & alignmask)
51
err = setkey_unaligned(tfm, key, keylen);
52
else
53
err = crypto_aead_alg(tfm)->setkey(tfm, key, keylen);
54
55
if (unlikely(err)) {
56
crypto_aead_set_flags(tfm, CRYPTO_TFM_NEED_KEY);
57
return err;
58
}
59
60
crypto_aead_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
61
return 0;
62
}
63
EXPORT_SYMBOL_GPL(crypto_aead_setkey);
64
65
int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
66
{
67
int err;
68
69
if ((!authsize && crypto_aead_maxauthsize(tfm)) ||
70
authsize > crypto_aead_maxauthsize(tfm))
71
return -EINVAL;
72
73
if (crypto_aead_alg(tfm)->setauthsize) {
74
err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize);
75
if (err)
76
return err;
77
}
78
79
tfm->authsize = authsize;
80
return 0;
81
}
82
EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
83
84
int crypto_aead_encrypt(struct aead_request *req)
85
{
86
struct crypto_aead *aead = crypto_aead_reqtfm(req);
87
88
if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
89
return -ENOKEY;
90
91
return crypto_aead_alg(aead)->encrypt(req);
92
}
93
EXPORT_SYMBOL_GPL(crypto_aead_encrypt);
94
95
int crypto_aead_decrypt(struct aead_request *req)
96
{
97
struct crypto_aead *aead = crypto_aead_reqtfm(req);
98
99
if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
100
return -ENOKEY;
101
102
if (req->cryptlen < crypto_aead_authsize(aead))
103
return -EINVAL;
104
105
return crypto_aead_alg(aead)->decrypt(req);
106
}
107
EXPORT_SYMBOL_GPL(crypto_aead_decrypt);
108
109
static void crypto_aead_exit_tfm(struct crypto_tfm *tfm)
110
{
111
struct crypto_aead *aead = __crypto_aead_cast(tfm);
112
struct aead_alg *alg = crypto_aead_alg(aead);
113
114
alg->exit(aead);
115
}
116
117
static int crypto_aead_init_tfm(struct crypto_tfm *tfm)
118
{
119
struct crypto_aead *aead = __crypto_aead_cast(tfm);
120
struct aead_alg *alg = crypto_aead_alg(aead);
121
122
crypto_aead_set_flags(aead, CRYPTO_TFM_NEED_KEY);
123
124
aead->authsize = alg->maxauthsize;
125
126
if (alg->exit)
127
aead->base.exit = crypto_aead_exit_tfm;
128
129
if (alg->init)
130
return alg->init(aead);
131
132
return 0;
133
}
134
135
static int __maybe_unused crypto_aead_report(
136
struct sk_buff *skb, struct crypto_alg *alg)
137
{
138
struct crypto_report_aead raead;
139
struct aead_alg *aead = container_of(alg, struct aead_alg, base);
140
141
memset(&raead, 0, sizeof(raead));
142
143
strscpy(raead.type, "aead", sizeof(raead.type));
144
strscpy(raead.geniv, "<none>", sizeof(raead.geniv));
145
146
raead.blocksize = alg->cra_blocksize;
147
raead.maxauthsize = aead->maxauthsize;
148
raead.ivsize = aead->ivsize;
149
150
return nla_put(skb, CRYPTOCFGA_REPORT_AEAD, sizeof(raead), &raead);
151
}
152
153
static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
154
__maybe_unused;
155
static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
156
{
157
struct aead_alg *aead = container_of(alg, struct aead_alg, base);
158
159
seq_printf(m, "type : aead\n");
160
seq_printf(m, "async : %s\n",
161
str_yes_no(alg->cra_flags & CRYPTO_ALG_ASYNC));
162
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
163
seq_printf(m, "ivsize : %u\n", aead->ivsize);
164
seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize);
165
seq_printf(m, "geniv : <none>\n");
166
}
167
168
static void crypto_aead_free_instance(struct crypto_instance *inst)
169
{
170
struct aead_instance *aead = aead_instance(inst);
171
172
aead->free(aead);
173
}
174
175
static const struct crypto_type crypto_aead_type = {
176
.extsize = crypto_alg_extsize,
177
.init_tfm = crypto_aead_init_tfm,
178
.free = crypto_aead_free_instance,
179
#ifdef CONFIG_PROC_FS
180
.show = crypto_aead_show,
181
#endif
182
#if IS_ENABLED(CONFIG_CRYPTO_USER)
183
.report = crypto_aead_report,
184
#endif
185
.maskclear = ~CRYPTO_ALG_TYPE_MASK,
186
.maskset = CRYPTO_ALG_TYPE_MASK,
187
.type = CRYPTO_ALG_TYPE_AEAD,
188
.tfmsize = offsetof(struct crypto_aead, base),
189
.algsize = offsetof(struct aead_alg, base),
190
};
191
192
int crypto_grab_aead(struct crypto_aead_spawn *spawn,
193
struct crypto_instance *inst,
194
const char *name, u32 type, u32 mask)
195
{
196
spawn->base.frontend = &crypto_aead_type;
197
return crypto_grab_spawn(&spawn->base, inst, name, type, mask);
198
}
199
EXPORT_SYMBOL_GPL(crypto_grab_aead);
200
201
struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
202
{
203
return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask);
204
}
205
EXPORT_SYMBOL_GPL(crypto_alloc_aead);
206
207
int crypto_has_aead(const char *alg_name, u32 type, u32 mask)
208
{
209
return crypto_type_has_alg(alg_name, &crypto_aead_type, type, mask);
210
}
211
EXPORT_SYMBOL_GPL(crypto_has_aead);
212
213
static int aead_prepare_alg(struct aead_alg *alg)
214
{
215
struct crypto_alg *base = &alg->base;
216
217
if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) >
218
PAGE_SIZE / 8)
219
return -EINVAL;
220
221
if (!alg->chunksize)
222
alg->chunksize = base->cra_blocksize;
223
224
base->cra_type = &crypto_aead_type;
225
base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
226
base->cra_flags |= CRYPTO_ALG_TYPE_AEAD;
227
228
return 0;
229
}
230
231
int crypto_register_aead(struct aead_alg *alg)
232
{
233
struct crypto_alg *base = &alg->base;
234
int err;
235
236
err = aead_prepare_alg(alg);
237
if (err)
238
return err;
239
240
return crypto_register_alg(base);
241
}
242
EXPORT_SYMBOL_GPL(crypto_register_aead);
243
244
void crypto_unregister_aead(struct aead_alg *alg)
245
{
246
crypto_unregister_alg(&alg->base);
247
}
248
EXPORT_SYMBOL_GPL(crypto_unregister_aead);
249
250
int crypto_register_aeads(struct aead_alg *algs, int count)
251
{
252
int i, ret;
253
254
for (i = 0; i < count; i++) {
255
ret = crypto_register_aead(&algs[i]);
256
if (ret)
257
goto err;
258
}
259
260
return 0;
261
262
err:
263
for (--i; i >= 0; --i)
264
crypto_unregister_aead(&algs[i]);
265
266
return ret;
267
}
268
EXPORT_SYMBOL_GPL(crypto_register_aeads);
269
270
void crypto_unregister_aeads(struct aead_alg *algs, int count)
271
{
272
int i;
273
274
for (i = count - 1; i >= 0; --i)
275
crypto_unregister_aead(&algs[i]);
276
}
277
EXPORT_SYMBOL_GPL(crypto_unregister_aeads);
278
279
int aead_register_instance(struct crypto_template *tmpl,
280
struct aead_instance *inst)
281
{
282
int err;
283
284
if (WARN_ON(!inst->free))
285
return -EINVAL;
286
287
err = aead_prepare_alg(&inst->alg);
288
if (err)
289
return err;
290
291
return crypto_register_instance(tmpl, aead_crypto_instance(inst));
292
}
293
EXPORT_SYMBOL_GPL(aead_register_instance);
294
295
MODULE_LICENSE("GPL");
296
MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
297
298