xref: /linux/crypto/aead.c (revision 29ce50e078b857977202205394f200a25889636e)
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 
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);
391ae97820SHerbert Xu 	memset(alignbuffer, 0, keylen);
401ae97820SHerbert Xu 	kfree(buffer);
411ae97820SHerbert Xu 	return ret;
421ae97820SHerbert Xu }
431ae97820SHerbert Xu 
445d1d65f8SHerbert Xu int crypto_aead_setkey(struct crypto_aead *tfm,
455d1d65f8SHerbert Xu 		       const u8 *key, unsigned int keylen)
461ae97820SHerbert Xu {
471ae97820SHerbert Xu 	unsigned long alignmask = crypto_aead_alignmask(tfm);
48dc26c17fSEric Biggers 	int err;
491ae97820SHerbert Xu 
501ae97820SHerbert Xu 	if ((unsigned long)key & alignmask)
51dc26c17fSEric Biggers 		err = setkey_unaligned(tfm, key, keylen);
52dc26c17fSEric Biggers 	else
53dc26c17fSEric Biggers 		err = crypto_aead_alg(tfm)->setkey(tfm, key, keylen);
541ae97820SHerbert Xu 
556ebc9700SEric Biggers 	if (unlikely(err)) {
566ebc9700SEric Biggers 		crypto_aead_set_flags(tfm, CRYPTO_TFM_NEED_KEY);
57dc26c17fSEric Biggers 		return err;
586ebc9700SEric Biggers 	}
59dc26c17fSEric Biggers 
60dc26c17fSEric Biggers 	crypto_aead_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
61dc26c17fSEric Biggers 	return 0;
621ae97820SHerbert Xu }
635d1d65f8SHerbert Xu EXPORT_SYMBOL_GPL(crypto_aead_setkey);
641ae97820SHerbert Xu 
657ba683a6SHerbert Xu int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
667ba683a6SHerbert Xu {
677ba683a6SHerbert Xu 	int err;
687ba683a6SHerbert Xu 
69a62084d2SPascal van Leeuwen 	if ((!authsize && crypto_aead_maxauthsize(tfm)) ||
70a62084d2SPascal van Leeuwen 	    authsize > crypto_aead_maxauthsize(tfm))
717ba683a6SHerbert Xu 		return -EINVAL;
727ba683a6SHerbert Xu 
73b0d955baSHerbert Xu 	if (crypto_aead_alg(tfm)->setauthsize) {
74b0d955baSHerbert Xu 		err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize);
757ba683a6SHerbert Xu 		if (err)
767ba683a6SHerbert Xu 			return err;
777ba683a6SHerbert Xu 	}
787ba683a6SHerbert Xu 
795d1d65f8SHerbert Xu 	tfm->authsize = authsize;
807ba683a6SHerbert Xu 	return 0;
817ba683a6SHerbert Xu }
827ba683a6SHerbert Xu EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
837ba683a6SHerbert Xu 
84f2fe1154SEric Biggers int crypto_aead_encrypt(struct aead_request *req)
85f2fe1154SEric Biggers {
86f2fe1154SEric Biggers 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
870df4adf8SHerbert Xu 
88f2fe1154SEric Biggers 	if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
89*29ce50e0SEric Biggers 		return -ENOKEY;
900df4adf8SHerbert Xu 
91*29ce50e0SEric Biggers 	return crypto_aead_alg(aead)->encrypt(req);
92f2fe1154SEric Biggers }
93f2fe1154SEric Biggers EXPORT_SYMBOL_GPL(crypto_aead_encrypt);
94f2fe1154SEric Biggers 
95f2fe1154SEric Biggers int crypto_aead_decrypt(struct aead_request *req)
96f2fe1154SEric Biggers {
97f2fe1154SEric Biggers 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
980df4adf8SHerbert Xu 
99f2fe1154SEric Biggers 	if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
100*29ce50e0SEric Biggers 		return -ENOKEY;
1010df4adf8SHerbert Xu 
102*29ce50e0SEric Biggers 	if (req->cryptlen < crypto_aead_authsize(aead))
103*29ce50e0SEric Biggers 		return -EINVAL;
104*29ce50e0SEric Biggers 
105*29ce50e0SEric Biggers 	return crypto_aead_alg(aead)->decrypt(req);
106f2fe1154SEric Biggers }
107f2fe1154SEric Biggers EXPORT_SYMBOL_GPL(crypto_aead_decrypt);
108f2fe1154SEric Biggers 
1095eb8ec6dSHerbert Xu static void crypto_aead_exit_tfm(struct crypto_tfm *tfm)
1105eb8ec6dSHerbert Xu {
1115eb8ec6dSHerbert Xu 	struct crypto_aead *aead = __crypto_aead_cast(tfm);
1125eb8ec6dSHerbert Xu 	struct aead_alg *alg = crypto_aead_alg(aead);
1135eb8ec6dSHerbert Xu 
1145eb8ec6dSHerbert Xu 	alg->exit(aead);
1155eb8ec6dSHerbert Xu }
1165eb8ec6dSHerbert Xu 
11763293c61SHerbert Xu static int crypto_aead_init_tfm(struct crypto_tfm *tfm)
11863293c61SHerbert Xu {
11963293c61SHerbert Xu 	struct crypto_aead *aead = __crypto_aead_cast(tfm);
12063293c61SHerbert Xu 	struct aead_alg *alg = crypto_aead_alg(aead);
12163293c61SHerbert Xu 
122dc26c17fSEric Biggers 	crypto_aead_set_flags(aead, CRYPTO_TFM_NEED_KEY);
123dc26c17fSEric Biggers 
12463293c61SHerbert Xu 	aead->authsize = alg->maxauthsize;
12563293c61SHerbert Xu 
1265eb8ec6dSHerbert Xu 	if (alg->exit)
1275eb8ec6dSHerbert Xu 		aead->base.exit = crypto_aead_exit_tfm;
1285eb8ec6dSHerbert Xu 
1295eb8ec6dSHerbert Xu 	if (alg->init)
1305eb8ec6dSHerbert Xu 		return alg->init(aead);
1315eb8ec6dSHerbert Xu 
13263293c61SHerbert Xu 	return 0;
13363293c61SHerbert Xu }
13463293c61SHerbert Xu 
135c0f9e01dSHerbert Xu static int __maybe_unused crypto_aead_report(
136c0f9e01dSHerbert Xu 	struct sk_buff *skb, struct crypto_alg *alg)
13763293c61SHerbert Xu {
13863293c61SHerbert Xu 	struct crypto_report_aead raead;
13963293c61SHerbert Xu 	struct aead_alg *aead = container_of(alg, struct aead_alg, base);
14063293c61SHerbert Xu 
14137db69e0SEric Biggers 	memset(&raead, 0, sizeof(raead));
14237db69e0SEric Biggers 
14337db69e0SEric Biggers 	strscpy(raead.type, "aead", sizeof(raead.type));
14437db69e0SEric Biggers 	strscpy(raead.geniv, "<none>", sizeof(raead.geniv));
14563293c61SHerbert Xu 
14663293c61SHerbert Xu 	raead.blocksize = alg->cra_blocksize;
14763293c61SHerbert Xu 	raead.maxauthsize = aead->maxauthsize;
14863293c61SHerbert Xu 	raead.ivsize = aead->ivsize;
14963293c61SHerbert Xu 
15037db69e0SEric Biggers 	return nla_put(skb, CRYPTOCFGA_REPORT_AEAD, sizeof(raead), &raead);
15163293c61SHerbert Xu }
1526ad414feSSteffen Klassert 
1531ae97820SHerbert Xu static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
154d8c34b94SGideon Israel Dsouza 	__maybe_unused;
1551ae97820SHerbert Xu static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
1561ae97820SHerbert Xu {
15763293c61SHerbert Xu 	struct aead_alg *aead = container_of(alg, struct aead_alg, base);
1581ae97820SHerbert Xu 
1591ae97820SHerbert Xu 	seq_printf(m, "type         : aead\n");
160189ed66eSHerbert Xu 	seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
161189ed66eSHerbert Xu 					     "yes" : "no");
1621ae97820SHerbert Xu 	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
1631ae97820SHerbert Xu 	seq_printf(m, "ivsize       : %u\n", aead->ivsize);
1647ba683a6SHerbert Xu 	seq_printf(m, "maxauthsize  : %u\n", aead->maxauthsize);
16563293c61SHerbert Xu 	seq_printf(m, "geniv        : <none>\n");
1661ae97820SHerbert Xu }
1671ae97820SHerbert Xu 
168ba75e15fSHerbert Xu static void crypto_aead_free_instance(struct crypto_instance *inst)
169ba75e15fSHerbert Xu {
170ba75e15fSHerbert Xu 	struct aead_instance *aead = aead_instance(inst);
171ba75e15fSHerbert Xu 
172ba75e15fSHerbert Xu 	aead->free(aead);
173ba75e15fSHerbert Xu }
174ba75e15fSHerbert Xu 
175b0d955baSHerbert Xu static const struct crypto_type crypto_aead_type = {
1765d1d65f8SHerbert Xu 	.extsize = crypto_alg_extsize,
1775d1d65f8SHerbert Xu 	.init_tfm = crypto_aead_init_tfm,
178ba75e15fSHerbert Xu 	.free = crypto_aead_free_instance,
1791ae97820SHerbert Xu #ifdef CONFIG_PROC_FS
1801ae97820SHerbert Xu 	.show = crypto_aead_show,
1811ae97820SHerbert Xu #endif
182b8969a1bSOndrej Mosnacek #if IS_ENABLED(CONFIG_CRYPTO_USER)
1836ad414feSSteffen Klassert 	.report = crypto_aead_report,
184c0f9e01dSHerbert Xu #endif
18563293c61SHerbert Xu 	.maskclear = ~CRYPTO_ALG_TYPE_MASK,
1865d1d65f8SHerbert Xu 	.maskset = CRYPTO_ALG_TYPE_MASK,
1875d1d65f8SHerbert Xu 	.type = CRYPTO_ALG_TYPE_AEAD,
1885d1d65f8SHerbert Xu 	.tfmsize = offsetof(struct crypto_aead, base),
1891ae97820SHerbert Xu };
1901ae97820SHerbert Xu 
191cd900f0cSEric Biggers int crypto_grab_aead(struct crypto_aead_spawn *spawn,
192cd900f0cSEric Biggers 		     struct crypto_instance *inst,
193cd900f0cSEric Biggers 		     const char *name, u32 type, u32 mask)
194d29ce988SHerbert Xu {
1955d1d65f8SHerbert Xu 	spawn->base.frontend = &crypto_aead_type;
196de95c957SEric Biggers 	return crypto_grab_spawn(&spawn->base, inst, name, type, mask);
197d29ce988SHerbert Xu }
198d29ce988SHerbert Xu EXPORT_SYMBOL_GPL(crypto_grab_aead);
199d29ce988SHerbert Xu 
200d29ce988SHerbert Xu struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
201d29ce988SHerbert Xu {
2025d1d65f8SHerbert Xu 	return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask);
203d29ce988SHerbert Xu }
204d29ce988SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alloc_aead);
205d29ce988SHerbert Xu 
206534562e5SHerbert Xu int crypto_has_aead(const char *alg_name, u32 type, u32 mask)
207534562e5SHerbert Xu {
208534562e5SHerbert Xu 	return crypto_type_has_alg(alg_name, &crypto_aead_type, type, mask);
209534562e5SHerbert Xu }
210534562e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_has_aead);
211534562e5SHerbert Xu 
21263293c61SHerbert Xu static int aead_prepare_alg(struct aead_alg *alg)
21363293c61SHerbert Xu {
21463293c61SHerbert Xu 	struct crypto_alg *base = &alg->base;
21563293c61SHerbert Xu 
2167a530aa9SHerbert Xu 	if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) >
2177a530aa9SHerbert Xu 	    PAGE_SIZE / 8)
21863293c61SHerbert Xu 		return -EINVAL;
21963293c61SHerbert Xu 
2207a530aa9SHerbert Xu 	if (!alg->chunksize)
2217a530aa9SHerbert Xu 		alg->chunksize = base->cra_blocksize;
2227a530aa9SHerbert Xu 
223b0d955baSHerbert Xu 	base->cra_type = &crypto_aead_type;
22463293c61SHerbert Xu 	base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
22563293c61SHerbert Xu 	base->cra_flags |= CRYPTO_ALG_TYPE_AEAD;
22663293c61SHerbert Xu 
22763293c61SHerbert Xu 	return 0;
22863293c61SHerbert Xu }
22963293c61SHerbert Xu 
23063293c61SHerbert Xu int crypto_register_aead(struct aead_alg *alg)
23163293c61SHerbert Xu {
23263293c61SHerbert Xu 	struct crypto_alg *base = &alg->base;
23363293c61SHerbert Xu 	int err;
23463293c61SHerbert Xu 
23563293c61SHerbert Xu 	err = aead_prepare_alg(alg);
23663293c61SHerbert Xu 	if (err)
23763293c61SHerbert Xu 		return err;
23863293c61SHerbert Xu 
23963293c61SHerbert Xu 	return crypto_register_alg(base);
24063293c61SHerbert Xu }
24163293c61SHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_aead);
24263293c61SHerbert Xu 
24343615369SHerbert Xu void crypto_unregister_aead(struct aead_alg *alg)
24463293c61SHerbert Xu {
24543615369SHerbert Xu 	crypto_unregister_alg(&alg->base);
24663293c61SHerbert Xu }
24763293c61SHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_aead);
24863293c61SHerbert Xu 
249caab9461SHerbert Xu int crypto_register_aeads(struct aead_alg *algs, int count)
250caab9461SHerbert Xu {
251caab9461SHerbert Xu 	int i, ret;
252caab9461SHerbert Xu 
253caab9461SHerbert Xu 	for (i = 0; i < count; i++) {
254caab9461SHerbert Xu 		ret = crypto_register_aead(&algs[i]);
255caab9461SHerbert Xu 		if (ret)
256caab9461SHerbert Xu 			goto err;
257caab9461SHerbert Xu 	}
258caab9461SHerbert Xu 
259caab9461SHerbert Xu 	return 0;
260caab9461SHerbert Xu 
261caab9461SHerbert Xu err:
262caab9461SHerbert Xu 	for (--i; i >= 0; --i)
263caab9461SHerbert Xu 		crypto_unregister_aead(&algs[i]);
264caab9461SHerbert Xu 
265caab9461SHerbert Xu 	return ret;
266caab9461SHerbert Xu }
267caab9461SHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_aeads);
268caab9461SHerbert Xu 
269caab9461SHerbert Xu void crypto_unregister_aeads(struct aead_alg *algs, int count)
270caab9461SHerbert Xu {
271caab9461SHerbert Xu 	int i;
272caab9461SHerbert Xu 
273caab9461SHerbert Xu 	for (i = count - 1; i >= 0; --i)
274caab9461SHerbert Xu 		crypto_unregister_aead(&algs[i]);
275caab9461SHerbert Xu }
276caab9461SHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_aeads);
277caab9461SHerbert Xu 
27863293c61SHerbert Xu int aead_register_instance(struct crypto_template *tmpl,
27963293c61SHerbert Xu 			   struct aead_instance *inst)
28063293c61SHerbert Xu {
28163293c61SHerbert Xu 	int err;
28263293c61SHerbert Xu 
283d4fdc2dfSEric Biggers 	if (WARN_ON(!inst->free))
284d4fdc2dfSEric Biggers 		return -EINVAL;
285d4fdc2dfSEric Biggers 
28663293c61SHerbert Xu 	err = aead_prepare_alg(&inst->alg);
28763293c61SHerbert Xu 	if (err)
28863293c61SHerbert Xu 		return err;
28963293c61SHerbert Xu 
29063293c61SHerbert Xu 	return crypto_register_instance(tmpl, aead_crypto_instance(inst));
29163293c61SHerbert Xu }
29263293c61SHerbert Xu EXPORT_SYMBOL_GPL(aead_register_instance);
29363293c61SHerbert Xu 
2941ae97820SHerbert Xu MODULE_LICENSE("GPL");
2951ae97820SHerbert Xu MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
296