Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * AEAD: Authenticated Encryption with Associated Data
0004  *
0005  * This file provides API support for AEAD algorithms.
0006  *
0007  * Copyright (c) 2007-2015 Herbert Xu <herbert@gondor.apana.org.au>
0008  */
0009 
0010 #include <crypto/internal/aead.h>
0011 #include <linux/errno.h>
0012 #include <linux/init.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/slab.h>
0016 #include <linux/seq_file.h>
0017 #include <linux/cryptouser.h>
0018 #include <net/netlink.h>
0019 
0020 #include "internal.h"
0021 
0022 static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
0023                 unsigned int keylen)
0024 {
0025     unsigned long alignmask = crypto_aead_alignmask(tfm);
0026     int ret;
0027     u8 *buffer, *alignbuffer;
0028     unsigned long absize;
0029 
0030     absize = keylen + alignmask;
0031     buffer = kmalloc(absize, GFP_ATOMIC);
0032     if (!buffer)
0033         return -ENOMEM;
0034 
0035     alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
0036     memcpy(alignbuffer, key, keylen);
0037     ret = crypto_aead_alg(tfm)->setkey(tfm, alignbuffer, keylen);
0038     memset(alignbuffer, 0, keylen);
0039     kfree(buffer);
0040     return ret;
0041 }
0042 
0043 int crypto_aead_setkey(struct crypto_aead *tfm,
0044                const u8 *key, unsigned int keylen)
0045 {
0046     unsigned long alignmask = crypto_aead_alignmask(tfm);
0047     int err;
0048 
0049     if ((unsigned long)key & alignmask)
0050         err = setkey_unaligned(tfm, key, keylen);
0051     else
0052         err = crypto_aead_alg(tfm)->setkey(tfm, key, keylen);
0053 
0054     if (unlikely(err)) {
0055         crypto_aead_set_flags(tfm, CRYPTO_TFM_NEED_KEY);
0056         return err;
0057     }
0058 
0059     crypto_aead_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
0060     return 0;
0061 }
0062 EXPORT_SYMBOL_GPL(crypto_aead_setkey);
0063 
0064 int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
0065 {
0066     int err;
0067 
0068     if ((!authsize && crypto_aead_maxauthsize(tfm)) ||
0069         authsize > crypto_aead_maxauthsize(tfm))
0070         return -EINVAL;
0071 
0072     if (crypto_aead_alg(tfm)->setauthsize) {
0073         err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize);
0074         if (err)
0075             return err;
0076     }
0077 
0078     tfm->authsize = authsize;
0079     return 0;
0080 }
0081 EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
0082 
0083 int crypto_aead_encrypt(struct aead_request *req)
0084 {
0085     struct crypto_aead *aead = crypto_aead_reqtfm(req);
0086     struct crypto_alg *alg = aead->base.__crt_alg;
0087     unsigned int cryptlen = req->cryptlen;
0088     int ret;
0089 
0090     crypto_stats_get(alg);
0091     if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
0092         ret = -ENOKEY;
0093     else
0094         ret = crypto_aead_alg(aead)->encrypt(req);
0095     crypto_stats_aead_encrypt(cryptlen, alg, ret);
0096     return ret;
0097 }
0098 EXPORT_SYMBOL_GPL(crypto_aead_encrypt);
0099 
0100 int crypto_aead_decrypt(struct aead_request *req)
0101 {
0102     struct crypto_aead *aead = crypto_aead_reqtfm(req);
0103     struct crypto_alg *alg = aead->base.__crt_alg;
0104     unsigned int cryptlen = req->cryptlen;
0105     int ret;
0106 
0107     crypto_stats_get(alg);
0108     if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
0109         ret = -ENOKEY;
0110     else if (req->cryptlen < crypto_aead_authsize(aead))
0111         ret = -EINVAL;
0112     else
0113         ret = crypto_aead_alg(aead)->decrypt(req);
0114     crypto_stats_aead_decrypt(cryptlen, alg, ret);
0115     return ret;
0116 }
0117 EXPORT_SYMBOL_GPL(crypto_aead_decrypt);
0118 
0119 static void crypto_aead_exit_tfm(struct crypto_tfm *tfm)
0120 {
0121     struct crypto_aead *aead = __crypto_aead_cast(tfm);
0122     struct aead_alg *alg = crypto_aead_alg(aead);
0123 
0124     alg->exit(aead);
0125 }
0126 
0127 static int crypto_aead_init_tfm(struct crypto_tfm *tfm)
0128 {
0129     struct crypto_aead *aead = __crypto_aead_cast(tfm);
0130     struct aead_alg *alg = crypto_aead_alg(aead);
0131 
0132     crypto_aead_set_flags(aead, CRYPTO_TFM_NEED_KEY);
0133 
0134     aead->authsize = alg->maxauthsize;
0135 
0136     if (alg->exit)
0137         aead->base.exit = crypto_aead_exit_tfm;
0138 
0139     if (alg->init)
0140         return alg->init(aead);
0141 
0142     return 0;
0143 }
0144 
0145 #ifdef CONFIG_NET
0146 static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
0147 {
0148     struct crypto_report_aead raead;
0149     struct aead_alg *aead = container_of(alg, struct aead_alg, base);
0150 
0151     memset(&raead, 0, sizeof(raead));
0152 
0153     strscpy(raead.type, "aead", sizeof(raead.type));
0154     strscpy(raead.geniv, "<none>", sizeof(raead.geniv));
0155 
0156     raead.blocksize = alg->cra_blocksize;
0157     raead.maxauthsize = aead->maxauthsize;
0158     raead.ivsize = aead->ivsize;
0159 
0160     return nla_put(skb, CRYPTOCFGA_REPORT_AEAD, sizeof(raead), &raead);
0161 }
0162 #else
0163 static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
0164 {
0165     return -ENOSYS;
0166 }
0167 #endif
0168 
0169 static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
0170     __maybe_unused;
0171 static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
0172 {
0173     struct aead_alg *aead = container_of(alg, struct aead_alg, base);
0174 
0175     seq_printf(m, "type         : aead\n");
0176     seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
0177                          "yes" : "no");
0178     seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
0179     seq_printf(m, "ivsize       : %u\n", aead->ivsize);
0180     seq_printf(m, "maxauthsize  : %u\n", aead->maxauthsize);
0181     seq_printf(m, "geniv        : <none>\n");
0182 }
0183 
0184 static void crypto_aead_free_instance(struct crypto_instance *inst)
0185 {
0186     struct aead_instance *aead = aead_instance(inst);
0187 
0188     aead->free(aead);
0189 }
0190 
0191 static const struct crypto_type crypto_aead_type = {
0192     .extsize = crypto_alg_extsize,
0193     .init_tfm = crypto_aead_init_tfm,
0194     .free = crypto_aead_free_instance,
0195 #ifdef CONFIG_PROC_FS
0196     .show = crypto_aead_show,
0197 #endif
0198     .report = crypto_aead_report,
0199     .maskclear = ~CRYPTO_ALG_TYPE_MASK,
0200     .maskset = CRYPTO_ALG_TYPE_MASK,
0201     .type = CRYPTO_ALG_TYPE_AEAD,
0202     .tfmsize = offsetof(struct crypto_aead, base),
0203 };
0204 
0205 int crypto_grab_aead(struct crypto_aead_spawn *spawn,
0206              struct crypto_instance *inst,
0207              const char *name, u32 type, u32 mask)
0208 {
0209     spawn->base.frontend = &crypto_aead_type;
0210     return crypto_grab_spawn(&spawn->base, inst, name, type, mask);
0211 }
0212 EXPORT_SYMBOL_GPL(crypto_grab_aead);
0213 
0214 struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
0215 {
0216     return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask);
0217 }
0218 EXPORT_SYMBOL_GPL(crypto_alloc_aead);
0219 
0220 static int aead_prepare_alg(struct aead_alg *alg)
0221 {
0222     struct crypto_alg *base = &alg->base;
0223 
0224     if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) >
0225         PAGE_SIZE / 8)
0226         return -EINVAL;
0227 
0228     if (!alg->chunksize)
0229         alg->chunksize = base->cra_blocksize;
0230 
0231     base->cra_type = &crypto_aead_type;
0232     base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
0233     base->cra_flags |= CRYPTO_ALG_TYPE_AEAD;
0234 
0235     return 0;
0236 }
0237 
0238 int crypto_register_aead(struct aead_alg *alg)
0239 {
0240     struct crypto_alg *base = &alg->base;
0241     int err;
0242 
0243     err = aead_prepare_alg(alg);
0244     if (err)
0245         return err;
0246 
0247     return crypto_register_alg(base);
0248 }
0249 EXPORT_SYMBOL_GPL(crypto_register_aead);
0250 
0251 void crypto_unregister_aead(struct aead_alg *alg)
0252 {
0253     crypto_unregister_alg(&alg->base);
0254 }
0255 EXPORT_SYMBOL_GPL(crypto_unregister_aead);
0256 
0257 int crypto_register_aeads(struct aead_alg *algs, int count)
0258 {
0259     int i, ret;
0260 
0261     for (i = 0; i < count; i++) {
0262         ret = crypto_register_aead(&algs[i]);
0263         if (ret)
0264             goto err;
0265     }
0266 
0267     return 0;
0268 
0269 err:
0270     for (--i; i >= 0; --i)
0271         crypto_unregister_aead(&algs[i]);
0272 
0273     return ret;
0274 }
0275 EXPORT_SYMBOL_GPL(crypto_register_aeads);
0276 
0277 void crypto_unregister_aeads(struct aead_alg *algs, int count)
0278 {
0279     int i;
0280 
0281     for (i = count - 1; i >= 0; --i)
0282         crypto_unregister_aead(&algs[i]);
0283 }
0284 EXPORT_SYMBOL_GPL(crypto_unregister_aeads);
0285 
0286 int aead_register_instance(struct crypto_template *tmpl,
0287                struct aead_instance *inst)
0288 {
0289     int err;
0290 
0291     if (WARN_ON(!inst->free))
0292         return -EINVAL;
0293 
0294     err = aead_prepare_alg(&inst->alg);
0295     if (err)
0296         return err;
0297 
0298     return crypto_register_instance(tmpl, aead_crypto_instance(inst));
0299 }
0300 EXPORT_SYMBOL_GPL(aead_register_instance);
0301 
0302 MODULE_LICENSE("GPL");
0303 MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");