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