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