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