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> 11*0df4adf8SHerbert 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> 18*0df4adf8SHerbert Xu #include <linux/string.h> 196ad414feSSteffen Klassert #include <net/netlink.h> 201ae97820SHerbert Xu 215b6d2d7fSHerbert Xu #include "internal.h" 225b6d2d7fSHerbert Xu 23*0df4adf8SHerbert Xu static inline struct crypto_istat_aead *aead_get_stat(struct aead_alg *alg) 24*0df4adf8SHerbert Xu { 25*0df4adf8SHerbert Xu #ifdef CONFIG_CRYPTO_STATS 26*0df4adf8SHerbert Xu return &alg->stat; 27*0df4adf8SHerbert Xu #else 28*0df4adf8SHerbert Xu return NULL; 29*0df4adf8SHerbert Xu #endif 30*0df4adf8SHerbert Xu } 31*0df4adf8SHerbert Xu 321ae97820SHerbert Xu static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, 331ae97820SHerbert Xu unsigned int keylen) 341ae97820SHerbert Xu { 351ae97820SHerbert Xu unsigned long alignmask = crypto_aead_alignmask(tfm); 361ae97820SHerbert Xu int ret; 371ae97820SHerbert Xu u8 *buffer, *alignbuffer; 381ae97820SHerbert Xu unsigned long absize; 391ae97820SHerbert Xu 401ae97820SHerbert Xu absize = keylen + alignmask; 411ae97820SHerbert Xu buffer = kmalloc(absize, GFP_ATOMIC); 421ae97820SHerbert Xu if (!buffer) 431ae97820SHerbert Xu return -ENOMEM; 441ae97820SHerbert Xu 451ae97820SHerbert Xu alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 461ae97820SHerbert Xu memcpy(alignbuffer, key, keylen); 47b0d955baSHerbert Xu ret = crypto_aead_alg(tfm)->setkey(tfm, alignbuffer, keylen); 481ae97820SHerbert Xu memset(alignbuffer, 0, keylen); 491ae97820SHerbert Xu kfree(buffer); 501ae97820SHerbert Xu return ret; 511ae97820SHerbert Xu } 521ae97820SHerbert Xu 535d1d65f8SHerbert Xu int crypto_aead_setkey(struct crypto_aead *tfm, 545d1d65f8SHerbert Xu const u8 *key, unsigned int keylen) 551ae97820SHerbert Xu { 561ae97820SHerbert Xu unsigned long alignmask = crypto_aead_alignmask(tfm); 57dc26c17fSEric Biggers int err; 581ae97820SHerbert Xu 591ae97820SHerbert Xu if ((unsigned long)key & alignmask) 60dc26c17fSEric Biggers err = setkey_unaligned(tfm, key, keylen); 61dc26c17fSEric Biggers else 62dc26c17fSEric Biggers err = crypto_aead_alg(tfm)->setkey(tfm, key, keylen); 631ae97820SHerbert Xu 646ebc9700SEric Biggers if (unlikely(err)) { 656ebc9700SEric Biggers crypto_aead_set_flags(tfm, CRYPTO_TFM_NEED_KEY); 66dc26c17fSEric Biggers return err; 676ebc9700SEric Biggers } 68dc26c17fSEric Biggers 69dc26c17fSEric Biggers crypto_aead_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); 70dc26c17fSEric Biggers return 0; 711ae97820SHerbert Xu } 725d1d65f8SHerbert Xu EXPORT_SYMBOL_GPL(crypto_aead_setkey); 731ae97820SHerbert Xu 747ba683a6SHerbert Xu int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 757ba683a6SHerbert Xu { 767ba683a6SHerbert Xu int err; 777ba683a6SHerbert Xu 78a62084d2SPascal van Leeuwen if ((!authsize && crypto_aead_maxauthsize(tfm)) || 79a62084d2SPascal van Leeuwen authsize > crypto_aead_maxauthsize(tfm)) 807ba683a6SHerbert Xu return -EINVAL; 817ba683a6SHerbert Xu 82b0d955baSHerbert Xu if (crypto_aead_alg(tfm)->setauthsize) { 83b0d955baSHerbert Xu err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize); 847ba683a6SHerbert Xu if (err) 857ba683a6SHerbert Xu return err; 867ba683a6SHerbert Xu } 877ba683a6SHerbert Xu 885d1d65f8SHerbert Xu tfm->authsize = authsize; 897ba683a6SHerbert Xu return 0; 907ba683a6SHerbert Xu } 917ba683a6SHerbert Xu EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); 927ba683a6SHerbert Xu 93*0df4adf8SHerbert Xu static inline int crypto_aead_errstat(struct crypto_istat_aead *istat, int err) 94*0df4adf8SHerbert Xu { 95*0df4adf8SHerbert Xu if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) 96*0df4adf8SHerbert Xu return err; 97*0df4adf8SHerbert Xu 98*0df4adf8SHerbert Xu if (err && err != -EINPROGRESS && err != -EBUSY) 99*0df4adf8SHerbert Xu atomic64_inc(&istat->err_cnt); 100*0df4adf8SHerbert Xu 101*0df4adf8SHerbert Xu return err; 102*0df4adf8SHerbert Xu } 103*0df4adf8SHerbert Xu 104f2fe1154SEric Biggers int crypto_aead_encrypt(struct aead_request *req) 105f2fe1154SEric Biggers { 106f2fe1154SEric Biggers struct crypto_aead *aead = crypto_aead_reqtfm(req); 107*0df4adf8SHerbert Xu struct aead_alg *alg = crypto_aead_alg(aead); 108*0df4adf8SHerbert Xu struct crypto_istat_aead *istat; 109f2fe1154SEric Biggers int ret; 110f2fe1154SEric Biggers 111*0df4adf8SHerbert Xu istat = aead_get_stat(alg); 112*0df4adf8SHerbert Xu 113*0df4adf8SHerbert Xu if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { 114*0df4adf8SHerbert Xu atomic64_inc(&istat->encrypt_cnt); 115*0df4adf8SHerbert Xu atomic64_add(req->cryptlen, &istat->encrypt_tlen); 116*0df4adf8SHerbert Xu } 117*0df4adf8SHerbert Xu 118f2fe1154SEric Biggers if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) 119f2fe1154SEric Biggers ret = -ENOKEY; 120f2fe1154SEric Biggers else 121*0df4adf8SHerbert Xu ret = alg->encrypt(req); 122*0df4adf8SHerbert Xu 123*0df4adf8SHerbert Xu return crypto_aead_errstat(istat, ret); 124f2fe1154SEric Biggers } 125f2fe1154SEric Biggers EXPORT_SYMBOL_GPL(crypto_aead_encrypt); 126f2fe1154SEric Biggers 127f2fe1154SEric Biggers int crypto_aead_decrypt(struct aead_request *req) 128f2fe1154SEric Biggers { 129f2fe1154SEric Biggers struct crypto_aead *aead = crypto_aead_reqtfm(req); 130*0df4adf8SHerbert Xu struct aead_alg *alg = crypto_aead_alg(aead); 131*0df4adf8SHerbert Xu struct crypto_istat_aead *istat; 132f2fe1154SEric Biggers int ret; 133f2fe1154SEric Biggers 134*0df4adf8SHerbert Xu istat = aead_get_stat(alg); 135*0df4adf8SHerbert Xu 136*0df4adf8SHerbert Xu if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { 137*0df4adf8SHerbert Xu atomic64_inc(&istat->encrypt_cnt); 138*0df4adf8SHerbert Xu atomic64_add(req->cryptlen, &istat->encrypt_tlen); 139*0df4adf8SHerbert Xu } 140*0df4adf8SHerbert Xu 141f2fe1154SEric Biggers if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) 142f2fe1154SEric Biggers ret = -ENOKEY; 143f2fe1154SEric Biggers else if (req->cryptlen < crypto_aead_authsize(aead)) 144f2fe1154SEric Biggers ret = -EINVAL; 145f2fe1154SEric Biggers else 146*0df4adf8SHerbert Xu ret = alg->decrypt(req); 147*0df4adf8SHerbert Xu 148*0df4adf8SHerbert Xu return crypto_aead_errstat(istat, ret); 149f2fe1154SEric Biggers } 150f2fe1154SEric Biggers EXPORT_SYMBOL_GPL(crypto_aead_decrypt); 151f2fe1154SEric Biggers 1525eb8ec6dSHerbert Xu static void crypto_aead_exit_tfm(struct crypto_tfm *tfm) 1535eb8ec6dSHerbert Xu { 1545eb8ec6dSHerbert Xu struct crypto_aead *aead = __crypto_aead_cast(tfm); 1555eb8ec6dSHerbert Xu struct aead_alg *alg = crypto_aead_alg(aead); 1565eb8ec6dSHerbert Xu 1575eb8ec6dSHerbert Xu alg->exit(aead); 1585eb8ec6dSHerbert Xu } 1595eb8ec6dSHerbert Xu 16063293c61SHerbert Xu static int crypto_aead_init_tfm(struct crypto_tfm *tfm) 16163293c61SHerbert Xu { 16263293c61SHerbert Xu struct crypto_aead *aead = __crypto_aead_cast(tfm); 16363293c61SHerbert Xu struct aead_alg *alg = crypto_aead_alg(aead); 16463293c61SHerbert Xu 165dc26c17fSEric Biggers crypto_aead_set_flags(aead, CRYPTO_TFM_NEED_KEY); 166dc26c17fSEric Biggers 16763293c61SHerbert Xu aead->authsize = alg->maxauthsize; 16863293c61SHerbert Xu 1695eb8ec6dSHerbert Xu if (alg->exit) 1705eb8ec6dSHerbert Xu aead->base.exit = crypto_aead_exit_tfm; 1715eb8ec6dSHerbert Xu 1725eb8ec6dSHerbert Xu if (alg->init) 1735eb8ec6dSHerbert Xu return alg->init(aead); 1745eb8ec6dSHerbert Xu 17563293c61SHerbert Xu return 0; 17663293c61SHerbert Xu } 17763293c61SHerbert Xu 1783acc8473SHerbert Xu #ifdef CONFIG_NET 17963293c61SHerbert Xu static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) 18063293c61SHerbert Xu { 18163293c61SHerbert Xu struct crypto_report_aead raead; 18263293c61SHerbert Xu struct aead_alg *aead = container_of(alg, struct aead_alg, base); 18363293c61SHerbert Xu 18437db69e0SEric Biggers memset(&raead, 0, sizeof(raead)); 18537db69e0SEric Biggers 18637db69e0SEric Biggers strscpy(raead.type, "aead", sizeof(raead.type)); 18737db69e0SEric Biggers strscpy(raead.geniv, "<none>", sizeof(raead.geniv)); 18863293c61SHerbert Xu 18963293c61SHerbert Xu raead.blocksize = alg->cra_blocksize; 19063293c61SHerbert Xu raead.maxauthsize = aead->maxauthsize; 19163293c61SHerbert Xu raead.ivsize = aead->ivsize; 19263293c61SHerbert Xu 19337db69e0SEric Biggers return nla_put(skb, CRYPTOCFGA_REPORT_AEAD, sizeof(raead), &raead); 19463293c61SHerbert Xu } 19563293c61SHerbert Xu #else 1963acc8473SHerbert Xu static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) 1973acc8473SHerbert Xu { 1983acc8473SHerbert Xu return -ENOSYS; 1993acc8473SHerbert Xu } 2003acc8473SHerbert Xu #endif 2016ad414feSSteffen Klassert 2021ae97820SHerbert Xu static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) 203d8c34b94SGideon Israel Dsouza __maybe_unused; 2041ae97820SHerbert Xu static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) 2051ae97820SHerbert Xu { 20663293c61SHerbert Xu struct aead_alg *aead = container_of(alg, struct aead_alg, base); 2071ae97820SHerbert Xu 2081ae97820SHerbert Xu seq_printf(m, "type : aead\n"); 209189ed66eSHerbert Xu seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? 210189ed66eSHerbert Xu "yes" : "no"); 2111ae97820SHerbert Xu seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); 2121ae97820SHerbert Xu seq_printf(m, "ivsize : %u\n", aead->ivsize); 2137ba683a6SHerbert Xu seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); 21463293c61SHerbert Xu seq_printf(m, "geniv : <none>\n"); 2151ae97820SHerbert Xu } 2161ae97820SHerbert Xu 217ba75e15fSHerbert Xu static void crypto_aead_free_instance(struct crypto_instance *inst) 218ba75e15fSHerbert Xu { 219ba75e15fSHerbert Xu struct aead_instance *aead = aead_instance(inst); 220ba75e15fSHerbert Xu 221ba75e15fSHerbert Xu aead->free(aead); 222ba75e15fSHerbert Xu } 223ba75e15fSHerbert Xu 224*0df4adf8SHerbert Xu static int __maybe_unused crypto_aead_report_stat( 225*0df4adf8SHerbert Xu struct sk_buff *skb, struct crypto_alg *alg) 226*0df4adf8SHerbert Xu { 227*0df4adf8SHerbert Xu struct aead_alg *aead = container_of(alg, struct aead_alg, base); 228*0df4adf8SHerbert Xu struct crypto_istat_aead *istat = aead_get_stat(aead); 229*0df4adf8SHerbert Xu struct crypto_stat_aead raead; 230*0df4adf8SHerbert Xu 231*0df4adf8SHerbert Xu memset(&raead, 0, sizeof(raead)); 232*0df4adf8SHerbert Xu 233*0df4adf8SHerbert Xu strscpy(raead.type, "aead", sizeof(raead.type)); 234*0df4adf8SHerbert Xu 235*0df4adf8SHerbert Xu raead.stat_encrypt_cnt = atomic64_read(&istat->encrypt_cnt); 236*0df4adf8SHerbert Xu raead.stat_encrypt_tlen = atomic64_read(&istat->encrypt_tlen); 237*0df4adf8SHerbert Xu raead.stat_decrypt_cnt = atomic64_read(&istat->decrypt_cnt); 238*0df4adf8SHerbert Xu raead.stat_decrypt_tlen = atomic64_read(&istat->decrypt_tlen); 239*0df4adf8SHerbert Xu raead.stat_err_cnt = atomic64_read(&istat->err_cnt); 240*0df4adf8SHerbert Xu 241*0df4adf8SHerbert Xu return nla_put(skb, CRYPTOCFGA_STAT_AEAD, sizeof(raead), &raead); 242*0df4adf8SHerbert Xu } 243*0df4adf8SHerbert Xu 244b0d955baSHerbert Xu static const struct crypto_type crypto_aead_type = { 2455d1d65f8SHerbert Xu .extsize = crypto_alg_extsize, 2465d1d65f8SHerbert Xu .init_tfm = crypto_aead_init_tfm, 247ba75e15fSHerbert Xu .free = crypto_aead_free_instance, 2481ae97820SHerbert Xu #ifdef CONFIG_PROC_FS 2491ae97820SHerbert Xu .show = crypto_aead_show, 2501ae97820SHerbert Xu #endif 2516ad414feSSteffen Klassert .report = crypto_aead_report, 252*0df4adf8SHerbert Xu #ifdef CONFIG_CRYPTO_STATS 253*0df4adf8SHerbert Xu .report_stat = crypto_aead_report_stat, 254*0df4adf8SHerbert Xu #endif 25563293c61SHerbert Xu .maskclear = ~CRYPTO_ALG_TYPE_MASK, 2565d1d65f8SHerbert Xu .maskset = CRYPTO_ALG_TYPE_MASK, 2575d1d65f8SHerbert Xu .type = CRYPTO_ALG_TYPE_AEAD, 2585d1d65f8SHerbert Xu .tfmsize = offsetof(struct crypto_aead, base), 2591ae97820SHerbert Xu }; 2601ae97820SHerbert Xu 261cd900f0cSEric Biggers int crypto_grab_aead(struct crypto_aead_spawn *spawn, 262cd900f0cSEric Biggers struct crypto_instance *inst, 263cd900f0cSEric Biggers const char *name, u32 type, u32 mask) 264d29ce988SHerbert Xu { 2655d1d65f8SHerbert Xu spawn->base.frontend = &crypto_aead_type; 266de95c957SEric Biggers return crypto_grab_spawn(&spawn->base, inst, name, type, mask); 267d29ce988SHerbert Xu } 268d29ce988SHerbert Xu EXPORT_SYMBOL_GPL(crypto_grab_aead); 269d29ce988SHerbert Xu 270d29ce988SHerbert Xu struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask) 271d29ce988SHerbert Xu { 2725d1d65f8SHerbert Xu return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask); 273d29ce988SHerbert Xu } 274d29ce988SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alloc_aead); 275d29ce988SHerbert Xu 27663293c61SHerbert Xu static int aead_prepare_alg(struct aead_alg *alg) 27763293c61SHerbert Xu { 278*0df4adf8SHerbert Xu struct crypto_istat_aead *istat = aead_get_stat(alg); 27963293c61SHerbert Xu struct crypto_alg *base = &alg->base; 28063293c61SHerbert Xu 2817a530aa9SHerbert Xu if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) > 2827a530aa9SHerbert Xu PAGE_SIZE / 8) 28363293c61SHerbert Xu return -EINVAL; 28463293c61SHerbert Xu 2857a530aa9SHerbert Xu if (!alg->chunksize) 2867a530aa9SHerbert Xu alg->chunksize = base->cra_blocksize; 2877a530aa9SHerbert Xu 288b0d955baSHerbert Xu base->cra_type = &crypto_aead_type; 28963293c61SHerbert Xu base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; 29063293c61SHerbert Xu base->cra_flags |= CRYPTO_ALG_TYPE_AEAD; 29163293c61SHerbert Xu 292*0df4adf8SHerbert Xu if (IS_ENABLED(CONFIG_CRYPTO_STATS)) 293*0df4adf8SHerbert Xu memset(istat, 0, sizeof(*istat)); 294*0df4adf8SHerbert Xu 29563293c61SHerbert Xu return 0; 29663293c61SHerbert Xu } 29763293c61SHerbert Xu 29863293c61SHerbert Xu int crypto_register_aead(struct aead_alg *alg) 29963293c61SHerbert Xu { 30063293c61SHerbert Xu struct crypto_alg *base = &alg->base; 30163293c61SHerbert Xu int err; 30263293c61SHerbert Xu 30363293c61SHerbert Xu err = aead_prepare_alg(alg); 30463293c61SHerbert Xu if (err) 30563293c61SHerbert Xu return err; 30663293c61SHerbert Xu 30763293c61SHerbert Xu return crypto_register_alg(base); 30863293c61SHerbert Xu } 30963293c61SHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_aead); 31063293c61SHerbert Xu 31143615369SHerbert Xu void crypto_unregister_aead(struct aead_alg *alg) 31263293c61SHerbert Xu { 31343615369SHerbert Xu crypto_unregister_alg(&alg->base); 31463293c61SHerbert Xu } 31563293c61SHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_aead); 31663293c61SHerbert Xu 317caab9461SHerbert Xu int crypto_register_aeads(struct aead_alg *algs, int count) 318caab9461SHerbert Xu { 319caab9461SHerbert Xu int i, ret; 320caab9461SHerbert Xu 321caab9461SHerbert Xu for (i = 0; i < count; i++) { 322caab9461SHerbert Xu ret = crypto_register_aead(&algs[i]); 323caab9461SHerbert Xu if (ret) 324caab9461SHerbert Xu goto err; 325caab9461SHerbert Xu } 326caab9461SHerbert Xu 327caab9461SHerbert Xu return 0; 328caab9461SHerbert Xu 329caab9461SHerbert Xu err: 330caab9461SHerbert Xu for (--i; i >= 0; --i) 331caab9461SHerbert Xu crypto_unregister_aead(&algs[i]); 332caab9461SHerbert Xu 333caab9461SHerbert Xu return ret; 334caab9461SHerbert Xu } 335caab9461SHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_aeads); 336caab9461SHerbert Xu 337caab9461SHerbert Xu void crypto_unregister_aeads(struct aead_alg *algs, int count) 338caab9461SHerbert Xu { 339caab9461SHerbert Xu int i; 340caab9461SHerbert Xu 341caab9461SHerbert Xu for (i = count - 1; i >= 0; --i) 342caab9461SHerbert Xu crypto_unregister_aead(&algs[i]); 343caab9461SHerbert Xu } 344caab9461SHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_aeads); 345caab9461SHerbert Xu 34663293c61SHerbert Xu int aead_register_instance(struct crypto_template *tmpl, 34763293c61SHerbert Xu struct aead_instance *inst) 34863293c61SHerbert Xu { 34963293c61SHerbert Xu int err; 35063293c61SHerbert Xu 351d4fdc2dfSEric Biggers if (WARN_ON(!inst->free)) 352d4fdc2dfSEric Biggers return -EINVAL; 353d4fdc2dfSEric Biggers 35463293c61SHerbert Xu err = aead_prepare_alg(&inst->alg); 35563293c61SHerbert Xu if (err) 35663293c61SHerbert Xu return err; 35763293c61SHerbert Xu 35863293c61SHerbert Xu return crypto_register_instance(tmpl, aead_crypto_instance(inst)); 35963293c61SHerbert Xu } 36063293c61SHerbert Xu EXPORT_SYMBOL_GPL(aead_register_instance); 36163293c61SHerbert Xu 3621ae97820SHerbert Xu MODULE_LICENSE("GPL"); 3631ae97820SHerbert Xu MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); 364