18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * authencesn.c - AEAD wrapper for IPsec with extended sequence numbers,
48c2ecf20Sopenharmony_ci *                 derived from authenc.c
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2010 secunet Security Networks AG
78c2ecf20Sopenharmony_ci * Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com>
88c2ecf20Sopenharmony_ci * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h>
128c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h>
138c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h>
148c2ecf20Sopenharmony_ci#include <crypto/authenc.h>
158c2ecf20Sopenharmony_ci#include <crypto/null.h>
168c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
178c2ecf20Sopenharmony_ci#include <linux/err.h>
188c2ecf20Sopenharmony_ci#include <linux/init.h>
198c2ecf20Sopenharmony_ci#include <linux/kernel.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct authenc_esn_instance_ctx {
268c2ecf20Sopenharmony_ci	struct crypto_ahash_spawn auth;
278c2ecf20Sopenharmony_ci	struct crypto_skcipher_spawn enc;
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct crypto_authenc_esn_ctx {
318c2ecf20Sopenharmony_ci	unsigned int reqoff;
328c2ecf20Sopenharmony_ci	struct crypto_ahash *auth;
338c2ecf20Sopenharmony_ci	struct crypto_skcipher *enc;
348c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *null;
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct authenc_esn_request_ctx {
388c2ecf20Sopenharmony_ci	struct scatterlist src[2];
398c2ecf20Sopenharmony_ci	struct scatterlist dst[2];
408c2ecf20Sopenharmony_ci	char tail[];
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void authenc_esn_request_complete(struct aead_request *req, int err)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	if (err != -EINPROGRESS)
468c2ecf20Sopenharmony_ci		aead_request_complete(req, err);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_setauthsize(struct crypto_aead *authenc_esn,
508c2ecf20Sopenharmony_ci					  unsigned int authsize)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	if (authsize > 0 && authsize < 4)
538c2ecf20Sopenharmony_ci		return -EINVAL;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return 0;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *key,
598c2ecf20Sopenharmony_ci				     unsigned int keylen)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
628c2ecf20Sopenharmony_ci	struct crypto_ahash *auth = ctx->auth;
638c2ecf20Sopenharmony_ci	struct crypto_skcipher *enc = ctx->enc;
648c2ecf20Sopenharmony_ci	struct crypto_authenc_keys keys;
658c2ecf20Sopenharmony_ci	int err = -EINVAL;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
688c2ecf20Sopenharmony_ci		goto out;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
718c2ecf20Sopenharmony_ci	crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc_esn) &
728c2ecf20Sopenharmony_ci				     CRYPTO_TFM_REQ_MASK);
738c2ecf20Sopenharmony_ci	err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
748c2ecf20Sopenharmony_ci	if (err)
758c2ecf20Sopenharmony_ci		goto out;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
788c2ecf20Sopenharmony_ci	crypto_skcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) &
798c2ecf20Sopenharmony_ci					 CRYPTO_TFM_REQ_MASK);
808c2ecf20Sopenharmony_ci	err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen);
818c2ecf20Sopenharmony_ciout:
828c2ecf20Sopenharmony_ci	memzero_explicit(&keys, sizeof(keys));
838c2ecf20Sopenharmony_ci	return err;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_genicv_tail(struct aead_request *req,
878c2ecf20Sopenharmony_ci					  unsigned int flags)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
908c2ecf20Sopenharmony_ci	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
918c2ecf20Sopenharmony_ci	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
928c2ecf20Sopenharmony_ci	struct crypto_ahash *auth = ctx->auth;
938c2ecf20Sopenharmony_ci	u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail,
948c2ecf20Sopenharmony_ci			     crypto_ahash_alignmask(auth) + 1);
958c2ecf20Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(authenc_esn);
968c2ecf20Sopenharmony_ci	unsigned int assoclen = req->assoclen;
978c2ecf20Sopenharmony_ci	unsigned int cryptlen = req->cryptlen;
988c2ecf20Sopenharmony_ci	struct scatterlist *dst = req->dst;
998c2ecf20Sopenharmony_ci	u32 tmp[2];
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/* Move high-order bits of sequence number back. */
1028c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
1038c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
1048c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(hash, dst, assoclen + cryptlen, authsize, 1);
1078c2ecf20Sopenharmony_ci	return 0;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic void authenc_esn_geniv_ahash_done(struct crypto_async_request *areq,
1118c2ecf20Sopenharmony_ci					 int err)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct aead_request *req = areq->data;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	err = err ?: crypto_authenc_esn_genicv_tail(req, 0);
1168c2ecf20Sopenharmony_ci	aead_request_complete(req, err);
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_genicv(struct aead_request *req,
1208c2ecf20Sopenharmony_ci				     unsigned int flags)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
1238c2ecf20Sopenharmony_ci	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
1248c2ecf20Sopenharmony_ci	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
1258c2ecf20Sopenharmony_ci	struct crypto_ahash *auth = ctx->auth;
1268c2ecf20Sopenharmony_ci	u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail,
1278c2ecf20Sopenharmony_ci			     crypto_ahash_alignmask(auth) + 1);
1288c2ecf20Sopenharmony_ci	struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
1298c2ecf20Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(authenc_esn);
1308c2ecf20Sopenharmony_ci	unsigned int assoclen = req->assoclen;
1318c2ecf20Sopenharmony_ci	unsigned int cryptlen = req->cryptlen;
1328c2ecf20Sopenharmony_ci	struct scatterlist *dst = req->dst;
1338c2ecf20Sopenharmony_ci	u32 tmp[2];
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (!authsize)
1368c2ecf20Sopenharmony_ci		return 0;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* Move high-order bits of sequence number to the end. */
1398c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
1408c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
1418c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	sg_init_table(areq_ctx->dst, 2);
1448c2ecf20Sopenharmony_ci	dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	ahash_request_set_tfm(ahreq, auth);
1478c2ecf20Sopenharmony_ci	ahash_request_set_crypt(ahreq, dst, hash, assoclen + cryptlen);
1488c2ecf20Sopenharmony_ci	ahash_request_set_callback(ahreq, flags,
1498c2ecf20Sopenharmony_ci				   authenc_esn_geniv_ahash_done, req);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return crypto_ahash_digest(ahreq) ?:
1528c2ecf20Sopenharmony_ci	       crypto_authenc_esn_genicv_tail(req, aead_request_flags(req));
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic void crypto_authenc_esn_encrypt_done(struct crypto_async_request *req,
1578c2ecf20Sopenharmony_ci					    int err)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct aead_request *areq = req->data;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (!err)
1628c2ecf20Sopenharmony_ci		err = crypto_authenc_esn_genicv(areq, 0);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	authenc_esn_request_complete(areq, err);
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
1708c2ecf20Sopenharmony_ci	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
1718c2ecf20Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	skcipher_request_set_sync_tfm(skreq, ctx->null);
1748c2ecf20Sopenharmony_ci	skcipher_request_set_callback(skreq, aead_request_flags(req),
1758c2ecf20Sopenharmony_ci				      NULL, NULL);
1768c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return crypto_skcipher_encrypt(skreq);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_encrypt(struct aead_request *req)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
1848c2ecf20Sopenharmony_ci	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
1858c2ecf20Sopenharmony_ci	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
1868c2ecf20Sopenharmony_ci	struct skcipher_request *skreq = (void *)(areq_ctx->tail +
1878c2ecf20Sopenharmony_ci						  ctx->reqoff);
1888c2ecf20Sopenharmony_ci	struct crypto_skcipher *enc = ctx->enc;
1898c2ecf20Sopenharmony_ci	unsigned int assoclen = req->assoclen;
1908c2ecf20Sopenharmony_ci	unsigned int cryptlen = req->cryptlen;
1918c2ecf20Sopenharmony_ci	struct scatterlist *src, *dst;
1928c2ecf20Sopenharmony_ci	int err;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	sg_init_table(areq_ctx->src, 2);
1958c2ecf20Sopenharmony_ci	src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen);
1968c2ecf20Sopenharmony_ci	dst = src;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (req->src != req->dst) {
1998c2ecf20Sopenharmony_ci		err = crypto_authenc_esn_copy(req, assoclen);
2008c2ecf20Sopenharmony_ci		if (err)
2018c2ecf20Sopenharmony_ci			return err;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		sg_init_table(areq_ctx->dst, 2);
2048c2ecf20Sopenharmony_ci		dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen);
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	skcipher_request_set_tfm(skreq, enc);
2088c2ecf20Sopenharmony_ci	skcipher_request_set_callback(skreq, aead_request_flags(req),
2098c2ecf20Sopenharmony_ci				      crypto_authenc_esn_encrypt_done, req);
2108c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	err = crypto_skcipher_encrypt(skreq);
2138c2ecf20Sopenharmony_ci	if (err)
2148c2ecf20Sopenharmony_ci		return err;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	return crypto_authenc_esn_genicv(req, aead_request_flags(req));
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
2208c2ecf20Sopenharmony_ci					   unsigned int flags)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
2238c2ecf20Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(authenc_esn);
2248c2ecf20Sopenharmony_ci	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
2258c2ecf20Sopenharmony_ci	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
2268c2ecf20Sopenharmony_ci	struct skcipher_request *skreq = (void *)(areq_ctx->tail +
2278c2ecf20Sopenharmony_ci						  ctx->reqoff);
2288c2ecf20Sopenharmony_ci	struct crypto_ahash *auth = ctx->auth;
2298c2ecf20Sopenharmony_ci	u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail,
2308c2ecf20Sopenharmony_ci			      crypto_ahash_alignmask(auth) + 1);
2318c2ecf20Sopenharmony_ci	unsigned int cryptlen = req->cryptlen - authsize;
2328c2ecf20Sopenharmony_ci	unsigned int assoclen = req->assoclen;
2338c2ecf20Sopenharmony_ci	struct scatterlist *dst = req->dst;
2348c2ecf20Sopenharmony_ci	u8 *ihash = ohash + crypto_ahash_digestsize(auth);
2358c2ecf20Sopenharmony_ci	u32 tmp[2];
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	if (!authsize)
2388c2ecf20Sopenharmony_ci		goto decrypt;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* Move high-order bits of sequence number back. */
2418c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
2428c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
2438c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	if (crypto_memneq(ihash, ohash, authsize))
2468c2ecf20Sopenharmony_ci		return -EBADMSG;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cidecrypt:
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	sg_init_table(areq_ctx->dst, 2);
2518c2ecf20Sopenharmony_ci	dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	skcipher_request_set_tfm(skreq, ctx->enc);
2548c2ecf20Sopenharmony_ci	skcipher_request_set_callback(skreq, flags,
2558c2ecf20Sopenharmony_ci				      req->base.complete, req->base.data);
2568c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return crypto_skcipher_decrypt(skreq);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic void authenc_esn_verify_ahash_done(struct crypto_async_request *areq,
2628c2ecf20Sopenharmony_ci					  int err)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct aead_request *req = areq->data;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	err = err ?: crypto_authenc_esn_decrypt_tail(req, 0);
2678c2ecf20Sopenharmony_ci	authenc_esn_request_complete(req, err);
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_decrypt(struct aead_request *req)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
2738c2ecf20Sopenharmony_ci	struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
2748c2ecf20Sopenharmony_ci	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
2758c2ecf20Sopenharmony_ci	struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
2768c2ecf20Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(authenc_esn);
2778c2ecf20Sopenharmony_ci	struct crypto_ahash *auth = ctx->auth;
2788c2ecf20Sopenharmony_ci	u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail,
2798c2ecf20Sopenharmony_ci			      crypto_ahash_alignmask(auth) + 1);
2808c2ecf20Sopenharmony_ci	unsigned int assoclen = req->assoclen;
2818c2ecf20Sopenharmony_ci	unsigned int cryptlen = req->cryptlen;
2828c2ecf20Sopenharmony_ci	u8 *ihash = ohash + crypto_ahash_digestsize(auth);
2838c2ecf20Sopenharmony_ci	struct scatterlist *dst = req->dst;
2848c2ecf20Sopenharmony_ci	u32 tmp[2];
2858c2ecf20Sopenharmony_ci	int err;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	cryptlen -= authsize;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (req->src != dst) {
2908c2ecf20Sopenharmony_ci		err = crypto_authenc_esn_copy(req, assoclen + cryptlen);
2918c2ecf20Sopenharmony_ci		if (err)
2928c2ecf20Sopenharmony_ci			return err;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen,
2968c2ecf20Sopenharmony_ci				 authsize, 0);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (!authsize)
2998c2ecf20Sopenharmony_ci		goto tail;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* Move high-order bits of sequence number to the end. */
3028c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
3038c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
3048c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	sg_init_table(areq_ctx->dst, 2);
3078c2ecf20Sopenharmony_ci	dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	ahash_request_set_tfm(ahreq, auth);
3108c2ecf20Sopenharmony_ci	ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen);
3118c2ecf20Sopenharmony_ci	ahash_request_set_callback(ahreq, aead_request_flags(req),
3128c2ecf20Sopenharmony_ci				   authenc_esn_verify_ahash_done, req);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	err = crypto_ahash_digest(ahreq);
3158c2ecf20Sopenharmony_ci	if (err)
3168c2ecf20Sopenharmony_ci		return err;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_citail:
3198c2ecf20Sopenharmony_ci	return crypto_authenc_esn_decrypt_tail(req, aead_request_flags(req));
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct aead_instance *inst = aead_alg_instance(tfm);
3258c2ecf20Sopenharmony_ci	struct authenc_esn_instance_ctx *ictx = aead_instance_ctx(inst);
3268c2ecf20Sopenharmony_ci	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
3278c2ecf20Sopenharmony_ci	struct crypto_ahash *auth;
3288c2ecf20Sopenharmony_ci	struct crypto_skcipher *enc;
3298c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *null;
3308c2ecf20Sopenharmony_ci	int err;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	auth = crypto_spawn_ahash(&ictx->auth);
3338c2ecf20Sopenharmony_ci	if (IS_ERR(auth))
3348c2ecf20Sopenharmony_ci		return PTR_ERR(auth);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	enc = crypto_spawn_skcipher(&ictx->enc);
3378c2ecf20Sopenharmony_ci	err = PTR_ERR(enc);
3388c2ecf20Sopenharmony_ci	if (IS_ERR(enc))
3398c2ecf20Sopenharmony_ci		goto err_free_ahash;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	null = crypto_get_default_null_skcipher();
3428c2ecf20Sopenharmony_ci	err = PTR_ERR(null);
3438c2ecf20Sopenharmony_ci	if (IS_ERR(null))
3448c2ecf20Sopenharmony_ci		goto err_free_skcipher;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	ctx->auth = auth;
3478c2ecf20Sopenharmony_ci	ctx->enc = enc;
3488c2ecf20Sopenharmony_ci	ctx->null = null;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth),
3518c2ecf20Sopenharmony_ci			    crypto_ahash_alignmask(auth) + 1);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	crypto_aead_set_reqsize(
3548c2ecf20Sopenharmony_ci		tfm,
3558c2ecf20Sopenharmony_ci		sizeof(struct authenc_esn_request_ctx) +
3568c2ecf20Sopenharmony_ci		ctx->reqoff +
3578c2ecf20Sopenharmony_ci		max_t(unsigned int,
3588c2ecf20Sopenharmony_ci		      crypto_ahash_reqsize(auth) +
3598c2ecf20Sopenharmony_ci		      sizeof(struct ahash_request),
3608c2ecf20Sopenharmony_ci		      sizeof(struct skcipher_request) +
3618c2ecf20Sopenharmony_ci		      crypto_skcipher_reqsize(enc)));
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return 0;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cierr_free_skcipher:
3668c2ecf20Sopenharmony_ci	crypto_free_skcipher(enc);
3678c2ecf20Sopenharmony_cierr_free_ahash:
3688c2ecf20Sopenharmony_ci	crypto_free_ahash(auth);
3698c2ecf20Sopenharmony_ci	return err;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	crypto_free_ahash(ctx->auth);
3778c2ecf20Sopenharmony_ci	crypto_free_skcipher(ctx->enc);
3788c2ecf20Sopenharmony_ci	crypto_put_default_null_skcipher();
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic void crypto_authenc_esn_free(struct aead_instance *inst)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct authenc_esn_instance_ctx *ctx = aead_instance_ctx(inst);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	crypto_drop_skcipher(&ctx->enc);
3868c2ecf20Sopenharmony_ci	crypto_drop_ahash(&ctx->auth);
3878c2ecf20Sopenharmony_ci	kfree(inst);
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic int crypto_authenc_esn_create(struct crypto_template *tmpl,
3918c2ecf20Sopenharmony_ci				     struct rtattr **tb)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	u32 mask;
3948c2ecf20Sopenharmony_ci	struct aead_instance *inst;
3958c2ecf20Sopenharmony_ci	struct authenc_esn_instance_ctx *ctx;
3968c2ecf20Sopenharmony_ci	struct hash_alg_common *auth;
3978c2ecf20Sopenharmony_ci	struct crypto_alg *auth_base;
3988c2ecf20Sopenharmony_ci	struct skcipher_alg *enc;
3998c2ecf20Sopenharmony_ci	int err;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask);
4028c2ecf20Sopenharmony_ci	if (err)
4038c2ecf20Sopenharmony_ci		return err;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
4068c2ecf20Sopenharmony_ci	if (!inst)
4078c2ecf20Sopenharmony_ci		return -ENOMEM;
4088c2ecf20Sopenharmony_ci	ctx = aead_instance_ctx(inst);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	err = crypto_grab_ahash(&ctx->auth, aead_crypto_instance(inst),
4118c2ecf20Sopenharmony_ci				crypto_attr_alg_name(tb[1]), 0, mask);
4128c2ecf20Sopenharmony_ci	if (err)
4138c2ecf20Sopenharmony_ci		goto err_free_inst;
4148c2ecf20Sopenharmony_ci	auth = crypto_spawn_ahash_alg(&ctx->auth);
4158c2ecf20Sopenharmony_ci	auth_base = &auth->base;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst),
4188c2ecf20Sopenharmony_ci				   crypto_attr_alg_name(tb[2]), 0, mask);
4198c2ecf20Sopenharmony_ci	if (err)
4208c2ecf20Sopenharmony_ci		goto err_free_inst;
4218c2ecf20Sopenharmony_ci	enc = crypto_spawn_skcipher_alg(&ctx->enc);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	err = -ENAMETOOLONG;
4248c2ecf20Sopenharmony_ci	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
4258c2ecf20Sopenharmony_ci		     "authencesn(%s,%s)", auth_base->cra_name,
4268c2ecf20Sopenharmony_ci		     enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
4278c2ecf20Sopenharmony_ci		goto err_free_inst;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
4308c2ecf20Sopenharmony_ci		     "authencesn(%s,%s)", auth_base->cra_driver_name,
4318c2ecf20Sopenharmony_ci		     enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
4328c2ecf20Sopenharmony_ci		goto err_free_inst;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
4358c2ecf20Sopenharmony_ci				      auth_base->cra_priority;
4368c2ecf20Sopenharmony_ci	inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
4378c2ecf20Sopenharmony_ci	inst->alg.base.cra_alignmask = auth_base->cra_alignmask |
4388c2ecf20Sopenharmony_ci				       enc->base.cra_alignmask;
4398c2ecf20Sopenharmony_ci	inst->alg.base.cra_ctxsize = sizeof(struct crypto_authenc_esn_ctx);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc);
4428c2ecf20Sopenharmony_ci	inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc);
4438c2ecf20Sopenharmony_ci	inst->alg.maxauthsize = auth->digestsize;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	inst->alg.init = crypto_authenc_esn_init_tfm;
4468c2ecf20Sopenharmony_ci	inst->alg.exit = crypto_authenc_esn_exit_tfm;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	inst->alg.setkey = crypto_authenc_esn_setkey;
4498c2ecf20Sopenharmony_ci	inst->alg.setauthsize = crypto_authenc_esn_setauthsize;
4508c2ecf20Sopenharmony_ci	inst->alg.encrypt = crypto_authenc_esn_encrypt;
4518c2ecf20Sopenharmony_ci	inst->alg.decrypt = crypto_authenc_esn_decrypt;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	inst->free = crypto_authenc_esn_free;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	err = aead_register_instance(tmpl, inst);
4568c2ecf20Sopenharmony_ci	if (err) {
4578c2ecf20Sopenharmony_cierr_free_inst:
4588c2ecf20Sopenharmony_ci		crypto_authenc_esn_free(inst);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci	return err;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic struct crypto_template crypto_authenc_esn_tmpl = {
4648c2ecf20Sopenharmony_ci	.name = "authencesn",
4658c2ecf20Sopenharmony_ci	.create = crypto_authenc_esn_create,
4668c2ecf20Sopenharmony_ci	.module = THIS_MODULE,
4678c2ecf20Sopenharmony_ci};
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic int __init crypto_authenc_esn_module_init(void)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	return crypto_register_template(&crypto_authenc_esn_tmpl);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic void __exit crypto_authenc_esn_module_exit(void)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	crypto_unregister_template(&crypto_authenc_esn_tmpl);
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cisubsys_initcall(crypto_authenc_esn_module_init);
4808c2ecf20Sopenharmony_cimodule_exit(crypto_authenc_esn_module_exit);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4838c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
4848c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AEAD wrapper for IPsec with extended sequence numbers");
4858c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("authencesn");
486