12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21ae97820SHerbert Xu /*
31ae97820SHerbert Xu * AEAD: Authenticated Encryption with Associated Data
41ae97820SHerbert Xu *
51ae97820SHerbert Xu * This file provides API support for AEAD algorithms.
61ae97820SHerbert Xu *
7b0d955baSHerbert Xu * Copyright (c) 2007-2015 Herbert Xu <herbert@gondor.apana.org.au>
81ae97820SHerbert Xu */
91ae97820SHerbert Xu
1020cc01baSHerbert Xu #include <crypto/internal/aead.h>
110df4adf8SHerbert Xu #include <linux/cryptouser.h>
1220cc01baSHerbert Xu #include <linux/errno.h>
131ae97820SHerbert Xu #include <linux/init.h>
141ae97820SHerbert Xu #include <linux/kernel.h>
151ae97820SHerbert Xu #include <linux/module.h>
161ae97820SHerbert Xu #include <linux/slab.h>
171ae97820SHerbert Xu #include <linux/seq_file.h>
180df4adf8SHerbert Xu #include <linux/string.h>
196ad414feSSteffen Klassert #include <net/netlink.h>
201ae97820SHerbert Xu
215b6d2d7fSHerbert Xu #include "internal.h"
225b6d2d7fSHerbert Xu
setkey_unaligned(struct crypto_aead * tfm,const u8 * key,unsigned int keylen)231ae97820SHerbert Xu static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
241ae97820SHerbert Xu unsigned int keylen)
251ae97820SHerbert Xu {
261ae97820SHerbert Xu unsigned long alignmask = crypto_aead_alignmask(tfm);
271ae97820SHerbert Xu int ret;
281ae97820SHerbert Xu u8 *buffer, *alignbuffer;
291ae97820SHerbert Xu unsigned long absize;
301ae97820SHerbert Xu
311ae97820SHerbert Xu absize = keylen + alignmask;
321ae97820SHerbert Xu buffer = kmalloc(absize, GFP_ATOMIC);
331ae97820SHerbert Xu if (!buffer)
341ae97820SHerbert Xu return -ENOMEM;
351ae97820SHerbert Xu
361ae97820SHerbert Xu alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
371ae97820SHerbert Xu memcpy(alignbuffer, key, keylen);
38b0d955baSHerbert Xu ret = crypto_aead_alg(tfm)->setkey(tfm, alignbuffer, keylen);
39*23e4099bSHailey Mothershead kfree_sensitive(buffer);
401ae97820SHerbert Xu return ret;
411ae97820SHerbert Xu }
421ae97820SHerbert Xu
crypto_aead_setkey(struct crypto_aead * tfm,const u8 * key,unsigned int keylen)435d1d65f8SHerbert Xu int crypto_aead_setkey(struct crypto_aead *tfm,
445d1d65f8SHerbert Xu const u8 *key, unsigned int keylen)
451ae97820SHerbert Xu {
461ae97820SHerbert Xu unsigned long alignmask = crypto_aead_alignmask(tfm);
47dc26c17fSEric Biggers int err;
481ae97820SHerbert Xu
491ae97820SHerbert Xu if ((unsigned long)key & alignmask)
50dc26c17fSEric Biggers err = setkey_unaligned(tfm, key, keylen);
51dc26c17fSEric Biggers else
52dc26c17fSEric Biggers err = crypto_aead_alg(tfm)->setkey(tfm, key, keylen);
531ae97820SHerbert Xu
546ebc9700SEric Biggers if (unlikely(err)) {
556ebc9700SEric Biggers crypto_aead_set_flags(tfm, CRYPTO_TFM_NEED_KEY);
56dc26c17fSEric Biggers return err;
576ebc9700SEric Biggers }
58dc26c17fSEric Biggers
59dc26c17fSEric Biggers crypto_aead_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
60dc26c17fSEric Biggers return 0;
611ae97820SHerbert Xu }
625d1d65f8SHerbert Xu EXPORT_SYMBOL_GPL(crypto_aead_setkey);
631ae97820SHerbert Xu
crypto_aead_setauthsize(struct crypto_aead * tfm,unsigned int authsize)647ba683a6SHerbert Xu int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
657ba683a6SHerbert Xu {
667ba683a6SHerbert Xu int err;
677ba683a6SHerbert Xu
68a62084d2SPascal van Leeuwen if ((!authsize && crypto_aead_maxauthsize(tfm)) ||
69a62084d2SPascal van Leeuwen authsize > crypto_aead_maxauthsize(tfm))
707ba683a6SHerbert Xu return -EINVAL;
717ba683a6SHerbert Xu
72b0d955baSHerbert Xu if (crypto_aead_alg(tfm)->setauthsize) {
73b0d955baSHerbert Xu err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize);
747ba683a6SHerbert Xu if (err)
757ba683a6SHerbert Xu return err;
767ba683a6SHerbert Xu }
777ba683a6SHerbert Xu
785d1d65f8SHerbert Xu tfm->authsize = authsize;
797ba683a6SHerbert Xu return 0;
807ba683a6SHerbert Xu }
817ba683a6SHerbert Xu EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
827ba683a6SHerbert Xu
crypto_aead_encrypt(struct aead_request * req)83f2fe1154SEric Biggers int crypto_aead_encrypt(struct aead_request *req)
84f2fe1154SEric Biggers {
85f2fe1154SEric Biggers struct crypto_aead *aead = crypto_aead_reqtfm(req);
860df4adf8SHerbert Xu
87f2fe1154SEric Biggers if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
8829ce50e0SEric Biggers return -ENOKEY;
890df4adf8SHerbert Xu
9029ce50e0SEric Biggers return crypto_aead_alg(aead)->encrypt(req);
91f2fe1154SEric Biggers }
92f2fe1154SEric Biggers EXPORT_SYMBOL_GPL(crypto_aead_encrypt);
93f2fe1154SEric Biggers
crypto_aead_decrypt(struct aead_request * req)94f2fe1154SEric Biggers int crypto_aead_decrypt(struct aead_request *req)
95f2fe1154SEric Biggers {
96f2fe1154SEric Biggers struct crypto_aead *aead = crypto_aead_reqtfm(req);
970df4adf8SHerbert Xu
98f2fe1154SEric Biggers if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
9929ce50e0SEric Biggers return -ENOKEY;
1000df4adf8SHerbert Xu
10129ce50e0SEric Biggers if (req->cryptlen < crypto_aead_authsize(aead))
10229ce50e0SEric Biggers return -EINVAL;
10329ce50e0SEric Biggers
10429ce50e0SEric Biggers return crypto_aead_alg(aead)->decrypt(req);
105f2fe1154SEric Biggers }
106f2fe1154SEric Biggers EXPORT_SYMBOL_GPL(crypto_aead_decrypt);
107f2fe1154SEric Biggers
crypto_aead_exit_tfm(struct crypto_tfm * tfm)1085eb8ec6dSHerbert Xu static void crypto_aead_exit_tfm(struct crypto_tfm *tfm)
1095eb8ec6dSHerbert Xu {
1105eb8ec6dSHerbert Xu struct crypto_aead *aead = __crypto_aead_cast(tfm);
1115eb8ec6dSHerbert Xu struct aead_alg *alg = crypto_aead_alg(aead);
1125eb8ec6dSHerbert Xu
1135eb8ec6dSHerbert Xu alg->exit(aead);
1145eb8ec6dSHerbert Xu }
1155eb8ec6dSHerbert Xu
crypto_aead_init_tfm(struct crypto_tfm * tfm)11663293c61SHerbert Xu static int crypto_aead_init_tfm(struct crypto_tfm *tfm)
11763293c61SHerbert Xu {
11863293c61SHerbert Xu struct crypto_aead *aead = __crypto_aead_cast(tfm);
11963293c61SHerbert Xu struct aead_alg *alg = crypto_aead_alg(aead);
12063293c61SHerbert Xu
121dc26c17fSEric Biggers crypto_aead_set_flags(aead, CRYPTO_TFM_NEED_KEY);
122dc26c17fSEric Biggers
12363293c61SHerbert Xu aead->authsize = alg->maxauthsize;
12463293c61SHerbert Xu
1255eb8ec6dSHerbert Xu if (alg->exit)
1265eb8ec6dSHerbert Xu aead->base.exit = crypto_aead_exit_tfm;
1275eb8ec6dSHerbert Xu
1285eb8ec6dSHerbert Xu if (alg->init)
1295eb8ec6dSHerbert Xu return alg->init(aead);
1305eb8ec6dSHerbert Xu
13163293c61SHerbert Xu return 0;
13263293c61SHerbert Xu }
13363293c61SHerbert Xu
crypto_aead_report(struct sk_buff * skb,struct crypto_alg * alg)134c0f9e01dSHerbert Xu static int __maybe_unused crypto_aead_report(
135c0f9e01dSHerbert Xu struct sk_buff *skb, struct crypto_alg *alg)
13663293c61SHerbert Xu {
13763293c61SHerbert Xu struct crypto_report_aead raead;
13863293c61SHerbert Xu struct aead_alg *aead = container_of(alg, struct aead_alg, base);
13963293c61SHerbert Xu
14037db69e0SEric Biggers memset(&raead, 0, sizeof(raead));
14137db69e0SEric Biggers
14237db69e0SEric Biggers strscpy(raead.type, "aead", sizeof(raead.type));
14337db69e0SEric Biggers strscpy(raead.geniv, "<none>", sizeof(raead.geniv));
14463293c61SHerbert Xu
14563293c61SHerbert Xu raead.blocksize = alg->cra_blocksize;
14663293c61SHerbert Xu raead.maxauthsize = aead->maxauthsize;
14763293c61SHerbert Xu raead.ivsize = aead->ivsize;
14863293c61SHerbert Xu
14937db69e0SEric Biggers return nla_put(skb, CRYPTOCFGA_REPORT_AEAD, sizeof(raead), &raead);
15063293c61SHerbert Xu }
1516ad414feSSteffen Klassert
1521ae97820SHerbert Xu static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
153d8c34b94SGideon Israel Dsouza __maybe_unused;
crypto_aead_show(struct seq_file * m,struct crypto_alg * alg)1541ae97820SHerbert Xu static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
1551ae97820SHerbert Xu {
15663293c61SHerbert Xu struct aead_alg *aead = container_of(alg, struct aead_alg, base);
1571ae97820SHerbert Xu
1581ae97820SHerbert Xu seq_printf(m, "type : aead\n");
159189ed66eSHerbert Xu seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
160189ed66eSHerbert Xu "yes" : "no");
1611ae97820SHerbert Xu seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
1621ae97820SHerbert Xu seq_printf(m, "ivsize : %u\n", aead->ivsize);
1637ba683a6SHerbert Xu seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize);
16463293c61SHerbert Xu seq_printf(m, "geniv : <none>\n");
1651ae97820SHerbert Xu }
1661ae97820SHerbert Xu
crypto_aead_free_instance(struct crypto_instance * inst)167ba75e15fSHerbert Xu static void crypto_aead_free_instance(struct crypto_instance *inst)
168ba75e15fSHerbert Xu {
169ba75e15fSHerbert Xu struct aead_instance *aead = aead_instance(inst);
170ba75e15fSHerbert Xu
171ba75e15fSHerbert Xu aead->free(aead);
172ba75e15fSHerbert Xu }
173ba75e15fSHerbert Xu
174b0d955baSHerbert Xu static const struct crypto_type crypto_aead_type = {
1755d1d65f8SHerbert Xu .extsize = crypto_alg_extsize,
1765d1d65f8SHerbert Xu .init_tfm = crypto_aead_init_tfm,
177ba75e15fSHerbert Xu .free = crypto_aead_free_instance,
1781ae97820SHerbert Xu #ifdef CONFIG_PROC_FS
1791ae97820SHerbert Xu .show = crypto_aead_show,
1801ae97820SHerbert Xu #endif
181b8969a1bSOndrej Mosnacek #if IS_ENABLED(CONFIG_CRYPTO_USER)
1826ad414feSSteffen Klassert .report = crypto_aead_report,
183c0f9e01dSHerbert Xu #endif
18463293c61SHerbert Xu .maskclear = ~CRYPTO_ALG_TYPE_MASK,
1855d1d65f8SHerbert Xu .maskset = CRYPTO_ALG_TYPE_MASK,
1865d1d65f8SHerbert Xu .type = CRYPTO_ALG_TYPE_AEAD,
1875d1d65f8SHerbert Xu .tfmsize = offsetof(struct crypto_aead, base),
1881ae97820SHerbert Xu };
1891ae97820SHerbert Xu
crypto_grab_aead(struct crypto_aead_spawn * spawn,struct crypto_instance * inst,const char * name,u32 type,u32 mask)190cd900f0cSEric Biggers int crypto_grab_aead(struct crypto_aead_spawn *spawn,
191cd900f0cSEric Biggers struct crypto_instance *inst,
192cd900f0cSEric Biggers const char *name, u32 type, u32 mask)
193d29ce988SHerbert Xu {
1945d1d65f8SHerbert Xu spawn->base.frontend = &crypto_aead_type;
195de95c957SEric Biggers return crypto_grab_spawn(&spawn->base, inst, name, type, mask);
196d29ce988SHerbert Xu }
197d29ce988SHerbert Xu EXPORT_SYMBOL_GPL(crypto_grab_aead);
198d29ce988SHerbert Xu
crypto_alloc_aead(const char * alg_name,u32 type,u32 mask)199d29ce988SHerbert Xu struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
200d29ce988SHerbert Xu {
2015d1d65f8SHerbert Xu return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask);
202d29ce988SHerbert Xu }
203d29ce988SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alloc_aead);
204d29ce988SHerbert Xu
crypto_has_aead(const char * alg_name,u32 type,u32 mask)205534562e5SHerbert Xu int crypto_has_aead(const char *alg_name, u32 type, u32 mask)
206534562e5SHerbert Xu {
207534562e5SHerbert Xu return crypto_type_has_alg(alg_name, &crypto_aead_type, type, mask);
208534562e5SHerbert Xu }
209534562e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_has_aead);
210534562e5SHerbert Xu
aead_prepare_alg(struct aead_alg * alg)21163293c61SHerbert Xu static int aead_prepare_alg(struct aead_alg *alg)
21263293c61SHerbert Xu {
21363293c61SHerbert Xu struct crypto_alg *base = &alg->base;
21463293c61SHerbert Xu
2157a530aa9SHerbert Xu if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) >
2167a530aa9SHerbert Xu PAGE_SIZE / 8)
21763293c61SHerbert Xu return -EINVAL;
21863293c61SHerbert Xu
2197a530aa9SHerbert Xu if (!alg->chunksize)
2207a530aa9SHerbert Xu alg->chunksize = base->cra_blocksize;
2217a530aa9SHerbert Xu
222b0d955baSHerbert Xu base->cra_type = &crypto_aead_type;
22363293c61SHerbert Xu base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
22463293c61SHerbert Xu base->cra_flags |= CRYPTO_ALG_TYPE_AEAD;
22563293c61SHerbert Xu
22663293c61SHerbert Xu return 0;
22763293c61SHerbert Xu }
22863293c61SHerbert Xu
crypto_register_aead(struct aead_alg * alg)22963293c61SHerbert Xu int crypto_register_aead(struct aead_alg *alg)
23063293c61SHerbert Xu {
23163293c61SHerbert Xu struct crypto_alg *base = &alg->base;
23263293c61SHerbert Xu int err;
23363293c61SHerbert Xu
23463293c61SHerbert Xu err = aead_prepare_alg(alg);
23563293c61SHerbert Xu if (err)
23663293c61SHerbert Xu return err;
23763293c61SHerbert Xu
23863293c61SHerbert Xu return crypto_register_alg(base);
23963293c61SHerbert Xu }
24063293c61SHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_aead);
24163293c61SHerbert Xu
crypto_unregister_aead(struct aead_alg * alg)24243615369SHerbert Xu void crypto_unregister_aead(struct aead_alg *alg)
24363293c61SHerbert Xu {
24443615369SHerbert Xu crypto_unregister_alg(&alg->base);
24563293c61SHerbert Xu }
24663293c61SHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_aead);
24763293c61SHerbert Xu
crypto_register_aeads(struct aead_alg * algs,int count)248caab9461SHerbert Xu int crypto_register_aeads(struct aead_alg *algs, int count)
249caab9461SHerbert Xu {
250caab9461SHerbert Xu int i, ret;
251caab9461SHerbert Xu
252caab9461SHerbert Xu for (i = 0; i < count; i++) {
253caab9461SHerbert Xu ret = crypto_register_aead(&algs[i]);
254caab9461SHerbert Xu if (ret)
255caab9461SHerbert Xu goto err;
256caab9461SHerbert Xu }
257caab9461SHerbert Xu
258caab9461SHerbert Xu return 0;
259caab9461SHerbert Xu
260caab9461SHerbert Xu err:
261caab9461SHerbert Xu for (--i; i >= 0; --i)
262caab9461SHerbert Xu crypto_unregister_aead(&algs[i]);
263caab9461SHerbert Xu
264caab9461SHerbert Xu return ret;
265caab9461SHerbert Xu }
266caab9461SHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_aeads);
267caab9461SHerbert Xu
crypto_unregister_aeads(struct aead_alg * algs,int count)268caab9461SHerbert Xu void crypto_unregister_aeads(struct aead_alg *algs, int count)
269caab9461SHerbert Xu {
270caab9461SHerbert Xu int i;
271caab9461SHerbert Xu
272caab9461SHerbert Xu for (i = count - 1; i >= 0; --i)
273caab9461SHerbert Xu crypto_unregister_aead(&algs[i]);
274caab9461SHerbert Xu }
275caab9461SHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_aeads);
276caab9461SHerbert Xu
aead_register_instance(struct crypto_template * tmpl,struct aead_instance * inst)27763293c61SHerbert Xu int aead_register_instance(struct crypto_template *tmpl,
27863293c61SHerbert Xu struct aead_instance *inst)
27963293c61SHerbert Xu {
28063293c61SHerbert Xu int err;
28163293c61SHerbert Xu
282d4fdc2dfSEric Biggers if (WARN_ON(!inst->free))
283d4fdc2dfSEric Biggers return -EINVAL;
284d4fdc2dfSEric Biggers
28563293c61SHerbert Xu err = aead_prepare_alg(&inst->alg);
28663293c61SHerbert Xu if (err)
28763293c61SHerbert Xu return err;
28863293c61SHerbert Xu
28963293c61SHerbert Xu return crypto_register_instance(tmpl, aead_crypto_instance(inst));
29063293c61SHerbert Xu }
29163293c61SHerbert Xu EXPORT_SYMBOL_GPL(aead_register_instance);
29263293c61SHerbert Xu
2931ae97820SHerbert Xu MODULE_LICENSE("GPL");
2941ae97820SHerbert Xu MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
295