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