162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * authencesn.c - AEAD wrapper for IPsec with extended sequence numbers, 462306a36Sopenharmony_ci * derived from authenc.c 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2010 secunet Security Networks AG 762306a36Sopenharmony_ci * Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com> 862306a36Sopenharmony_ci * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <crypto/internal/aead.h> 1262306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1362306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 1462306a36Sopenharmony_ci#include <crypto/authenc.h> 1562306a36Sopenharmony_ci#include <crypto/null.h> 1662306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1762306a36Sopenharmony_ci#include <linux/err.h> 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/rtnetlink.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/spinlock.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct authenc_esn_instance_ctx { 2662306a36Sopenharmony_ci struct crypto_ahash_spawn auth; 2762306a36Sopenharmony_ci struct crypto_skcipher_spawn enc; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistruct crypto_authenc_esn_ctx { 3162306a36Sopenharmony_ci unsigned int reqoff; 3262306a36Sopenharmony_ci struct crypto_ahash *auth; 3362306a36Sopenharmony_ci struct crypto_skcipher *enc; 3462306a36Sopenharmony_ci struct crypto_sync_skcipher *null; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct authenc_esn_request_ctx { 3862306a36Sopenharmony_ci struct scatterlist src[2]; 3962306a36Sopenharmony_ci struct scatterlist dst[2]; 4062306a36Sopenharmony_ci char tail[]; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic void authenc_esn_request_complete(struct aead_request *req, int err) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci if (err != -EINPROGRESS) 4662306a36Sopenharmony_ci aead_request_complete(req, err); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int crypto_authenc_esn_setauthsize(struct crypto_aead *authenc_esn, 5062306a36Sopenharmony_ci unsigned int authsize) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci if (authsize > 0 && authsize < 4) 5362306a36Sopenharmony_ci return -EINVAL; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return 0; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *key, 5962306a36Sopenharmony_ci unsigned int keylen) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); 6262306a36Sopenharmony_ci struct crypto_ahash *auth = ctx->auth; 6362306a36Sopenharmony_ci struct crypto_skcipher *enc = ctx->enc; 6462306a36Sopenharmony_ci struct crypto_authenc_keys keys; 6562306a36Sopenharmony_ci int err = -EINVAL; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) 6862306a36Sopenharmony_ci goto out; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); 7162306a36Sopenharmony_ci crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc_esn) & 7262306a36Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 7362306a36Sopenharmony_ci err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen); 7462306a36Sopenharmony_ci if (err) 7562306a36Sopenharmony_ci goto out; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK); 7862306a36Sopenharmony_ci crypto_skcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) & 7962306a36Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 8062306a36Sopenharmony_ci err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen); 8162306a36Sopenharmony_ciout: 8262306a36Sopenharmony_ci memzero_explicit(&keys, sizeof(keys)); 8362306a36Sopenharmony_ci return err; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic int crypto_authenc_esn_genicv_tail(struct aead_request *req, 8762306a36Sopenharmony_ci unsigned int flags) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); 9062306a36Sopenharmony_ci struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); 9162306a36Sopenharmony_ci struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); 9262306a36Sopenharmony_ci struct crypto_ahash *auth = ctx->auth; 9362306a36Sopenharmony_ci u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail, 9462306a36Sopenharmony_ci crypto_ahash_alignmask(auth) + 1); 9562306a36Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(authenc_esn); 9662306a36Sopenharmony_ci unsigned int assoclen = req->assoclen; 9762306a36Sopenharmony_ci unsigned int cryptlen = req->cryptlen; 9862306a36Sopenharmony_ci struct scatterlist *dst = req->dst; 9962306a36Sopenharmony_ci u32 tmp[2]; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Move high-order bits of sequence number back. */ 10262306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); 10362306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); 10462306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci scatterwalk_map_and_copy(hash, dst, assoclen + cryptlen, authsize, 1); 10762306a36Sopenharmony_ci return 0; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void authenc_esn_geniv_ahash_done(void *data, int err) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct aead_request *req = data; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci err = err ?: crypto_authenc_esn_genicv_tail(req, 0); 11562306a36Sopenharmony_ci aead_request_complete(req, err); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int crypto_authenc_esn_genicv(struct aead_request *req, 11962306a36Sopenharmony_ci unsigned int flags) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); 12262306a36Sopenharmony_ci struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); 12362306a36Sopenharmony_ci struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); 12462306a36Sopenharmony_ci struct crypto_ahash *auth = ctx->auth; 12562306a36Sopenharmony_ci u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail, 12662306a36Sopenharmony_ci crypto_ahash_alignmask(auth) + 1); 12762306a36Sopenharmony_ci struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); 12862306a36Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(authenc_esn); 12962306a36Sopenharmony_ci unsigned int assoclen = req->assoclen; 13062306a36Sopenharmony_ci unsigned int cryptlen = req->cryptlen; 13162306a36Sopenharmony_ci struct scatterlist *dst = req->dst; 13262306a36Sopenharmony_ci u32 tmp[2]; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (!authsize) 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Move high-order bits of sequence number to the end. */ 13862306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp, dst, 0, 8, 0); 13962306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); 14062306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci sg_init_table(areq_ctx->dst, 2); 14362306a36Sopenharmony_ci dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci ahash_request_set_tfm(ahreq, auth); 14662306a36Sopenharmony_ci ahash_request_set_crypt(ahreq, dst, hash, assoclen + cryptlen); 14762306a36Sopenharmony_ci ahash_request_set_callback(ahreq, flags, 14862306a36Sopenharmony_ci authenc_esn_geniv_ahash_done, req); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return crypto_ahash_digest(ahreq) ?: 15162306a36Sopenharmony_ci crypto_authenc_esn_genicv_tail(req, aead_request_flags(req)); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void crypto_authenc_esn_encrypt_done(void *data, int err) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct aead_request *areq = data; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (!err) 16062306a36Sopenharmony_ci err = crypto_authenc_esn_genicv(areq, 0); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci authenc_esn_request_complete(areq, err); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); 16862306a36Sopenharmony_ci struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); 16962306a36Sopenharmony_ci SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci skcipher_request_set_sync_tfm(skreq, ctx->null); 17262306a36Sopenharmony_ci skcipher_request_set_callback(skreq, aead_request_flags(req), 17362306a36Sopenharmony_ci NULL, NULL); 17462306a36Sopenharmony_ci skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci return crypto_skcipher_encrypt(skreq); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int crypto_authenc_esn_encrypt(struct aead_request *req) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); 18262306a36Sopenharmony_ci struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); 18362306a36Sopenharmony_ci struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); 18462306a36Sopenharmony_ci struct skcipher_request *skreq = (void *)(areq_ctx->tail + 18562306a36Sopenharmony_ci ctx->reqoff); 18662306a36Sopenharmony_ci struct crypto_skcipher *enc = ctx->enc; 18762306a36Sopenharmony_ci unsigned int assoclen = req->assoclen; 18862306a36Sopenharmony_ci unsigned int cryptlen = req->cryptlen; 18962306a36Sopenharmony_ci struct scatterlist *src, *dst; 19062306a36Sopenharmony_ci int err; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci sg_init_table(areq_ctx->src, 2); 19362306a36Sopenharmony_ci src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen); 19462306a36Sopenharmony_ci dst = src; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (req->src != req->dst) { 19762306a36Sopenharmony_ci err = crypto_authenc_esn_copy(req, assoclen); 19862306a36Sopenharmony_ci if (err) 19962306a36Sopenharmony_ci return err; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci sg_init_table(areq_ctx->dst, 2); 20262306a36Sopenharmony_ci dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci skcipher_request_set_tfm(skreq, enc); 20662306a36Sopenharmony_ci skcipher_request_set_callback(skreq, aead_request_flags(req), 20762306a36Sopenharmony_ci crypto_authenc_esn_encrypt_done, req); 20862306a36Sopenharmony_ci skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci err = crypto_skcipher_encrypt(skreq); 21162306a36Sopenharmony_ci if (err) 21262306a36Sopenharmony_ci return err; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return crypto_authenc_esn_genicv(req, aead_request_flags(req)); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int crypto_authenc_esn_decrypt_tail(struct aead_request *req, 21862306a36Sopenharmony_ci unsigned int flags) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); 22162306a36Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(authenc_esn); 22262306a36Sopenharmony_ci struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); 22362306a36Sopenharmony_ci struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); 22462306a36Sopenharmony_ci struct skcipher_request *skreq = (void *)(areq_ctx->tail + 22562306a36Sopenharmony_ci ctx->reqoff); 22662306a36Sopenharmony_ci struct crypto_ahash *auth = ctx->auth; 22762306a36Sopenharmony_ci u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail, 22862306a36Sopenharmony_ci crypto_ahash_alignmask(auth) + 1); 22962306a36Sopenharmony_ci unsigned int cryptlen = req->cryptlen - authsize; 23062306a36Sopenharmony_ci unsigned int assoclen = req->assoclen; 23162306a36Sopenharmony_ci struct scatterlist *dst = req->dst; 23262306a36Sopenharmony_ci u8 *ihash = ohash + crypto_ahash_digestsize(auth); 23362306a36Sopenharmony_ci u32 tmp[2]; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (!authsize) 23662306a36Sopenharmony_ci goto decrypt; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Move high-order bits of sequence number back. */ 23962306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); 24062306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); 24162306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (crypto_memneq(ihash, ohash, authsize)) 24462306a36Sopenharmony_ci return -EBADMSG; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cidecrypt: 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci sg_init_table(areq_ctx->dst, 2); 24962306a36Sopenharmony_ci dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci skcipher_request_set_tfm(skreq, ctx->enc); 25262306a36Sopenharmony_ci skcipher_request_set_callback(skreq, flags, 25362306a36Sopenharmony_ci req->base.complete, req->base.data); 25462306a36Sopenharmony_ci skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return crypto_skcipher_decrypt(skreq); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic void authenc_esn_verify_ahash_done(void *data, int err) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct aead_request *req = data; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci err = err ?: crypto_authenc_esn_decrypt_tail(req, 0); 26462306a36Sopenharmony_ci authenc_esn_request_complete(req, err); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int crypto_authenc_esn_decrypt(struct aead_request *req) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); 27062306a36Sopenharmony_ci struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); 27162306a36Sopenharmony_ci struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); 27262306a36Sopenharmony_ci struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); 27362306a36Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(authenc_esn); 27462306a36Sopenharmony_ci struct crypto_ahash *auth = ctx->auth; 27562306a36Sopenharmony_ci u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail, 27662306a36Sopenharmony_ci crypto_ahash_alignmask(auth) + 1); 27762306a36Sopenharmony_ci unsigned int assoclen = req->assoclen; 27862306a36Sopenharmony_ci unsigned int cryptlen = req->cryptlen; 27962306a36Sopenharmony_ci u8 *ihash = ohash + crypto_ahash_digestsize(auth); 28062306a36Sopenharmony_ci struct scatterlist *dst = req->dst; 28162306a36Sopenharmony_ci u32 tmp[2]; 28262306a36Sopenharmony_ci int err; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci cryptlen -= authsize; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (req->src != dst) { 28762306a36Sopenharmony_ci err = crypto_authenc_esn_copy(req, assoclen + cryptlen); 28862306a36Sopenharmony_ci if (err) 28962306a36Sopenharmony_ci return err; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen, 29362306a36Sopenharmony_ci authsize, 0); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (!authsize) 29662306a36Sopenharmony_ci goto tail; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* Move high-order bits of sequence number to the end. */ 29962306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp, dst, 0, 8, 0); 30062306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); 30162306a36Sopenharmony_ci scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci sg_init_table(areq_ctx->dst, 2); 30462306a36Sopenharmony_ci dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci ahash_request_set_tfm(ahreq, auth); 30762306a36Sopenharmony_ci ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen); 30862306a36Sopenharmony_ci ahash_request_set_callback(ahreq, aead_request_flags(req), 30962306a36Sopenharmony_ci authenc_esn_verify_ahash_done, req); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci err = crypto_ahash_digest(ahreq); 31262306a36Sopenharmony_ci if (err) 31362306a36Sopenharmony_ci return err; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_citail: 31662306a36Sopenharmony_ci return crypto_authenc_esn_decrypt_tail(req, aead_request_flags(req)); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct aead_instance *inst = aead_alg_instance(tfm); 32262306a36Sopenharmony_ci struct authenc_esn_instance_ctx *ictx = aead_instance_ctx(inst); 32362306a36Sopenharmony_ci struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); 32462306a36Sopenharmony_ci struct crypto_ahash *auth; 32562306a36Sopenharmony_ci struct crypto_skcipher *enc; 32662306a36Sopenharmony_ci struct crypto_sync_skcipher *null; 32762306a36Sopenharmony_ci int err; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci auth = crypto_spawn_ahash(&ictx->auth); 33062306a36Sopenharmony_ci if (IS_ERR(auth)) 33162306a36Sopenharmony_ci return PTR_ERR(auth); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci enc = crypto_spawn_skcipher(&ictx->enc); 33462306a36Sopenharmony_ci err = PTR_ERR(enc); 33562306a36Sopenharmony_ci if (IS_ERR(enc)) 33662306a36Sopenharmony_ci goto err_free_ahash; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci null = crypto_get_default_null_skcipher(); 33962306a36Sopenharmony_ci err = PTR_ERR(null); 34062306a36Sopenharmony_ci if (IS_ERR(null)) 34162306a36Sopenharmony_ci goto err_free_skcipher; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci ctx->auth = auth; 34462306a36Sopenharmony_ci ctx->enc = enc; 34562306a36Sopenharmony_ci ctx->null = null; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth), 34862306a36Sopenharmony_ci crypto_ahash_alignmask(auth) + 1); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci crypto_aead_set_reqsize( 35162306a36Sopenharmony_ci tfm, 35262306a36Sopenharmony_ci sizeof(struct authenc_esn_request_ctx) + 35362306a36Sopenharmony_ci ctx->reqoff + 35462306a36Sopenharmony_ci max_t(unsigned int, 35562306a36Sopenharmony_ci crypto_ahash_reqsize(auth) + 35662306a36Sopenharmony_ci sizeof(struct ahash_request), 35762306a36Sopenharmony_ci sizeof(struct skcipher_request) + 35862306a36Sopenharmony_ci crypto_skcipher_reqsize(enc))); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cierr_free_skcipher: 36362306a36Sopenharmony_ci crypto_free_skcipher(enc); 36462306a36Sopenharmony_cierr_free_ahash: 36562306a36Sopenharmony_ci crypto_free_ahash(auth); 36662306a36Sopenharmony_ci return err; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci crypto_free_ahash(ctx->auth); 37462306a36Sopenharmony_ci crypto_free_skcipher(ctx->enc); 37562306a36Sopenharmony_ci crypto_put_default_null_skcipher(); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void crypto_authenc_esn_free(struct aead_instance *inst) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct authenc_esn_instance_ctx *ctx = aead_instance_ctx(inst); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci crypto_drop_skcipher(&ctx->enc); 38362306a36Sopenharmony_ci crypto_drop_ahash(&ctx->auth); 38462306a36Sopenharmony_ci kfree(inst); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int crypto_authenc_esn_create(struct crypto_template *tmpl, 38862306a36Sopenharmony_ci struct rtattr **tb) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci u32 mask; 39162306a36Sopenharmony_ci struct aead_instance *inst; 39262306a36Sopenharmony_ci struct authenc_esn_instance_ctx *ctx; 39362306a36Sopenharmony_ci struct hash_alg_common *auth; 39462306a36Sopenharmony_ci struct crypto_alg *auth_base; 39562306a36Sopenharmony_ci struct skcipher_alg *enc; 39662306a36Sopenharmony_ci int err; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask); 39962306a36Sopenharmony_ci if (err) 40062306a36Sopenharmony_ci return err; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); 40362306a36Sopenharmony_ci if (!inst) 40462306a36Sopenharmony_ci return -ENOMEM; 40562306a36Sopenharmony_ci ctx = aead_instance_ctx(inst); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci err = crypto_grab_ahash(&ctx->auth, aead_crypto_instance(inst), 40862306a36Sopenharmony_ci crypto_attr_alg_name(tb[1]), 0, mask); 40962306a36Sopenharmony_ci if (err) 41062306a36Sopenharmony_ci goto err_free_inst; 41162306a36Sopenharmony_ci auth = crypto_spawn_ahash_alg(&ctx->auth); 41262306a36Sopenharmony_ci auth_base = &auth->base; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst), 41562306a36Sopenharmony_ci crypto_attr_alg_name(tb[2]), 0, mask); 41662306a36Sopenharmony_ci if (err) 41762306a36Sopenharmony_ci goto err_free_inst; 41862306a36Sopenharmony_ci enc = crypto_spawn_skcipher_alg(&ctx->enc); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci err = -ENAMETOOLONG; 42162306a36Sopenharmony_ci if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 42262306a36Sopenharmony_ci "authencesn(%s,%s)", auth_base->cra_name, 42362306a36Sopenharmony_ci enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME) 42462306a36Sopenharmony_ci goto err_free_inst; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 42762306a36Sopenharmony_ci "authencesn(%s,%s)", auth_base->cra_driver_name, 42862306a36Sopenharmony_ci enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) 42962306a36Sopenharmony_ci goto err_free_inst; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci inst->alg.base.cra_priority = enc->base.cra_priority * 10 + 43262306a36Sopenharmony_ci auth_base->cra_priority; 43362306a36Sopenharmony_ci inst->alg.base.cra_blocksize = enc->base.cra_blocksize; 43462306a36Sopenharmony_ci inst->alg.base.cra_alignmask = auth_base->cra_alignmask | 43562306a36Sopenharmony_ci enc->base.cra_alignmask; 43662306a36Sopenharmony_ci inst->alg.base.cra_ctxsize = sizeof(struct crypto_authenc_esn_ctx); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc); 43962306a36Sopenharmony_ci inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc); 44062306a36Sopenharmony_ci inst->alg.maxauthsize = auth->digestsize; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci inst->alg.init = crypto_authenc_esn_init_tfm; 44362306a36Sopenharmony_ci inst->alg.exit = crypto_authenc_esn_exit_tfm; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci inst->alg.setkey = crypto_authenc_esn_setkey; 44662306a36Sopenharmony_ci inst->alg.setauthsize = crypto_authenc_esn_setauthsize; 44762306a36Sopenharmony_ci inst->alg.encrypt = crypto_authenc_esn_encrypt; 44862306a36Sopenharmony_ci inst->alg.decrypt = crypto_authenc_esn_decrypt; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci inst->free = crypto_authenc_esn_free; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci err = aead_register_instance(tmpl, inst); 45362306a36Sopenharmony_ci if (err) { 45462306a36Sopenharmony_cierr_free_inst: 45562306a36Sopenharmony_ci crypto_authenc_esn_free(inst); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci return err; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic struct crypto_template crypto_authenc_esn_tmpl = { 46162306a36Sopenharmony_ci .name = "authencesn", 46262306a36Sopenharmony_ci .create = crypto_authenc_esn_create, 46362306a36Sopenharmony_ci .module = THIS_MODULE, 46462306a36Sopenharmony_ci}; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int __init crypto_authenc_esn_module_init(void) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci return crypto_register_template(&crypto_authenc_esn_tmpl); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic void __exit crypto_authenc_esn_module_exit(void) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci crypto_unregister_template(&crypto_authenc_esn_tmpl); 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cisubsys_initcall(crypto_authenc_esn_module_init); 47762306a36Sopenharmony_cimodule_exit(crypto_authenc_esn_module_exit); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 48062306a36Sopenharmony_ciMODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>"); 48162306a36Sopenharmony_ciMODULE_DESCRIPTION("AEAD wrapper for IPsec with extended sequence numbers"); 48262306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("authencesn"); 483