1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * AEAD: Authenticated Encryption with Associated Data 4 * 5 * This file provides API support for AEAD algorithms. 6 * 7 * Copyright (c) 2007-2015 Herbert Xu <herbert@gondor.apana.org.au> 8 */ 9 10#include <crypto/internal/aead.h> 11#include <linux/errno.h> 12#include <linux/init.h> 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/slab.h> 16#include <linux/seq_file.h> 17#include <linux/cryptouser.h> 18#include <net/netlink.h> 19 20#include "internal.h" 21 22static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, 23 unsigned int keylen) 24{ 25 unsigned long alignmask = crypto_aead_alignmask(tfm); 26 int ret; 27 u8 *buffer, *alignbuffer; 28 unsigned long absize; 29 30 absize = keylen + alignmask; 31 buffer = kmalloc(absize, GFP_ATOMIC); 32 if (!buffer) 33 return -ENOMEM; 34 35 alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 36 memcpy(alignbuffer, key, keylen); 37 ret = crypto_aead_alg(tfm)->setkey(tfm, alignbuffer, keylen); 38 kfree_sensitive(buffer); 39 return ret; 40} 41 42int crypto_aead_setkey(struct crypto_aead *tfm, 43 const u8 *key, unsigned int keylen) 44{ 45 unsigned long alignmask = crypto_aead_alignmask(tfm); 46 int err; 47 48 if ((unsigned long)key & alignmask) 49 err = setkey_unaligned(tfm, key, keylen); 50 else 51 err = crypto_aead_alg(tfm)->setkey(tfm, key, keylen); 52 53 if (unlikely(err)) { 54 crypto_aead_set_flags(tfm, CRYPTO_TFM_NEED_KEY); 55 return err; 56 } 57 58 crypto_aead_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); 59 return 0; 60} 61EXPORT_SYMBOL_GPL(crypto_aead_setkey); 62 63int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 64{ 65 int err; 66 67 if ((!authsize && crypto_aead_maxauthsize(tfm)) || 68 authsize > crypto_aead_maxauthsize(tfm)) 69 return -EINVAL; 70 71 if (crypto_aead_alg(tfm)->setauthsize) { 72 err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize); 73 if (err) 74 return err; 75 } 76 77 tfm->authsize = authsize; 78 return 0; 79} 80EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); 81 82int crypto_aead_encrypt(struct aead_request *req) 83{ 84 struct crypto_aead *aead = crypto_aead_reqtfm(req); 85 struct crypto_alg *alg = aead->base.__crt_alg; 86 unsigned int cryptlen = req->cryptlen; 87 int ret; 88 89 crypto_stats_get(alg); 90 if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) 91 ret = -ENOKEY; 92 else 93 ret = crypto_aead_alg(aead)->encrypt(req); 94 crypto_stats_aead_encrypt(cryptlen, alg, ret); 95 return ret; 96} 97EXPORT_SYMBOL_GPL(crypto_aead_encrypt); 98 99int crypto_aead_decrypt(struct aead_request *req) 100{ 101 struct crypto_aead *aead = crypto_aead_reqtfm(req); 102 struct crypto_alg *alg = aead->base.__crt_alg; 103 unsigned int cryptlen = req->cryptlen; 104 int ret; 105 106 crypto_stats_get(alg); 107 if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) 108 ret = -ENOKEY; 109 else if (req->cryptlen < crypto_aead_authsize(aead)) 110 ret = -EINVAL; 111 else 112 ret = crypto_aead_alg(aead)->decrypt(req); 113 crypto_stats_aead_decrypt(cryptlen, alg, ret); 114 return ret; 115} 116EXPORT_SYMBOL_GPL(crypto_aead_decrypt); 117 118static void crypto_aead_exit_tfm(struct crypto_tfm *tfm) 119{ 120 struct crypto_aead *aead = __crypto_aead_cast(tfm); 121 struct aead_alg *alg = crypto_aead_alg(aead); 122 123 alg->exit(aead); 124} 125 126static int crypto_aead_init_tfm(struct crypto_tfm *tfm) 127{ 128 struct crypto_aead *aead = __crypto_aead_cast(tfm); 129 struct aead_alg *alg = crypto_aead_alg(aead); 130 131 crypto_aead_set_flags(aead, CRYPTO_TFM_NEED_KEY); 132 133 aead->authsize = alg->maxauthsize; 134 135 if (alg->exit) 136 aead->base.exit = crypto_aead_exit_tfm; 137 138 if (alg->init) 139 return alg->init(aead); 140 141 return 0; 142} 143 144#ifdef CONFIG_NET 145static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) 146{ 147 struct crypto_report_aead raead; 148 struct aead_alg *aead = container_of(alg, struct aead_alg, base); 149 150 memset(&raead, 0, sizeof(raead)); 151 152 strscpy(raead.type, "aead", sizeof(raead.type)); 153 strscpy(raead.geniv, "<none>", sizeof(raead.geniv)); 154 155 raead.blocksize = alg->cra_blocksize; 156 raead.maxauthsize = aead->maxauthsize; 157 raead.ivsize = aead->ivsize; 158 159 return nla_put(skb, CRYPTOCFGA_REPORT_AEAD, sizeof(raead), &raead); 160} 161#else 162static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) 163{ 164 return -ENOSYS; 165} 166#endif 167 168static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) 169 __maybe_unused; 170static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) 171{ 172 struct aead_alg *aead = container_of(alg, struct aead_alg, base); 173 174 seq_printf(m, "type : aead\n"); 175 seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? 176 "yes" : "no"); 177 seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); 178 seq_printf(m, "ivsize : %u\n", aead->ivsize); 179 seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); 180 seq_printf(m, "geniv : <none>\n"); 181} 182 183static void crypto_aead_free_instance(struct crypto_instance *inst) 184{ 185 struct aead_instance *aead = aead_instance(inst); 186 187 aead->free(aead); 188} 189 190static const struct crypto_type crypto_aead_type = { 191 .extsize = crypto_alg_extsize, 192 .init_tfm = crypto_aead_init_tfm, 193 .free = crypto_aead_free_instance, 194#ifdef CONFIG_PROC_FS 195 .show = crypto_aead_show, 196#endif 197 .report = crypto_aead_report, 198 .maskclear = ~CRYPTO_ALG_TYPE_MASK, 199 .maskset = CRYPTO_ALG_TYPE_MASK, 200 .type = CRYPTO_ALG_TYPE_AEAD, 201 .tfmsize = offsetof(struct crypto_aead, base), 202}; 203 204int crypto_grab_aead(struct crypto_aead_spawn *spawn, 205 struct crypto_instance *inst, 206 const char *name, u32 type, u32 mask) 207{ 208 spawn->base.frontend = &crypto_aead_type; 209 return crypto_grab_spawn(&spawn->base, inst, name, type, mask); 210} 211EXPORT_SYMBOL_GPL(crypto_grab_aead); 212 213struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask) 214{ 215 return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask); 216} 217EXPORT_SYMBOL_GPL(crypto_alloc_aead); 218 219static int aead_prepare_alg(struct aead_alg *alg) 220{ 221 struct crypto_alg *base = &alg->base; 222 223 if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) > 224 PAGE_SIZE / 8) 225 return -EINVAL; 226 227 if (!alg->chunksize) 228 alg->chunksize = base->cra_blocksize; 229 230 base->cra_type = &crypto_aead_type; 231 base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; 232 base->cra_flags |= CRYPTO_ALG_TYPE_AEAD; 233 234 return 0; 235} 236 237int crypto_register_aead(struct aead_alg *alg) 238{ 239 struct crypto_alg *base = &alg->base; 240 int err; 241 242 err = aead_prepare_alg(alg); 243 if (err) 244 return err; 245 246 return crypto_register_alg(base); 247} 248EXPORT_SYMBOL_GPL(crypto_register_aead); 249 250void crypto_unregister_aead(struct aead_alg *alg) 251{ 252 crypto_unregister_alg(&alg->base); 253} 254EXPORT_SYMBOL_GPL(crypto_unregister_aead); 255 256int crypto_register_aeads(struct aead_alg *algs, int count) 257{ 258 int i, ret; 259 260 for (i = 0; i < count; i++) { 261 ret = crypto_register_aead(&algs[i]); 262 if (ret) 263 goto err; 264 } 265 266 return 0; 267 268err: 269 for (--i; i >= 0; --i) 270 crypto_unregister_aead(&algs[i]); 271 272 return ret; 273} 274EXPORT_SYMBOL_GPL(crypto_register_aeads); 275 276void crypto_unregister_aeads(struct aead_alg *algs, int count) 277{ 278 int i; 279 280 for (i = count - 1; i >= 0; --i) 281 crypto_unregister_aead(&algs[i]); 282} 283EXPORT_SYMBOL_GPL(crypto_unregister_aeads); 284 285int aead_register_instance(struct crypto_template *tmpl, 286 struct aead_instance *inst) 287{ 288 int err; 289 290 if (WARN_ON(!inst->free)) 291 return -EINVAL; 292 293 err = aead_prepare_alg(&inst->alg); 294 if (err) 295 return err; 296 297 return crypto_register_instance(tmpl, aead_crypto_instance(inst)); 298} 299EXPORT_SYMBOL_GPL(aead_register_instance); 300 301MODULE_LICENSE("GPL"); 302MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); 303