xref: /linux/crypto/aead.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
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