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