cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

aead.c (7417B)


      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	memset(alignbuffer, 0, keylen);
     39	kfree(buffer);
     40	return ret;
     41}
     42
     43int 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}
     62EXPORT_SYMBOL_GPL(crypto_aead_setkey);
     63
     64int 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}
     81EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
     82
     83int 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}
     98EXPORT_SYMBOL_GPL(crypto_aead_encrypt);
     99
    100int 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}
    117EXPORT_SYMBOL_GPL(crypto_aead_decrypt);
    118
    119static 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
    127static 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
    146static 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
    163static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
    164{
    165	return -ENOSYS;
    166}
    167#endif
    168
    169static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
    170	__maybe_unused;
    171static 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
    184static 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
    191static 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
    205int 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}
    212EXPORT_SYMBOL_GPL(crypto_grab_aead);
    213
    214struct 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}
    218EXPORT_SYMBOL_GPL(crypto_alloc_aead);
    219
    220static 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
    238int 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}
    249EXPORT_SYMBOL_GPL(crypto_register_aead);
    250
    251void crypto_unregister_aead(struct aead_alg *alg)
    252{
    253	crypto_unregister_alg(&alg->base);
    254}
    255EXPORT_SYMBOL_GPL(crypto_unregister_aead);
    256
    257int 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
    269err:
    270	for (--i; i >= 0; --i)
    271		crypto_unregister_aead(&algs[i]);
    272
    273	return ret;
    274}
    275EXPORT_SYMBOL_GPL(crypto_register_aeads);
    276
    277void 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}
    284EXPORT_SYMBOL_GPL(crypto_unregister_aeads);
    285
    286int 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}
    300EXPORT_SYMBOL_GPL(aead_register_instance);
    301
    302MODULE_LICENSE("GPL");
    303MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");