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

authencesn.c (14502B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * authencesn.c - AEAD wrapper for IPsec with extended sequence numbers,
      4 *                 derived from authenc.c
      5 *
      6 * Copyright (C) 2010 secunet Security Networks AG
      7 * Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com>
      8 * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
      9 */
     10
     11#include <crypto/internal/aead.h>
     12#include <crypto/internal/hash.h>
     13#include <crypto/internal/skcipher.h>
     14#include <crypto/authenc.h>
     15#include <crypto/null.h>
     16#include <crypto/scatterwalk.h>
     17#include <linux/err.h>
     18#include <linux/init.h>
     19#include <linux/kernel.h>
     20#include <linux/module.h>
     21#include <linux/rtnetlink.h>
     22#include <linux/slab.h>
     23#include <linux/spinlock.h>
     24
     25struct authenc_esn_instance_ctx {
     26	struct crypto_ahash_spawn auth;
     27	struct crypto_skcipher_spawn enc;
     28};
     29
     30struct crypto_authenc_esn_ctx {
     31	unsigned int reqoff;
     32	struct crypto_ahash *auth;
     33	struct crypto_skcipher *enc;
     34	struct crypto_sync_skcipher *null;
     35};
     36
     37struct authenc_esn_request_ctx {
     38	struct scatterlist src[2];
     39	struct scatterlist dst[2];
     40	char tail[];
     41};
     42
     43static void authenc_esn_request_complete(struct aead_request *req, int err)
     44{
     45	if (err != -EINPROGRESS)
     46		aead_request_complete(req, err);
     47}
     48
     49static int crypto_authenc_esn_setauthsize(struct crypto_aead *authenc_esn,
     50					  unsigned int authsize)
     51{
     52	if (authsize > 0 && authsize < 4)
     53		return -EINVAL;
     54
     55	return 0;
     56}
     57
     58static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *key,
     59				     unsigned int keylen)
     60{
     61	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
     62	struct crypto_ahash *auth = ctx->auth;
     63	struct crypto_skcipher *enc = ctx->enc;
     64	struct crypto_authenc_keys keys;
     65	int err = -EINVAL;
     66
     67	if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
     68		goto out;
     69
     70	crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
     71	crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc_esn) &
     72				     CRYPTO_TFM_REQ_MASK);
     73	err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
     74	if (err)
     75		goto out;
     76
     77	crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
     78	crypto_skcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) &
     79					 CRYPTO_TFM_REQ_MASK);
     80	err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen);
     81out:
     82	memzero_explicit(&keys, sizeof(keys));
     83	return err;
     84}
     85
     86static int crypto_authenc_esn_genicv_tail(struct aead_request *req,
     87					  unsigned int flags)
     88{
     89	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
     90	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
     91	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
     92	struct crypto_ahash *auth = ctx->auth;
     93	u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail,
     94			     crypto_ahash_alignmask(auth) + 1);
     95	unsigned int authsize = crypto_aead_authsize(authenc_esn);
     96	unsigned int assoclen = req->assoclen;
     97	unsigned int cryptlen = req->cryptlen;
     98	struct scatterlist *dst = req->dst;
     99	u32 tmp[2];
    100
    101	/* Move high-order bits of sequence number back. */
    102	scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
    103	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
    104	scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
    105
    106	scatterwalk_map_and_copy(hash, dst, assoclen + cryptlen, authsize, 1);
    107	return 0;
    108}
    109
    110static void authenc_esn_geniv_ahash_done(struct crypto_async_request *areq,
    111					 int err)
    112{
    113	struct aead_request *req = areq->data;
    114
    115	err = err ?: crypto_authenc_esn_genicv_tail(req, 0);
    116	aead_request_complete(req, err);
    117}
    118
    119static int crypto_authenc_esn_genicv(struct aead_request *req,
    120				     unsigned int flags)
    121{
    122	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
    123	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
    124	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
    125	struct crypto_ahash *auth = ctx->auth;
    126	u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail,
    127			     crypto_ahash_alignmask(auth) + 1);
    128	struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
    129	unsigned int authsize = crypto_aead_authsize(authenc_esn);
    130	unsigned int assoclen = req->assoclen;
    131	unsigned int cryptlen = req->cryptlen;
    132	struct scatterlist *dst = req->dst;
    133	u32 tmp[2];
    134
    135	if (!authsize)
    136		return 0;
    137
    138	/* Move high-order bits of sequence number to the end. */
    139	scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
    140	scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
    141	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
    142
    143	sg_init_table(areq_ctx->dst, 2);
    144	dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
    145
    146	ahash_request_set_tfm(ahreq, auth);
    147	ahash_request_set_crypt(ahreq, dst, hash, assoclen + cryptlen);
    148	ahash_request_set_callback(ahreq, flags,
    149				   authenc_esn_geniv_ahash_done, req);
    150
    151	return crypto_ahash_digest(ahreq) ?:
    152	       crypto_authenc_esn_genicv_tail(req, aead_request_flags(req));
    153}
    154
    155
    156static void crypto_authenc_esn_encrypt_done(struct crypto_async_request *req,
    157					    int err)
    158{
    159	struct aead_request *areq = req->data;
    160
    161	if (!err)
    162		err = crypto_authenc_esn_genicv(areq, 0);
    163
    164	authenc_esn_request_complete(areq, err);
    165}
    166
    167static int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len)
    168{
    169	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
    170	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
    171	SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
    172
    173	skcipher_request_set_sync_tfm(skreq, ctx->null);
    174	skcipher_request_set_callback(skreq, aead_request_flags(req),
    175				      NULL, NULL);
    176	skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL);
    177
    178	return crypto_skcipher_encrypt(skreq);
    179}
    180
    181static int crypto_authenc_esn_encrypt(struct aead_request *req)
    182{
    183	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
    184	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
    185	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
    186	struct skcipher_request *skreq = (void *)(areq_ctx->tail +
    187						  ctx->reqoff);
    188	struct crypto_skcipher *enc = ctx->enc;
    189	unsigned int assoclen = req->assoclen;
    190	unsigned int cryptlen = req->cryptlen;
    191	struct scatterlist *src, *dst;
    192	int err;
    193
    194	sg_init_table(areq_ctx->src, 2);
    195	src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen);
    196	dst = src;
    197
    198	if (req->src != req->dst) {
    199		err = crypto_authenc_esn_copy(req, assoclen);
    200		if (err)
    201			return err;
    202
    203		sg_init_table(areq_ctx->dst, 2);
    204		dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen);
    205	}
    206
    207	skcipher_request_set_tfm(skreq, enc);
    208	skcipher_request_set_callback(skreq, aead_request_flags(req),
    209				      crypto_authenc_esn_encrypt_done, req);
    210	skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
    211
    212	err = crypto_skcipher_encrypt(skreq);
    213	if (err)
    214		return err;
    215
    216	return crypto_authenc_esn_genicv(req, aead_request_flags(req));
    217}
    218
    219static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
    220					   unsigned int flags)
    221{
    222	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
    223	unsigned int authsize = crypto_aead_authsize(authenc_esn);
    224	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
    225	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
    226	struct skcipher_request *skreq = (void *)(areq_ctx->tail +
    227						  ctx->reqoff);
    228	struct crypto_ahash *auth = ctx->auth;
    229	u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail,
    230			      crypto_ahash_alignmask(auth) + 1);
    231	unsigned int cryptlen = req->cryptlen - authsize;
    232	unsigned int assoclen = req->assoclen;
    233	struct scatterlist *dst = req->dst;
    234	u8 *ihash = ohash + crypto_ahash_digestsize(auth);
    235	u32 tmp[2];
    236
    237	if (!authsize)
    238		goto decrypt;
    239
    240	/* Move high-order bits of sequence number back. */
    241	scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
    242	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
    243	scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
    244
    245	if (crypto_memneq(ihash, ohash, authsize))
    246		return -EBADMSG;
    247
    248decrypt:
    249
    250	sg_init_table(areq_ctx->dst, 2);
    251	dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen);
    252
    253	skcipher_request_set_tfm(skreq, ctx->enc);
    254	skcipher_request_set_callback(skreq, flags,
    255				      req->base.complete, req->base.data);
    256	skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv);
    257
    258	return crypto_skcipher_decrypt(skreq);
    259}
    260
    261static void authenc_esn_verify_ahash_done(struct crypto_async_request *areq,
    262					  int err)
    263{
    264	struct aead_request *req = areq->data;
    265
    266	err = err ?: crypto_authenc_esn_decrypt_tail(req, 0);
    267	authenc_esn_request_complete(req, err);
    268}
    269
    270static int crypto_authenc_esn_decrypt(struct aead_request *req)
    271{
    272	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
    273	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
    274	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
    275	struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
    276	unsigned int authsize = crypto_aead_authsize(authenc_esn);
    277	struct crypto_ahash *auth = ctx->auth;
    278	u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail,
    279			      crypto_ahash_alignmask(auth) + 1);
    280	unsigned int assoclen = req->assoclen;
    281	unsigned int cryptlen = req->cryptlen;
    282	u8 *ihash = ohash + crypto_ahash_digestsize(auth);
    283	struct scatterlist *dst = req->dst;
    284	u32 tmp[2];
    285	int err;
    286
    287	cryptlen -= authsize;
    288
    289	if (req->src != dst) {
    290		err = crypto_authenc_esn_copy(req, assoclen + cryptlen);
    291		if (err)
    292			return err;
    293	}
    294
    295	scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen,
    296				 authsize, 0);
    297
    298	if (!authsize)
    299		goto tail;
    300
    301	/* Move high-order bits of sequence number to the end. */
    302	scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
    303	scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
    304	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
    305
    306	sg_init_table(areq_ctx->dst, 2);
    307	dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
    308
    309	ahash_request_set_tfm(ahreq, auth);
    310	ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen);
    311	ahash_request_set_callback(ahreq, aead_request_flags(req),
    312				   authenc_esn_verify_ahash_done, req);
    313
    314	err = crypto_ahash_digest(ahreq);
    315	if (err)
    316		return err;
    317
    318tail:
    319	return crypto_authenc_esn_decrypt_tail(req, aead_request_flags(req));
    320}
    321
    322static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm)
    323{
    324	struct aead_instance *inst = aead_alg_instance(tfm);
    325	struct authenc_esn_instance_ctx *ictx = aead_instance_ctx(inst);
    326	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
    327	struct crypto_ahash *auth;
    328	struct crypto_skcipher *enc;
    329	struct crypto_sync_skcipher *null;
    330	int err;
    331
    332	auth = crypto_spawn_ahash(&ictx->auth);
    333	if (IS_ERR(auth))
    334		return PTR_ERR(auth);
    335
    336	enc = crypto_spawn_skcipher(&ictx->enc);
    337	err = PTR_ERR(enc);
    338	if (IS_ERR(enc))
    339		goto err_free_ahash;
    340
    341	null = crypto_get_default_null_skcipher();
    342	err = PTR_ERR(null);
    343	if (IS_ERR(null))
    344		goto err_free_skcipher;
    345
    346	ctx->auth = auth;
    347	ctx->enc = enc;
    348	ctx->null = null;
    349
    350	ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth),
    351			    crypto_ahash_alignmask(auth) + 1);
    352
    353	crypto_aead_set_reqsize(
    354		tfm,
    355		sizeof(struct authenc_esn_request_ctx) +
    356		ctx->reqoff +
    357		max_t(unsigned int,
    358		      crypto_ahash_reqsize(auth) +
    359		      sizeof(struct ahash_request),
    360		      sizeof(struct skcipher_request) +
    361		      crypto_skcipher_reqsize(enc)));
    362
    363	return 0;
    364
    365err_free_skcipher:
    366	crypto_free_skcipher(enc);
    367err_free_ahash:
    368	crypto_free_ahash(auth);
    369	return err;
    370}
    371
    372static void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm)
    373{
    374	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
    375
    376	crypto_free_ahash(ctx->auth);
    377	crypto_free_skcipher(ctx->enc);
    378	crypto_put_default_null_skcipher();
    379}
    380
    381static void crypto_authenc_esn_free(struct aead_instance *inst)
    382{
    383	struct authenc_esn_instance_ctx *ctx = aead_instance_ctx(inst);
    384
    385	crypto_drop_skcipher(&ctx->enc);
    386	crypto_drop_ahash(&ctx->auth);
    387	kfree(inst);
    388}
    389
    390static int crypto_authenc_esn_create(struct crypto_template *tmpl,
    391				     struct rtattr **tb)
    392{
    393	u32 mask;
    394	struct aead_instance *inst;
    395	struct authenc_esn_instance_ctx *ctx;
    396	struct hash_alg_common *auth;
    397	struct crypto_alg *auth_base;
    398	struct skcipher_alg *enc;
    399	int err;
    400
    401	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask);
    402	if (err)
    403		return err;
    404
    405	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
    406	if (!inst)
    407		return -ENOMEM;
    408	ctx = aead_instance_ctx(inst);
    409
    410	err = crypto_grab_ahash(&ctx->auth, aead_crypto_instance(inst),
    411				crypto_attr_alg_name(tb[1]), 0, mask);
    412	if (err)
    413		goto err_free_inst;
    414	auth = crypto_spawn_ahash_alg(&ctx->auth);
    415	auth_base = &auth->base;
    416
    417	err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst),
    418				   crypto_attr_alg_name(tb[2]), 0, mask);
    419	if (err)
    420		goto err_free_inst;
    421	enc = crypto_spawn_skcipher_alg(&ctx->enc);
    422
    423	err = -ENAMETOOLONG;
    424	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
    425		     "authencesn(%s,%s)", auth_base->cra_name,
    426		     enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
    427		goto err_free_inst;
    428
    429	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
    430		     "authencesn(%s,%s)", auth_base->cra_driver_name,
    431		     enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
    432		goto err_free_inst;
    433
    434	inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
    435				      auth_base->cra_priority;
    436	inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
    437	inst->alg.base.cra_alignmask = auth_base->cra_alignmask |
    438				       enc->base.cra_alignmask;
    439	inst->alg.base.cra_ctxsize = sizeof(struct crypto_authenc_esn_ctx);
    440
    441	inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc);
    442	inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc);
    443	inst->alg.maxauthsize = auth->digestsize;
    444
    445	inst->alg.init = crypto_authenc_esn_init_tfm;
    446	inst->alg.exit = crypto_authenc_esn_exit_tfm;
    447
    448	inst->alg.setkey = crypto_authenc_esn_setkey;
    449	inst->alg.setauthsize = crypto_authenc_esn_setauthsize;
    450	inst->alg.encrypt = crypto_authenc_esn_encrypt;
    451	inst->alg.decrypt = crypto_authenc_esn_decrypt;
    452
    453	inst->free = crypto_authenc_esn_free;
    454
    455	err = aead_register_instance(tmpl, inst);
    456	if (err) {
    457err_free_inst:
    458		crypto_authenc_esn_free(inst);
    459	}
    460	return err;
    461}
    462
    463static struct crypto_template crypto_authenc_esn_tmpl = {
    464	.name = "authencesn",
    465	.create = crypto_authenc_esn_create,
    466	.module = THIS_MODULE,
    467};
    468
    469static int __init crypto_authenc_esn_module_init(void)
    470{
    471	return crypto_register_template(&crypto_authenc_esn_tmpl);
    472}
    473
    474static void __exit crypto_authenc_esn_module_exit(void)
    475{
    476	crypto_unregister_template(&crypto_authenc_esn_tmpl);
    477}
    478
    479subsys_initcall(crypto_authenc_esn_module_init);
    480module_exit(crypto_authenc_esn_module_exit);
    481
    482MODULE_LICENSE("GPL");
    483MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
    484MODULE_DESCRIPTION("AEAD wrapper for IPsec with extended sequence numbers");
    485MODULE_ALIAS_CRYPTO("authencesn");