18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AEAD: Authenticated Encryption with Associated Data
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This file provides API support for AEAD algorithms.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2007-2015 Herbert Xu <herbert@gondor.apana.org.au>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h>
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
178c2ecf20Sopenharmony_ci#include <linux/cryptouser.h>
188c2ecf20Sopenharmony_ci#include <net/netlink.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "internal.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
238c2ecf20Sopenharmony_ci			    unsigned int keylen)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	unsigned long alignmask = crypto_aead_alignmask(tfm);
268c2ecf20Sopenharmony_ci	int ret;
278c2ecf20Sopenharmony_ci	u8 *buffer, *alignbuffer;
288c2ecf20Sopenharmony_ci	unsigned long absize;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	absize = keylen + alignmask;
318c2ecf20Sopenharmony_ci	buffer = kmalloc(absize, GFP_ATOMIC);
328c2ecf20Sopenharmony_ci	if (!buffer)
338c2ecf20Sopenharmony_ci		return -ENOMEM;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
368c2ecf20Sopenharmony_ci	memcpy(alignbuffer, key, keylen);
378c2ecf20Sopenharmony_ci	ret = crypto_aead_alg(tfm)->setkey(tfm, alignbuffer, keylen);
388c2ecf20Sopenharmony_ci	kfree_sensitive(buffer);
398c2ecf20Sopenharmony_ci	return ret;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ciint crypto_aead_setkey(struct crypto_aead *tfm,
438c2ecf20Sopenharmony_ci		       const u8 *key, unsigned int keylen)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	unsigned long alignmask = crypto_aead_alignmask(tfm);
468c2ecf20Sopenharmony_ci	int err;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if ((unsigned long)key & alignmask)
498c2ecf20Sopenharmony_ci		err = setkey_unaligned(tfm, key, keylen);
508c2ecf20Sopenharmony_ci	else
518c2ecf20Sopenharmony_ci		err = crypto_aead_alg(tfm)->setkey(tfm, key, keylen);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (unlikely(err)) {
548c2ecf20Sopenharmony_ci		crypto_aead_set_flags(tfm, CRYPTO_TFM_NEED_KEY);
558c2ecf20Sopenharmony_ci		return err;
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	crypto_aead_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
598c2ecf20Sopenharmony_ci	return 0;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_aead_setkey);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ciint crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	int err;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if ((!authsize && crypto_aead_maxauthsize(tfm)) ||
688c2ecf20Sopenharmony_ci	    authsize > crypto_aead_maxauthsize(tfm))
698c2ecf20Sopenharmony_ci		return -EINVAL;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (crypto_aead_alg(tfm)->setauthsize) {
728c2ecf20Sopenharmony_ci		err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize);
738c2ecf20Sopenharmony_ci		if (err)
748c2ecf20Sopenharmony_ci			return err;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	tfm->authsize = authsize;
788c2ecf20Sopenharmony_ci	return 0;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciint crypto_aead_encrypt(struct aead_request *req)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
858c2ecf20Sopenharmony_ci	struct crypto_alg *alg = aead->base.__crt_alg;
868c2ecf20Sopenharmony_ci	unsigned int cryptlen = req->cryptlen;
878c2ecf20Sopenharmony_ci	int ret;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	crypto_stats_get(alg);
908c2ecf20Sopenharmony_ci	if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
918c2ecf20Sopenharmony_ci		ret = -ENOKEY;
928c2ecf20Sopenharmony_ci	else
938c2ecf20Sopenharmony_ci		ret = crypto_aead_alg(aead)->encrypt(req);
948c2ecf20Sopenharmony_ci	crypto_stats_aead_encrypt(cryptlen, alg, ret);
958c2ecf20Sopenharmony_ci	return ret;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_aead_encrypt);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint crypto_aead_decrypt(struct aead_request *req)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
1028c2ecf20Sopenharmony_ci	struct crypto_alg *alg = aead->base.__crt_alg;
1038c2ecf20Sopenharmony_ci	unsigned int cryptlen = req->cryptlen;
1048c2ecf20Sopenharmony_ci	int ret;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	crypto_stats_get(alg);
1078c2ecf20Sopenharmony_ci	if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
1088c2ecf20Sopenharmony_ci		ret = -ENOKEY;
1098c2ecf20Sopenharmony_ci	else if (req->cryptlen < crypto_aead_authsize(aead))
1108c2ecf20Sopenharmony_ci		ret = -EINVAL;
1118c2ecf20Sopenharmony_ci	else
1128c2ecf20Sopenharmony_ci		ret = crypto_aead_alg(aead)->decrypt(req);
1138c2ecf20Sopenharmony_ci	crypto_stats_aead_decrypt(cryptlen, alg, ret);
1148c2ecf20Sopenharmony_ci	return ret;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_aead_decrypt);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic void crypto_aead_exit_tfm(struct crypto_tfm *tfm)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	struct crypto_aead *aead = __crypto_aead_cast(tfm);
1218c2ecf20Sopenharmony_ci	struct aead_alg *alg = crypto_aead_alg(aead);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	alg->exit(aead);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic int crypto_aead_init_tfm(struct crypto_tfm *tfm)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct crypto_aead *aead = __crypto_aead_cast(tfm);
1298c2ecf20Sopenharmony_ci	struct aead_alg *alg = crypto_aead_alg(aead);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	crypto_aead_set_flags(aead, CRYPTO_TFM_NEED_KEY);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	aead->authsize = alg->maxauthsize;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (alg->exit)
1368c2ecf20Sopenharmony_ci		aead->base.exit = crypto_aead_exit_tfm;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (alg->init)
1398c2ecf20Sopenharmony_ci		return alg->init(aead);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return 0;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci#ifdef CONFIG_NET
1458c2ecf20Sopenharmony_cistatic int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct crypto_report_aead raead;
1488c2ecf20Sopenharmony_ci	struct aead_alg *aead = container_of(alg, struct aead_alg, base);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	memset(&raead, 0, sizeof(raead));
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	strscpy(raead.type, "aead", sizeof(raead.type));
1538c2ecf20Sopenharmony_ci	strscpy(raead.geniv, "<none>", sizeof(raead.geniv));
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	raead.blocksize = alg->cra_blocksize;
1568c2ecf20Sopenharmony_ci	raead.maxauthsize = aead->maxauthsize;
1578c2ecf20Sopenharmony_ci	raead.ivsize = aead->ivsize;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	return nla_put(skb, CRYPTOCFGA_REPORT_AEAD, sizeof(raead), &raead);
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci#else
1628c2ecf20Sopenharmony_cistatic int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	return -ENOSYS;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci#endif
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
1698c2ecf20Sopenharmony_ci	__maybe_unused;
1708c2ecf20Sopenharmony_cistatic void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	struct aead_alg *aead = container_of(alg, struct aead_alg, base);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	seq_printf(m, "type         : aead\n");
1758c2ecf20Sopenharmony_ci	seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
1768c2ecf20Sopenharmony_ci					     "yes" : "no");
1778c2ecf20Sopenharmony_ci	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
1788c2ecf20Sopenharmony_ci	seq_printf(m, "ivsize       : %u\n", aead->ivsize);
1798c2ecf20Sopenharmony_ci	seq_printf(m, "maxauthsize  : %u\n", aead->maxauthsize);
1808c2ecf20Sopenharmony_ci	seq_printf(m, "geniv        : <none>\n");
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic void crypto_aead_free_instance(struct crypto_instance *inst)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	struct aead_instance *aead = aead_instance(inst);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	aead->free(aead);
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic const struct crypto_type crypto_aead_type = {
1918c2ecf20Sopenharmony_ci	.extsize = crypto_alg_extsize,
1928c2ecf20Sopenharmony_ci	.init_tfm = crypto_aead_init_tfm,
1938c2ecf20Sopenharmony_ci	.free = crypto_aead_free_instance,
1948c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
1958c2ecf20Sopenharmony_ci	.show = crypto_aead_show,
1968c2ecf20Sopenharmony_ci#endif
1978c2ecf20Sopenharmony_ci	.report = crypto_aead_report,
1988c2ecf20Sopenharmony_ci	.maskclear = ~CRYPTO_ALG_TYPE_MASK,
1998c2ecf20Sopenharmony_ci	.maskset = CRYPTO_ALG_TYPE_MASK,
2008c2ecf20Sopenharmony_ci	.type = CRYPTO_ALG_TYPE_AEAD,
2018c2ecf20Sopenharmony_ci	.tfmsize = offsetof(struct crypto_aead, base),
2028c2ecf20Sopenharmony_ci};
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ciint crypto_grab_aead(struct crypto_aead_spawn *spawn,
2058c2ecf20Sopenharmony_ci		     struct crypto_instance *inst,
2068c2ecf20Sopenharmony_ci		     const char *name, u32 type, u32 mask)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	spawn->base.frontend = &crypto_aead_type;
2098c2ecf20Sopenharmony_ci	return crypto_grab_spawn(&spawn->base, inst, name, type, mask);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_grab_aead);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistruct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_alloc_aead);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic int aead_prepare_alg(struct aead_alg *alg)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct crypto_alg *base = &alg->base;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) >
2248c2ecf20Sopenharmony_ci	    PAGE_SIZE / 8)
2258c2ecf20Sopenharmony_ci		return -EINVAL;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (!alg->chunksize)
2288c2ecf20Sopenharmony_ci		alg->chunksize = base->cra_blocksize;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	base->cra_type = &crypto_aead_type;
2318c2ecf20Sopenharmony_ci	base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
2328c2ecf20Sopenharmony_ci	base->cra_flags |= CRYPTO_ALG_TYPE_AEAD;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return 0;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ciint crypto_register_aead(struct aead_alg *alg)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct crypto_alg *base = &alg->base;
2408c2ecf20Sopenharmony_ci	int err;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	err = aead_prepare_alg(alg);
2438c2ecf20Sopenharmony_ci	if (err)
2448c2ecf20Sopenharmony_ci		return err;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return crypto_register_alg(base);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_register_aead);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_civoid crypto_unregister_aead(struct aead_alg *alg)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	crypto_unregister_alg(&alg->base);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_unregister_aead);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ciint crypto_register_aeads(struct aead_alg *algs, int count)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	int i, ret;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
2618c2ecf20Sopenharmony_ci		ret = crypto_register_aead(&algs[i]);
2628c2ecf20Sopenharmony_ci		if (ret)
2638c2ecf20Sopenharmony_ci			goto err;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	return 0;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cierr:
2698c2ecf20Sopenharmony_ci	for (--i; i >= 0; --i)
2708c2ecf20Sopenharmony_ci		crypto_unregister_aead(&algs[i]);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	return ret;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_register_aeads);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_civoid crypto_unregister_aeads(struct aead_alg *algs, int count)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	int i;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	for (i = count - 1; i >= 0; --i)
2818c2ecf20Sopenharmony_ci		crypto_unregister_aead(&algs[i]);
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_unregister_aeads);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ciint aead_register_instance(struct crypto_template *tmpl,
2868c2ecf20Sopenharmony_ci			   struct aead_instance *inst)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	int err;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (WARN_ON(!inst->free))
2918c2ecf20Sopenharmony_ci		return -EINVAL;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	err = aead_prepare_alg(&inst->alg);
2948c2ecf20Sopenharmony_ci	if (err)
2958c2ecf20Sopenharmony_ci		return err;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return crypto_register_instance(tmpl, aead_crypto_instance(inst));
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(aead_register_instance);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
3028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
303