162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * GCM: Galois/Counter Mode.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <crypto/gf128mul.h>
962306a36Sopenharmony_ci#include <crypto/internal/aead.h>
1062306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
1162306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1262306a36Sopenharmony_ci#include <crypto/null.h>
1362306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
1462306a36Sopenharmony_ci#include <crypto/gcm.h>
1562306a36Sopenharmony_ci#include <crypto/hash.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct gcm_instance_ctx {
2362306a36Sopenharmony_ci	struct crypto_skcipher_spawn ctr;
2462306a36Sopenharmony_ci	struct crypto_ahash_spawn ghash;
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct crypto_gcm_ctx {
2862306a36Sopenharmony_ci	struct crypto_skcipher *ctr;
2962306a36Sopenharmony_ci	struct crypto_ahash *ghash;
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct crypto_rfc4106_ctx {
3362306a36Sopenharmony_ci	struct crypto_aead *child;
3462306a36Sopenharmony_ci	u8 nonce[4];
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistruct crypto_rfc4106_req_ctx {
3862306a36Sopenharmony_ci	struct scatterlist src[3];
3962306a36Sopenharmony_ci	struct scatterlist dst[3];
4062306a36Sopenharmony_ci	struct aead_request subreq;
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct crypto_rfc4543_instance_ctx {
4462306a36Sopenharmony_ci	struct crypto_aead_spawn aead;
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct crypto_rfc4543_ctx {
4862306a36Sopenharmony_ci	struct crypto_aead *child;
4962306a36Sopenharmony_ci	struct crypto_sync_skcipher *null;
5062306a36Sopenharmony_ci	u8 nonce[4];
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct crypto_rfc4543_req_ctx {
5462306a36Sopenharmony_ci	struct aead_request subreq;
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistruct crypto_gcm_ghash_ctx {
5862306a36Sopenharmony_ci	unsigned int cryptlen;
5962306a36Sopenharmony_ci	struct scatterlist *src;
6062306a36Sopenharmony_ci	int (*complete)(struct aead_request *req, u32 flags);
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistruct crypto_gcm_req_priv_ctx {
6462306a36Sopenharmony_ci	u8 iv[16];
6562306a36Sopenharmony_ci	u8 auth_tag[16];
6662306a36Sopenharmony_ci	u8 iauth_tag[16];
6762306a36Sopenharmony_ci	struct scatterlist src[3];
6862306a36Sopenharmony_ci	struct scatterlist dst[3];
6962306a36Sopenharmony_ci	struct scatterlist sg;
7062306a36Sopenharmony_ci	struct crypto_gcm_ghash_ctx ghash_ctx;
7162306a36Sopenharmony_ci	union {
7262306a36Sopenharmony_ci		struct ahash_request ahreq;
7362306a36Sopenharmony_ci		struct skcipher_request skreq;
7462306a36Sopenharmony_ci	} u;
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic struct {
7862306a36Sopenharmony_ci	u8 buf[16];
7962306a36Sopenharmony_ci	struct scatterlist sg;
8062306a36Sopenharmony_ci} *gcm_zeroes;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx(
8562306a36Sopenharmony_ci	struct aead_request *req)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
9362306a36Sopenharmony_ci			     unsigned int keylen)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
9662306a36Sopenharmony_ci	struct crypto_ahash *ghash = ctx->ghash;
9762306a36Sopenharmony_ci	struct crypto_skcipher *ctr = ctx->ctr;
9862306a36Sopenharmony_ci	struct {
9962306a36Sopenharmony_ci		be128 hash;
10062306a36Sopenharmony_ci		u8 iv[16];
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci		struct crypto_wait wait;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		struct scatterlist sg[1];
10562306a36Sopenharmony_ci		struct skcipher_request req;
10662306a36Sopenharmony_ci	} *data;
10762306a36Sopenharmony_ci	int err;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
11062306a36Sopenharmony_ci	crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
11162306a36Sopenharmony_ci				       CRYPTO_TFM_REQ_MASK);
11262306a36Sopenharmony_ci	err = crypto_skcipher_setkey(ctr, key, keylen);
11362306a36Sopenharmony_ci	if (err)
11462306a36Sopenharmony_ci		return err;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	data = kzalloc(sizeof(*data) + crypto_skcipher_reqsize(ctr),
11762306a36Sopenharmony_ci		       GFP_KERNEL);
11862306a36Sopenharmony_ci	if (!data)
11962306a36Sopenharmony_ci		return -ENOMEM;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	crypto_init_wait(&data->wait);
12262306a36Sopenharmony_ci	sg_init_one(data->sg, &data->hash, sizeof(data->hash));
12362306a36Sopenharmony_ci	skcipher_request_set_tfm(&data->req, ctr);
12462306a36Sopenharmony_ci	skcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP |
12562306a36Sopenharmony_ci						  CRYPTO_TFM_REQ_MAY_BACKLOG,
12662306a36Sopenharmony_ci				      crypto_req_done,
12762306a36Sopenharmony_ci				      &data->wait);
12862306a36Sopenharmony_ci	skcipher_request_set_crypt(&data->req, data->sg, data->sg,
12962306a36Sopenharmony_ci				   sizeof(data->hash), data->iv);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	err = crypto_wait_req(crypto_skcipher_encrypt(&data->req),
13262306a36Sopenharmony_ci							&data->wait);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (err)
13562306a36Sopenharmony_ci		goto out;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	crypto_ahash_clear_flags(ghash, CRYPTO_TFM_REQ_MASK);
13862306a36Sopenharmony_ci	crypto_ahash_set_flags(ghash, crypto_aead_get_flags(aead) &
13962306a36Sopenharmony_ci			       CRYPTO_TFM_REQ_MASK);
14062306a36Sopenharmony_ci	err = crypto_ahash_setkey(ghash, (u8 *)&data->hash, sizeof(be128));
14162306a36Sopenharmony_ciout:
14262306a36Sopenharmony_ci	kfree_sensitive(data);
14362306a36Sopenharmony_ci	return err;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int crypto_gcm_setauthsize(struct crypto_aead *tfm,
14762306a36Sopenharmony_ci				  unsigned int authsize)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	return crypto_gcm_check_authsize(authsize);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic void crypto_gcm_init_common(struct aead_request *req)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
15562306a36Sopenharmony_ci	__be32 counter = cpu_to_be32(1);
15662306a36Sopenharmony_ci	struct scatterlist *sg;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag));
15962306a36Sopenharmony_ci	memcpy(pctx->iv, req->iv, GCM_AES_IV_SIZE);
16062306a36Sopenharmony_ci	memcpy(pctx->iv + GCM_AES_IV_SIZE, &counter, 4);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	sg_init_table(pctx->src, 3);
16362306a36Sopenharmony_ci	sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag));
16462306a36Sopenharmony_ci	sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen);
16562306a36Sopenharmony_ci	if (sg != pctx->src + 1)
16662306a36Sopenharmony_ci		sg_chain(pctx->src, 2, sg);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (req->src != req->dst) {
16962306a36Sopenharmony_ci		sg_init_table(pctx->dst, 3);
17062306a36Sopenharmony_ci		sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag));
17162306a36Sopenharmony_ci		sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen);
17262306a36Sopenharmony_ci		if (sg != pctx->dst + 1)
17362306a36Sopenharmony_ci			sg_chain(pctx->dst, 2, sg);
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void crypto_gcm_init_crypt(struct aead_request *req,
17862306a36Sopenharmony_ci				  unsigned int cryptlen)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
18162306a36Sopenharmony_ci	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
18262306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
18362306a36Sopenharmony_ci	struct skcipher_request *skreq = &pctx->u.skreq;
18462306a36Sopenharmony_ci	struct scatterlist *dst;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	dst = req->src == req->dst ? pctx->src : pctx->dst;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	skcipher_request_set_tfm(skreq, ctx->ctr);
18962306a36Sopenharmony_ci	skcipher_request_set_crypt(skreq, pctx->src, dst,
19062306a36Sopenharmony_ci				     cryptlen + sizeof(pctx->auth_tag),
19162306a36Sopenharmony_ci				     pctx->iv);
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic inline unsigned int gcm_remain(unsigned int len)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	len &= 0xfU;
19762306a36Sopenharmony_ci	return len ? 16 - len : 0;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void gcm_hash_len_done(void *data, int err);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic int gcm_hash_update(struct aead_request *req,
20362306a36Sopenharmony_ci			   crypto_completion_t compl,
20462306a36Sopenharmony_ci			   struct scatterlist *src,
20562306a36Sopenharmony_ci			   unsigned int len, u32 flags)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
20862306a36Sopenharmony_ci	struct ahash_request *ahreq = &pctx->u.ahreq;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ahash_request_set_callback(ahreq, flags, compl, req);
21162306a36Sopenharmony_ci	ahash_request_set_crypt(ahreq, src, NULL, len);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return crypto_ahash_update(ahreq);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int gcm_hash_remain(struct aead_request *req,
21762306a36Sopenharmony_ci			   unsigned int remain,
21862306a36Sopenharmony_ci			   crypto_completion_t compl, u32 flags)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	return gcm_hash_update(req, compl, &gcm_zeroes->sg, remain, flags);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic int gcm_hash_len(struct aead_request *req, u32 flags)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
22662306a36Sopenharmony_ci	struct ahash_request *ahreq = &pctx->u.ahreq;
22762306a36Sopenharmony_ci	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
22862306a36Sopenharmony_ci	be128 lengths;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	lengths.a = cpu_to_be64(req->assoclen * 8);
23162306a36Sopenharmony_ci	lengths.b = cpu_to_be64(gctx->cryptlen * 8);
23262306a36Sopenharmony_ci	memcpy(pctx->iauth_tag, &lengths, 16);
23362306a36Sopenharmony_ci	sg_init_one(&pctx->sg, pctx->iauth_tag, 16);
23462306a36Sopenharmony_ci	ahash_request_set_callback(ahreq, flags, gcm_hash_len_done, req);
23562306a36Sopenharmony_ci	ahash_request_set_crypt(ahreq, &pctx->sg,
23662306a36Sopenharmony_ci				pctx->iauth_tag, sizeof(lengths));
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return crypto_ahash_finup(ahreq);
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int gcm_hash_len_continue(struct aead_request *req, u32 flags)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
24462306a36Sopenharmony_ci	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return gctx->complete(req, flags);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void gcm_hash_len_done(void *data, int err)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct aead_request *req = data;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (err)
25462306a36Sopenharmony_ci		goto out;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	err = gcm_hash_len_continue(req, 0);
25762306a36Sopenharmony_ci	if (err == -EINPROGRESS)
25862306a36Sopenharmony_ci		return;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ciout:
26162306a36Sopenharmony_ci	aead_request_complete(req, err);
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int gcm_hash_crypt_remain_continue(struct aead_request *req, u32 flags)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	return gcm_hash_len(req, flags) ?:
26762306a36Sopenharmony_ci	       gcm_hash_len_continue(req, flags);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void gcm_hash_crypt_remain_done(void *data, int err)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	struct aead_request *req = data;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (err)
27562306a36Sopenharmony_ci		goto out;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	err = gcm_hash_crypt_remain_continue(req, 0);
27862306a36Sopenharmony_ci	if (err == -EINPROGRESS)
27962306a36Sopenharmony_ci		return;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ciout:
28262306a36Sopenharmony_ci	aead_request_complete(req, err);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic int gcm_hash_crypt_continue(struct aead_request *req, u32 flags)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
28862306a36Sopenharmony_ci	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
28962306a36Sopenharmony_ci	unsigned int remain;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	remain = gcm_remain(gctx->cryptlen);
29262306a36Sopenharmony_ci	if (remain)
29362306a36Sopenharmony_ci		return gcm_hash_remain(req, remain,
29462306a36Sopenharmony_ci				       gcm_hash_crypt_remain_done, flags) ?:
29562306a36Sopenharmony_ci		       gcm_hash_crypt_remain_continue(req, flags);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return gcm_hash_crypt_remain_continue(req, flags);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic void gcm_hash_crypt_done(void *data, int err)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct aead_request *req = data;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (err)
30562306a36Sopenharmony_ci		goto out;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	err = gcm_hash_crypt_continue(req, 0);
30862306a36Sopenharmony_ci	if (err == -EINPROGRESS)
30962306a36Sopenharmony_ci		return;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ciout:
31262306a36Sopenharmony_ci	aead_request_complete(req, err);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int gcm_hash_assoc_remain_continue(struct aead_request *req, u32 flags)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
31862306a36Sopenharmony_ci	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (gctx->cryptlen)
32162306a36Sopenharmony_ci		return gcm_hash_update(req, gcm_hash_crypt_done,
32262306a36Sopenharmony_ci				       gctx->src, gctx->cryptlen, flags) ?:
32362306a36Sopenharmony_ci		       gcm_hash_crypt_continue(req, flags);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	return gcm_hash_crypt_remain_continue(req, flags);
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic void gcm_hash_assoc_remain_done(void *data, int err)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct aead_request *req = data;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (err)
33362306a36Sopenharmony_ci		goto out;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	err = gcm_hash_assoc_remain_continue(req, 0);
33662306a36Sopenharmony_ci	if (err == -EINPROGRESS)
33762306a36Sopenharmony_ci		return;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciout:
34062306a36Sopenharmony_ci	aead_request_complete(req, err);
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int gcm_hash_assoc_continue(struct aead_request *req, u32 flags)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	unsigned int remain;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	remain = gcm_remain(req->assoclen);
34862306a36Sopenharmony_ci	if (remain)
34962306a36Sopenharmony_ci		return gcm_hash_remain(req, remain,
35062306a36Sopenharmony_ci				       gcm_hash_assoc_remain_done, flags) ?:
35162306a36Sopenharmony_ci		       gcm_hash_assoc_remain_continue(req, flags);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return gcm_hash_assoc_remain_continue(req, flags);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void gcm_hash_assoc_done(void *data, int err)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct aead_request *req = data;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (err)
36162306a36Sopenharmony_ci		goto out;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	err = gcm_hash_assoc_continue(req, 0);
36462306a36Sopenharmony_ci	if (err == -EINPROGRESS)
36562306a36Sopenharmony_ci		return;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ciout:
36862306a36Sopenharmony_ci	aead_request_complete(req, err);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic int gcm_hash_init_continue(struct aead_request *req, u32 flags)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	if (req->assoclen)
37462306a36Sopenharmony_ci		return gcm_hash_update(req, gcm_hash_assoc_done,
37562306a36Sopenharmony_ci				       req->src, req->assoclen, flags) ?:
37662306a36Sopenharmony_ci		       gcm_hash_assoc_continue(req, flags);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return gcm_hash_assoc_remain_continue(req, flags);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic void gcm_hash_init_done(void *data, int err)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct aead_request *req = data;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (err)
38662306a36Sopenharmony_ci		goto out;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	err = gcm_hash_init_continue(req, 0);
38962306a36Sopenharmony_ci	if (err == -EINPROGRESS)
39062306a36Sopenharmony_ci		return;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ciout:
39362306a36Sopenharmony_ci	aead_request_complete(req, err);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic int gcm_hash(struct aead_request *req, u32 flags)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
39962306a36Sopenharmony_ci	struct ahash_request *ahreq = &pctx->u.ahreq;
40062306a36Sopenharmony_ci	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	ahash_request_set_tfm(ahreq, ctx->ghash);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	ahash_request_set_callback(ahreq, flags, gcm_hash_init_done, req);
40562306a36Sopenharmony_ci	return crypto_ahash_init(ahreq) ?:
40662306a36Sopenharmony_ci	       gcm_hash_init_continue(req, flags);
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic int gcm_enc_copy_hash(struct aead_request *req, u32 flags)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
41262306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
41362306a36Sopenharmony_ci	u8 *auth_tag = pctx->auth_tag;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	crypto_xor(auth_tag, pctx->iauth_tag, 16);
41662306a36Sopenharmony_ci	scatterwalk_map_and_copy(auth_tag, req->dst,
41762306a36Sopenharmony_ci				 req->assoclen + req->cryptlen,
41862306a36Sopenharmony_ci				 crypto_aead_authsize(aead), 1);
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int gcm_encrypt_continue(struct aead_request *req, u32 flags)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
42562306a36Sopenharmony_ci	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	gctx->src = sg_next(req->src == req->dst ? pctx->src : pctx->dst);
42862306a36Sopenharmony_ci	gctx->cryptlen = req->cryptlen;
42962306a36Sopenharmony_ci	gctx->complete = gcm_enc_copy_hash;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return gcm_hash(req, flags);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic void gcm_encrypt_done(void *data, int err)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct aead_request *req = data;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (err)
43962306a36Sopenharmony_ci		goto out;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	err = gcm_encrypt_continue(req, 0);
44262306a36Sopenharmony_ci	if (err == -EINPROGRESS)
44362306a36Sopenharmony_ci		return;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ciout:
44662306a36Sopenharmony_ci	aead_request_complete(req, err);
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic int crypto_gcm_encrypt(struct aead_request *req)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
45262306a36Sopenharmony_ci	struct skcipher_request *skreq = &pctx->u.skreq;
45362306a36Sopenharmony_ci	u32 flags = aead_request_flags(req);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	crypto_gcm_init_common(req);
45662306a36Sopenharmony_ci	crypto_gcm_init_crypt(req, req->cryptlen);
45762306a36Sopenharmony_ci	skcipher_request_set_callback(skreq, flags, gcm_encrypt_done, req);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return crypto_skcipher_encrypt(skreq) ?:
46062306a36Sopenharmony_ci	       gcm_encrypt_continue(req, flags);
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic int crypto_gcm_verify(struct aead_request *req)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
46662306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
46762306a36Sopenharmony_ci	u8 *auth_tag = pctx->auth_tag;
46862306a36Sopenharmony_ci	u8 *iauth_tag = pctx->iauth_tag;
46962306a36Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(aead);
47062306a36Sopenharmony_ci	unsigned int cryptlen = req->cryptlen - authsize;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	crypto_xor(auth_tag, iauth_tag, 16);
47362306a36Sopenharmony_ci	scatterwalk_map_and_copy(iauth_tag, req->src,
47462306a36Sopenharmony_ci				 req->assoclen + cryptlen, authsize, 0);
47562306a36Sopenharmony_ci	return crypto_memneq(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void gcm_decrypt_done(void *data, int err)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct aead_request *req = data;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (!err)
48362306a36Sopenharmony_ci		err = crypto_gcm_verify(req);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	aead_request_complete(req, err);
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic int gcm_dec_hash_continue(struct aead_request *req, u32 flags)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
49162306a36Sopenharmony_ci	struct skcipher_request *skreq = &pctx->u.skreq;
49262306a36Sopenharmony_ci	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	crypto_gcm_init_crypt(req, gctx->cryptlen);
49562306a36Sopenharmony_ci	skcipher_request_set_callback(skreq, flags, gcm_decrypt_done, req);
49662306a36Sopenharmony_ci	return crypto_skcipher_decrypt(skreq) ?: crypto_gcm_verify(req);
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic int crypto_gcm_decrypt(struct aead_request *req)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
50262306a36Sopenharmony_ci	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
50362306a36Sopenharmony_ci	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
50462306a36Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(aead);
50562306a36Sopenharmony_ci	unsigned int cryptlen = req->cryptlen;
50662306a36Sopenharmony_ci	u32 flags = aead_request_flags(req);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	cryptlen -= authsize;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	crypto_gcm_init_common(req);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	gctx->src = sg_next(pctx->src);
51362306a36Sopenharmony_ci	gctx->cryptlen = cryptlen;
51462306a36Sopenharmony_ci	gctx->complete = gcm_dec_hash_continue;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	return gcm_hash(req, flags);
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic int crypto_gcm_init_tfm(struct crypto_aead *tfm)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct aead_instance *inst = aead_alg_instance(tfm);
52262306a36Sopenharmony_ci	struct gcm_instance_ctx *ictx = aead_instance_ctx(inst);
52362306a36Sopenharmony_ci	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm);
52462306a36Sopenharmony_ci	struct crypto_skcipher *ctr;
52562306a36Sopenharmony_ci	struct crypto_ahash *ghash;
52662306a36Sopenharmony_ci	unsigned long align;
52762306a36Sopenharmony_ci	int err;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	ghash = crypto_spawn_ahash(&ictx->ghash);
53062306a36Sopenharmony_ci	if (IS_ERR(ghash))
53162306a36Sopenharmony_ci		return PTR_ERR(ghash);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	ctr = crypto_spawn_skcipher(&ictx->ctr);
53462306a36Sopenharmony_ci	err = PTR_ERR(ctr);
53562306a36Sopenharmony_ci	if (IS_ERR(ctr))
53662306a36Sopenharmony_ci		goto err_free_hash;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	ctx->ctr = ctr;
53962306a36Sopenharmony_ci	ctx->ghash = ghash;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	align = crypto_aead_alignmask(tfm);
54262306a36Sopenharmony_ci	align &= ~(crypto_tfm_ctx_alignment() - 1);
54362306a36Sopenharmony_ci	crypto_aead_set_reqsize(tfm,
54462306a36Sopenharmony_ci		align + offsetof(struct crypto_gcm_req_priv_ctx, u) +
54562306a36Sopenharmony_ci		max(sizeof(struct skcipher_request) +
54662306a36Sopenharmony_ci		    crypto_skcipher_reqsize(ctr),
54762306a36Sopenharmony_ci		    sizeof(struct ahash_request) +
54862306a36Sopenharmony_ci		    crypto_ahash_reqsize(ghash)));
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	return 0;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cierr_free_hash:
55362306a36Sopenharmony_ci	crypto_free_ahash(ghash);
55462306a36Sopenharmony_ci	return err;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic void crypto_gcm_exit_tfm(struct crypto_aead *tfm)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	crypto_free_ahash(ctx->ghash);
56262306a36Sopenharmony_ci	crypto_free_skcipher(ctx->ctr);
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic void crypto_gcm_free(struct aead_instance *inst)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct gcm_instance_ctx *ctx = aead_instance_ctx(inst);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	crypto_drop_skcipher(&ctx->ctr);
57062306a36Sopenharmony_ci	crypto_drop_ahash(&ctx->ghash);
57162306a36Sopenharmony_ci	kfree(inst);
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic int crypto_gcm_create_common(struct crypto_template *tmpl,
57562306a36Sopenharmony_ci				    struct rtattr **tb,
57662306a36Sopenharmony_ci				    const char *ctr_name,
57762306a36Sopenharmony_ci				    const char *ghash_name)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	u32 mask;
58062306a36Sopenharmony_ci	struct aead_instance *inst;
58162306a36Sopenharmony_ci	struct gcm_instance_ctx *ctx;
58262306a36Sopenharmony_ci	struct skcipher_alg *ctr;
58362306a36Sopenharmony_ci	struct hash_alg_common *ghash;
58462306a36Sopenharmony_ci	int err;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask);
58762306a36Sopenharmony_ci	if (err)
58862306a36Sopenharmony_ci		return err;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
59162306a36Sopenharmony_ci	if (!inst)
59262306a36Sopenharmony_ci		return -ENOMEM;
59362306a36Sopenharmony_ci	ctx = aead_instance_ctx(inst);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	err = crypto_grab_ahash(&ctx->ghash, aead_crypto_instance(inst),
59662306a36Sopenharmony_ci				ghash_name, 0, mask);
59762306a36Sopenharmony_ci	if (err)
59862306a36Sopenharmony_ci		goto err_free_inst;
59962306a36Sopenharmony_ci	ghash = crypto_spawn_ahash_alg(&ctx->ghash);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	err = -EINVAL;
60262306a36Sopenharmony_ci	if (strcmp(ghash->base.cra_name, "ghash") != 0 ||
60362306a36Sopenharmony_ci	    ghash->digestsize != 16)
60462306a36Sopenharmony_ci		goto err_free_inst;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	err = crypto_grab_skcipher(&ctx->ctr, aead_crypto_instance(inst),
60762306a36Sopenharmony_ci				   ctr_name, 0, mask);
60862306a36Sopenharmony_ci	if (err)
60962306a36Sopenharmony_ci		goto err_free_inst;
61062306a36Sopenharmony_ci	ctr = crypto_spawn_skcipher_alg(&ctx->ctr);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	/* The skcipher algorithm must be CTR mode, using 16-byte blocks. */
61362306a36Sopenharmony_ci	err = -EINVAL;
61462306a36Sopenharmony_ci	if (strncmp(ctr->base.cra_name, "ctr(", 4) != 0 ||
61562306a36Sopenharmony_ci	    crypto_skcipher_alg_ivsize(ctr) != 16 ||
61662306a36Sopenharmony_ci	    ctr->base.cra_blocksize != 1)
61762306a36Sopenharmony_ci		goto err_free_inst;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	err = -ENAMETOOLONG;
62062306a36Sopenharmony_ci	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
62162306a36Sopenharmony_ci		     "gcm(%s", ctr->base.cra_name + 4) >= CRYPTO_MAX_ALG_NAME)
62262306a36Sopenharmony_ci		goto err_free_inst;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
62562306a36Sopenharmony_ci		     "gcm_base(%s,%s)", ctr->base.cra_driver_name,
62662306a36Sopenharmony_ci		     ghash->base.cra_driver_name) >=
62762306a36Sopenharmony_ci	    CRYPTO_MAX_ALG_NAME)
62862306a36Sopenharmony_ci		goto err_free_inst;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	inst->alg.base.cra_priority = (ghash->base.cra_priority +
63162306a36Sopenharmony_ci				       ctr->base.cra_priority) / 2;
63262306a36Sopenharmony_ci	inst->alg.base.cra_blocksize = 1;
63362306a36Sopenharmony_ci	inst->alg.base.cra_alignmask = ghash->base.cra_alignmask |
63462306a36Sopenharmony_ci				       ctr->base.cra_alignmask;
63562306a36Sopenharmony_ci	inst->alg.base.cra_ctxsize = sizeof(struct crypto_gcm_ctx);
63662306a36Sopenharmony_ci	inst->alg.ivsize = GCM_AES_IV_SIZE;
63762306a36Sopenharmony_ci	inst->alg.chunksize = crypto_skcipher_alg_chunksize(ctr);
63862306a36Sopenharmony_ci	inst->alg.maxauthsize = 16;
63962306a36Sopenharmony_ci	inst->alg.init = crypto_gcm_init_tfm;
64062306a36Sopenharmony_ci	inst->alg.exit = crypto_gcm_exit_tfm;
64162306a36Sopenharmony_ci	inst->alg.setkey = crypto_gcm_setkey;
64262306a36Sopenharmony_ci	inst->alg.setauthsize = crypto_gcm_setauthsize;
64362306a36Sopenharmony_ci	inst->alg.encrypt = crypto_gcm_encrypt;
64462306a36Sopenharmony_ci	inst->alg.decrypt = crypto_gcm_decrypt;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	inst->free = crypto_gcm_free;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	err = aead_register_instance(tmpl, inst);
64962306a36Sopenharmony_ci	if (err) {
65062306a36Sopenharmony_cierr_free_inst:
65162306a36Sopenharmony_ci		crypto_gcm_free(inst);
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci	return err;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic int crypto_gcm_create(struct crypto_template *tmpl, struct rtattr **tb)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	const char *cipher_name;
65962306a36Sopenharmony_ci	char ctr_name[CRYPTO_MAX_ALG_NAME];
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	cipher_name = crypto_attr_alg_name(tb[1]);
66262306a36Sopenharmony_ci	if (IS_ERR(cipher_name))
66362306a36Sopenharmony_ci		return PTR_ERR(cipher_name);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >=
66662306a36Sopenharmony_ci	    CRYPTO_MAX_ALG_NAME)
66762306a36Sopenharmony_ci		return -ENAMETOOLONG;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	return crypto_gcm_create_common(tmpl, tb, ctr_name, "ghash");
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic int crypto_gcm_base_create(struct crypto_template *tmpl,
67362306a36Sopenharmony_ci				  struct rtattr **tb)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	const char *ctr_name;
67662306a36Sopenharmony_ci	const char *ghash_name;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	ctr_name = crypto_attr_alg_name(tb[1]);
67962306a36Sopenharmony_ci	if (IS_ERR(ctr_name))
68062306a36Sopenharmony_ci		return PTR_ERR(ctr_name);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	ghash_name = crypto_attr_alg_name(tb[2]);
68362306a36Sopenharmony_ci	if (IS_ERR(ghash_name))
68462306a36Sopenharmony_ci		return PTR_ERR(ghash_name);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	return crypto_gcm_create_common(tmpl, tb, ctr_name, ghash_name);
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_cistatic int crypto_rfc4106_setkey(struct crypto_aead *parent, const u8 *key,
69062306a36Sopenharmony_ci				 unsigned int keylen)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent);
69362306a36Sopenharmony_ci	struct crypto_aead *child = ctx->child;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (keylen < 4)
69662306a36Sopenharmony_ci		return -EINVAL;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	keylen -= 4;
69962306a36Sopenharmony_ci	memcpy(ctx->nonce, key + keylen, 4);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
70262306a36Sopenharmony_ci	crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
70362306a36Sopenharmony_ci				     CRYPTO_TFM_REQ_MASK);
70462306a36Sopenharmony_ci	return crypto_aead_setkey(child, key, keylen);
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic int crypto_rfc4106_setauthsize(struct crypto_aead *parent,
70862306a36Sopenharmony_ci				      unsigned int authsize)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent);
71162306a36Sopenharmony_ci	int err;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	err = crypto_rfc4106_check_authsize(authsize);
71462306a36Sopenharmony_ci	if (err)
71562306a36Sopenharmony_ci		return err;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	return crypto_aead_setauthsize(ctx->child, authsize);
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic struct aead_request *crypto_rfc4106_crypt(struct aead_request *req)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	struct crypto_rfc4106_req_ctx *rctx = aead_request_ctx(req);
72362306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
72462306a36Sopenharmony_ci	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead);
72562306a36Sopenharmony_ci	struct aead_request *subreq = &rctx->subreq;
72662306a36Sopenharmony_ci	struct crypto_aead *child = ctx->child;
72762306a36Sopenharmony_ci	struct scatterlist *sg;
72862306a36Sopenharmony_ci	u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
72962306a36Sopenharmony_ci			   crypto_aead_alignmask(child) + 1);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	scatterwalk_map_and_copy(iv + GCM_AES_IV_SIZE, req->src, 0, req->assoclen - 8, 0);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	memcpy(iv, ctx->nonce, 4);
73462306a36Sopenharmony_ci	memcpy(iv + 4, req->iv, 8);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	sg_init_table(rctx->src, 3);
73762306a36Sopenharmony_ci	sg_set_buf(rctx->src, iv + GCM_AES_IV_SIZE, req->assoclen - 8);
73862306a36Sopenharmony_ci	sg = scatterwalk_ffwd(rctx->src + 1, req->src, req->assoclen);
73962306a36Sopenharmony_ci	if (sg != rctx->src + 1)
74062306a36Sopenharmony_ci		sg_chain(rctx->src, 2, sg);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (req->src != req->dst) {
74362306a36Sopenharmony_ci		sg_init_table(rctx->dst, 3);
74462306a36Sopenharmony_ci		sg_set_buf(rctx->dst, iv + GCM_AES_IV_SIZE, req->assoclen - 8);
74562306a36Sopenharmony_ci		sg = scatterwalk_ffwd(rctx->dst + 1, req->dst, req->assoclen);
74662306a36Sopenharmony_ci		if (sg != rctx->dst + 1)
74762306a36Sopenharmony_ci			sg_chain(rctx->dst, 2, sg);
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	aead_request_set_tfm(subreq, child);
75162306a36Sopenharmony_ci	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
75262306a36Sopenharmony_ci				  req->base.data);
75362306a36Sopenharmony_ci	aead_request_set_crypt(subreq, rctx->src,
75462306a36Sopenharmony_ci			       req->src == req->dst ? rctx->src : rctx->dst,
75562306a36Sopenharmony_ci			       req->cryptlen, iv);
75662306a36Sopenharmony_ci	aead_request_set_ad(subreq, req->assoclen - 8);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	return subreq;
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic int crypto_rfc4106_encrypt(struct aead_request *req)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	int err;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	err = crypto_ipsec_check_assoclen(req->assoclen);
76662306a36Sopenharmony_ci	if (err)
76762306a36Sopenharmony_ci		return err;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	req = crypto_rfc4106_crypt(req);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	return crypto_aead_encrypt(req);
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic int crypto_rfc4106_decrypt(struct aead_request *req)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	int err;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	err = crypto_ipsec_check_assoclen(req->assoclen);
77962306a36Sopenharmony_ci	if (err)
78062306a36Sopenharmony_ci		return err;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	req = crypto_rfc4106_crypt(req);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	return crypto_aead_decrypt(req);
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic int crypto_rfc4106_init_tfm(struct crypto_aead *tfm)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct aead_instance *inst = aead_alg_instance(tfm);
79062306a36Sopenharmony_ci	struct crypto_aead_spawn *spawn = aead_instance_ctx(inst);
79162306a36Sopenharmony_ci	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm);
79262306a36Sopenharmony_ci	struct crypto_aead *aead;
79362306a36Sopenharmony_ci	unsigned long align;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	aead = crypto_spawn_aead(spawn);
79662306a36Sopenharmony_ci	if (IS_ERR(aead))
79762306a36Sopenharmony_ci		return PTR_ERR(aead);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	ctx->child = aead;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	align = crypto_aead_alignmask(aead);
80262306a36Sopenharmony_ci	align &= ~(crypto_tfm_ctx_alignment() - 1);
80362306a36Sopenharmony_ci	crypto_aead_set_reqsize(
80462306a36Sopenharmony_ci		tfm,
80562306a36Sopenharmony_ci		sizeof(struct crypto_rfc4106_req_ctx) +
80662306a36Sopenharmony_ci		ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
80762306a36Sopenharmony_ci		align + 24);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	return 0;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic void crypto_rfc4106_exit_tfm(struct crypto_aead *tfm)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	crypto_free_aead(ctx->child);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic void crypto_rfc4106_free(struct aead_instance *inst)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	crypto_drop_aead(aead_instance_ctx(inst));
82262306a36Sopenharmony_ci	kfree(inst);
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic int crypto_rfc4106_create(struct crypto_template *tmpl,
82662306a36Sopenharmony_ci				 struct rtattr **tb)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	u32 mask;
82962306a36Sopenharmony_ci	struct aead_instance *inst;
83062306a36Sopenharmony_ci	struct crypto_aead_spawn *spawn;
83162306a36Sopenharmony_ci	struct aead_alg *alg;
83262306a36Sopenharmony_ci	int err;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask);
83562306a36Sopenharmony_ci	if (err)
83662306a36Sopenharmony_ci		return err;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
83962306a36Sopenharmony_ci	if (!inst)
84062306a36Sopenharmony_ci		return -ENOMEM;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	spawn = aead_instance_ctx(inst);
84362306a36Sopenharmony_ci	err = crypto_grab_aead(spawn, aead_crypto_instance(inst),
84462306a36Sopenharmony_ci			       crypto_attr_alg_name(tb[1]), 0, mask);
84562306a36Sopenharmony_ci	if (err)
84662306a36Sopenharmony_ci		goto err_free_inst;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	alg = crypto_spawn_aead_alg(spawn);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	err = -EINVAL;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	/* Underlying IV size must be 12. */
85362306a36Sopenharmony_ci	if (crypto_aead_alg_ivsize(alg) != GCM_AES_IV_SIZE)
85462306a36Sopenharmony_ci		goto err_free_inst;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	/* Not a stream cipher? */
85762306a36Sopenharmony_ci	if (alg->base.cra_blocksize != 1)
85862306a36Sopenharmony_ci		goto err_free_inst;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	err = -ENAMETOOLONG;
86162306a36Sopenharmony_ci	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
86262306a36Sopenharmony_ci		     "rfc4106(%s)", alg->base.cra_name) >=
86362306a36Sopenharmony_ci	    CRYPTO_MAX_ALG_NAME ||
86462306a36Sopenharmony_ci	    snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
86562306a36Sopenharmony_ci		     "rfc4106(%s)", alg->base.cra_driver_name) >=
86662306a36Sopenharmony_ci	    CRYPTO_MAX_ALG_NAME)
86762306a36Sopenharmony_ci		goto err_free_inst;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	inst->alg.base.cra_priority = alg->base.cra_priority;
87062306a36Sopenharmony_ci	inst->alg.base.cra_blocksize = 1;
87162306a36Sopenharmony_ci	inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	inst->alg.ivsize = GCM_RFC4106_IV_SIZE;
87662306a36Sopenharmony_ci	inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
87762306a36Sopenharmony_ci	inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	inst->alg.init = crypto_rfc4106_init_tfm;
88062306a36Sopenharmony_ci	inst->alg.exit = crypto_rfc4106_exit_tfm;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	inst->alg.setkey = crypto_rfc4106_setkey;
88362306a36Sopenharmony_ci	inst->alg.setauthsize = crypto_rfc4106_setauthsize;
88462306a36Sopenharmony_ci	inst->alg.encrypt = crypto_rfc4106_encrypt;
88562306a36Sopenharmony_ci	inst->alg.decrypt = crypto_rfc4106_decrypt;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	inst->free = crypto_rfc4106_free;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	err = aead_register_instance(tmpl, inst);
89062306a36Sopenharmony_ci	if (err) {
89162306a36Sopenharmony_cierr_free_inst:
89262306a36Sopenharmony_ci		crypto_rfc4106_free(inst);
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci	return err;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic int crypto_rfc4543_setkey(struct crypto_aead *parent, const u8 *key,
89862306a36Sopenharmony_ci				 unsigned int keylen)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent);
90162306a36Sopenharmony_ci	struct crypto_aead *child = ctx->child;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	if (keylen < 4)
90462306a36Sopenharmony_ci		return -EINVAL;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	keylen -= 4;
90762306a36Sopenharmony_ci	memcpy(ctx->nonce, key + keylen, 4);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
91062306a36Sopenharmony_ci	crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
91162306a36Sopenharmony_ci				     CRYPTO_TFM_REQ_MASK);
91262306a36Sopenharmony_ci	return crypto_aead_setkey(child, key, keylen);
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic int crypto_rfc4543_setauthsize(struct crypto_aead *parent,
91662306a36Sopenharmony_ci				      unsigned int authsize)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (authsize != 16)
92162306a36Sopenharmony_ci		return -EINVAL;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	return crypto_aead_setauthsize(ctx->child, authsize);
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic int crypto_rfc4543_crypt(struct aead_request *req, bool enc)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
92962306a36Sopenharmony_ci	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead);
93062306a36Sopenharmony_ci	struct crypto_rfc4543_req_ctx *rctx = aead_request_ctx(req);
93162306a36Sopenharmony_ci	struct aead_request *subreq = &rctx->subreq;
93262306a36Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(aead);
93362306a36Sopenharmony_ci	u8 *iv = PTR_ALIGN((u8 *)(rctx + 1) + crypto_aead_reqsize(ctx->child),
93462306a36Sopenharmony_ci			   crypto_aead_alignmask(ctx->child) + 1);
93562306a36Sopenharmony_ci	int err;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	if (req->src != req->dst) {
93862306a36Sopenharmony_ci		err = crypto_rfc4543_copy_src_to_dst(req, enc);
93962306a36Sopenharmony_ci		if (err)
94062306a36Sopenharmony_ci			return err;
94162306a36Sopenharmony_ci	}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	memcpy(iv, ctx->nonce, 4);
94462306a36Sopenharmony_ci	memcpy(iv + 4, req->iv, 8);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	aead_request_set_tfm(subreq, ctx->child);
94762306a36Sopenharmony_ci	aead_request_set_callback(subreq, req->base.flags,
94862306a36Sopenharmony_ci				  req->base.complete, req->base.data);
94962306a36Sopenharmony_ci	aead_request_set_crypt(subreq, req->src, req->dst,
95062306a36Sopenharmony_ci			       enc ? 0 : authsize, iv);
95162306a36Sopenharmony_ci	aead_request_set_ad(subreq, req->assoclen + req->cryptlen -
95262306a36Sopenharmony_ci				    subreq->cryptlen);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	return enc ? crypto_aead_encrypt(subreq) : crypto_aead_decrypt(subreq);
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(req);
96062306a36Sopenharmony_ci	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead);
96162306a36Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(aead);
96262306a36Sopenharmony_ci	unsigned int nbytes = req->assoclen + req->cryptlen -
96362306a36Sopenharmony_ci			      (enc ? 0 : authsize);
96462306a36Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	skcipher_request_set_sync_tfm(nreq, ctx->null);
96762306a36Sopenharmony_ci	skcipher_request_set_callback(nreq, req->base.flags, NULL, NULL);
96862306a36Sopenharmony_ci	skcipher_request_set_crypt(nreq, req->src, req->dst, nbytes, NULL);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	return crypto_skcipher_encrypt(nreq);
97162306a36Sopenharmony_ci}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_cistatic int crypto_rfc4543_encrypt(struct aead_request *req)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	return crypto_ipsec_check_assoclen(req->assoclen) ?:
97662306a36Sopenharmony_ci	       crypto_rfc4543_crypt(req, true);
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cistatic int crypto_rfc4543_decrypt(struct aead_request *req)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	return crypto_ipsec_check_assoclen(req->assoclen) ?:
98262306a36Sopenharmony_ci	       crypto_rfc4543_crypt(req, false);
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_cistatic int crypto_rfc4543_init_tfm(struct crypto_aead *tfm)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	struct aead_instance *inst = aead_alg_instance(tfm);
98862306a36Sopenharmony_ci	struct crypto_rfc4543_instance_ctx *ictx = aead_instance_ctx(inst);
98962306a36Sopenharmony_ci	struct crypto_aead_spawn *spawn = &ictx->aead;
99062306a36Sopenharmony_ci	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm);
99162306a36Sopenharmony_ci	struct crypto_aead *aead;
99262306a36Sopenharmony_ci	struct crypto_sync_skcipher *null;
99362306a36Sopenharmony_ci	unsigned long align;
99462306a36Sopenharmony_ci	int err = 0;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	aead = crypto_spawn_aead(spawn);
99762306a36Sopenharmony_ci	if (IS_ERR(aead))
99862306a36Sopenharmony_ci		return PTR_ERR(aead);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	null = crypto_get_default_null_skcipher();
100162306a36Sopenharmony_ci	err = PTR_ERR(null);
100262306a36Sopenharmony_ci	if (IS_ERR(null))
100362306a36Sopenharmony_ci		goto err_free_aead;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	ctx->child = aead;
100662306a36Sopenharmony_ci	ctx->null = null;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	align = crypto_aead_alignmask(aead);
100962306a36Sopenharmony_ci	align &= ~(crypto_tfm_ctx_alignment() - 1);
101062306a36Sopenharmony_ci	crypto_aead_set_reqsize(
101162306a36Sopenharmony_ci		tfm,
101262306a36Sopenharmony_ci		sizeof(struct crypto_rfc4543_req_ctx) +
101362306a36Sopenharmony_ci		ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
101462306a36Sopenharmony_ci		align + GCM_AES_IV_SIZE);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	return 0;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cierr_free_aead:
101962306a36Sopenharmony_ci	crypto_free_aead(aead);
102062306a36Sopenharmony_ci	return err;
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_cistatic void crypto_rfc4543_exit_tfm(struct crypto_aead *tfm)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	crypto_free_aead(ctx->child);
102862306a36Sopenharmony_ci	crypto_put_default_null_skcipher();
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic void crypto_rfc4543_free(struct aead_instance *inst)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	struct crypto_rfc4543_instance_ctx *ctx = aead_instance_ctx(inst);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	crypto_drop_aead(&ctx->aead);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	kfree(inst);
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cistatic int crypto_rfc4543_create(struct crypto_template *tmpl,
104162306a36Sopenharmony_ci				struct rtattr **tb)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	u32 mask;
104462306a36Sopenharmony_ci	struct aead_instance *inst;
104562306a36Sopenharmony_ci	struct aead_alg *alg;
104662306a36Sopenharmony_ci	struct crypto_rfc4543_instance_ctx *ctx;
104762306a36Sopenharmony_ci	int err;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask);
105062306a36Sopenharmony_ci	if (err)
105162306a36Sopenharmony_ci		return err;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
105462306a36Sopenharmony_ci	if (!inst)
105562306a36Sopenharmony_ci		return -ENOMEM;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	ctx = aead_instance_ctx(inst);
105862306a36Sopenharmony_ci	err = crypto_grab_aead(&ctx->aead, aead_crypto_instance(inst),
105962306a36Sopenharmony_ci			       crypto_attr_alg_name(tb[1]), 0, mask);
106062306a36Sopenharmony_ci	if (err)
106162306a36Sopenharmony_ci		goto err_free_inst;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	alg = crypto_spawn_aead_alg(&ctx->aead);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	err = -EINVAL;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	/* Underlying IV size must be 12. */
106862306a36Sopenharmony_ci	if (crypto_aead_alg_ivsize(alg) != GCM_AES_IV_SIZE)
106962306a36Sopenharmony_ci		goto err_free_inst;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	/* Not a stream cipher? */
107262306a36Sopenharmony_ci	if (alg->base.cra_blocksize != 1)
107362306a36Sopenharmony_ci		goto err_free_inst;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	err = -ENAMETOOLONG;
107662306a36Sopenharmony_ci	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
107762306a36Sopenharmony_ci		     "rfc4543(%s)", alg->base.cra_name) >=
107862306a36Sopenharmony_ci	    CRYPTO_MAX_ALG_NAME ||
107962306a36Sopenharmony_ci	    snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
108062306a36Sopenharmony_ci		     "rfc4543(%s)", alg->base.cra_driver_name) >=
108162306a36Sopenharmony_ci	    CRYPTO_MAX_ALG_NAME)
108262306a36Sopenharmony_ci		goto err_free_inst;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	inst->alg.base.cra_priority = alg->base.cra_priority;
108562306a36Sopenharmony_ci	inst->alg.base.cra_blocksize = 1;
108662306a36Sopenharmony_ci	inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4543_ctx);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	inst->alg.ivsize = GCM_RFC4543_IV_SIZE;
109162306a36Sopenharmony_ci	inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
109262306a36Sopenharmony_ci	inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	inst->alg.init = crypto_rfc4543_init_tfm;
109562306a36Sopenharmony_ci	inst->alg.exit = crypto_rfc4543_exit_tfm;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	inst->alg.setkey = crypto_rfc4543_setkey;
109862306a36Sopenharmony_ci	inst->alg.setauthsize = crypto_rfc4543_setauthsize;
109962306a36Sopenharmony_ci	inst->alg.encrypt = crypto_rfc4543_encrypt;
110062306a36Sopenharmony_ci	inst->alg.decrypt = crypto_rfc4543_decrypt;
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	inst->free = crypto_rfc4543_free;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	err = aead_register_instance(tmpl, inst);
110562306a36Sopenharmony_ci	if (err) {
110662306a36Sopenharmony_cierr_free_inst:
110762306a36Sopenharmony_ci		crypto_rfc4543_free(inst);
110862306a36Sopenharmony_ci	}
110962306a36Sopenharmony_ci	return err;
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistatic struct crypto_template crypto_gcm_tmpls[] = {
111362306a36Sopenharmony_ci	{
111462306a36Sopenharmony_ci		.name = "gcm_base",
111562306a36Sopenharmony_ci		.create = crypto_gcm_base_create,
111662306a36Sopenharmony_ci		.module = THIS_MODULE,
111762306a36Sopenharmony_ci	}, {
111862306a36Sopenharmony_ci		.name = "gcm",
111962306a36Sopenharmony_ci		.create = crypto_gcm_create,
112062306a36Sopenharmony_ci		.module = THIS_MODULE,
112162306a36Sopenharmony_ci	}, {
112262306a36Sopenharmony_ci		.name = "rfc4106",
112362306a36Sopenharmony_ci		.create = crypto_rfc4106_create,
112462306a36Sopenharmony_ci		.module = THIS_MODULE,
112562306a36Sopenharmony_ci	}, {
112662306a36Sopenharmony_ci		.name = "rfc4543",
112762306a36Sopenharmony_ci		.create = crypto_rfc4543_create,
112862306a36Sopenharmony_ci		.module = THIS_MODULE,
112962306a36Sopenharmony_ci	},
113062306a36Sopenharmony_ci};
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic int __init crypto_gcm_module_init(void)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	int err;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	gcm_zeroes = kzalloc(sizeof(*gcm_zeroes), GFP_KERNEL);
113762306a36Sopenharmony_ci	if (!gcm_zeroes)
113862306a36Sopenharmony_ci		return -ENOMEM;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	sg_init_one(&gcm_zeroes->sg, gcm_zeroes->buf, sizeof(gcm_zeroes->buf));
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	err = crypto_register_templates(crypto_gcm_tmpls,
114362306a36Sopenharmony_ci					ARRAY_SIZE(crypto_gcm_tmpls));
114462306a36Sopenharmony_ci	if (err)
114562306a36Sopenharmony_ci		kfree(gcm_zeroes);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	return err;
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cistatic void __exit crypto_gcm_module_exit(void)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	kfree(gcm_zeroes);
115362306a36Sopenharmony_ci	crypto_unregister_templates(crypto_gcm_tmpls,
115462306a36Sopenharmony_ci				    ARRAY_SIZE(crypto_gcm_tmpls));
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cisubsys_initcall(crypto_gcm_module_init);
115862306a36Sopenharmony_cimodule_exit(crypto_gcm_module_exit);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
116162306a36Sopenharmony_ciMODULE_DESCRIPTION("Galois/Counter Mode");
116262306a36Sopenharmony_ciMODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>");
116362306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("gcm_base");
116462306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("rfc4106");
116562306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("rfc4543");
116662306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("gcm");
1167