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