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