162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Asynchronous Cryptographic Hash operations.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This is the asynchronous version of hash.c with notification of
662306a36Sopenharmony_ci * completion via a callback.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (c) 2008 Loc Ho <lho@amcc.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
1262306a36Sopenharmony_ci#include <linux/cryptouser.h>
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/sched.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/seq_file.h>
1962306a36Sopenharmony_ci#include <linux/string.h>
2062306a36Sopenharmony_ci#include <net/netlink.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "hash.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic const struct crypto_type crypto_ahash_type;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistruct ahash_request_priv {
2762306a36Sopenharmony_ci	crypto_completion_t complete;
2862306a36Sopenharmony_ci	void *data;
2962306a36Sopenharmony_ci	u8 *result;
3062306a36Sopenharmony_ci	u32 flags;
3162306a36Sopenharmony_ci	void *ubuf[] CRYPTO_MINALIGN_ATTR;
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int hash_walk_next(struct crypto_hash_walk *walk)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	unsigned int alignmask = walk->alignmask;
3762306a36Sopenharmony_ci	unsigned int offset = walk->offset;
3862306a36Sopenharmony_ci	unsigned int nbytes = min(walk->entrylen,
3962306a36Sopenharmony_ci				  ((unsigned int)(PAGE_SIZE)) - offset);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	walk->data = kmap_local_page(walk->pg);
4262306a36Sopenharmony_ci	walk->data += offset;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (offset & alignmask) {
4562306a36Sopenharmony_ci		unsigned int unaligned = alignmask + 1 - (offset & alignmask);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		if (nbytes > unaligned)
4862306a36Sopenharmony_ci			nbytes = unaligned;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	walk->entrylen -= nbytes;
5262306a36Sopenharmony_ci	return nbytes;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic int hash_walk_new_entry(struct crypto_hash_walk *walk)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct scatterlist *sg;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	sg = walk->sg;
6062306a36Sopenharmony_ci	walk->offset = sg->offset;
6162306a36Sopenharmony_ci	walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT);
6262306a36Sopenharmony_ci	walk->offset = offset_in_page(walk->offset);
6362306a36Sopenharmony_ci	walk->entrylen = sg->length;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (walk->entrylen > walk->total)
6662306a36Sopenharmony_ci		walk->entrylen = walk->total;
6762306a36Sopenharmony_ci	walk->total -= walk->entrylen;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return hash_walk_next(walk);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ciint crypto_hash_walk_done(struct crypto_hash_walk *walk, int err)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	unsigned int alignmask = walk->alignmask;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	walk->data -= walk->offset;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (walk->entrylen && (walk->offset & alignmask) && !err) {
7962306a36Sopenharmony_ci		unsigned int nbytes;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		walk->offset = ALIGN(walk->offset, alignmask + 1);
8262306a36Sopenharmony_ci		nbytes = min(walk->entrylen,
8362306a36Sopenharmony_ci			     (unsigned int)(PAGE_SIZE - walk->offset));
8462306a36Sopenharmony_ci		if (nbytes) {
8562306a36Sopenharmony_ci			walk->entrylen -= nbytes;
8662306a36Sopenharmony_ci			walk->data += walk->offset;
8762306a36Sopenharmony_ci			return nbytes;
8862306a36Sopenharmony_ci		}
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	kunmap_local(walk->data);
9262306a36Sopenharmony_ci	crypto_yield(walk->flags);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (err)
9562306a36Sopenharmony_ci		return err;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (walk->entrylen) {
9862306a36Sopenharmony_ci		walk->offset = 0;
9962306a36Sopenharmony_ci		walk->pg++;
10062306a36Sopenharmony_ci		return hash_walk_next(walk);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (!walk->total)
10462306a36Sopenharmony_ci		return 0;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	walk->sg = sg_next(walk->sg);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	return hash_walk_new_entry(walk);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_hash_walk_done);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciint crypto_hash_walk_first(struct ahash_request *req,
11362306a36Sopenharmony_ci			   struct crypto_hash_walk *walk)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	walk->total = req->nbytes;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if (!walk->total) {
11862306a36Sopenharmony_ci		walk->entrylen = 0;
11962306a36Sopenharmony_ci		return 0;
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req));
12362306a36Sopenharmony_ci	walk->sg = req->src;
12462306a36Sopenharmony_ci	walk->flags = req->base.flags;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return hash_walk_new_entry(walk);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_hash_walk_first);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
13162306a36Sopenharmony_ci				unsigned int keylen)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	unsigned long alignmask = crypto_ahash_alignmask(tfm);
13462306a36Sopenharmony_ci	int ret;
13562306a36Sopenharmony_ci	u8 *buffer, *alignbuffer;
13662306a36Sopenharmony_ci	unsigned long absize;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	absize = keylen + alignmask;
13962306a36Sopenharmony_ci	buffer = kmalloc(absize, GFP_KERNEL);
14062306a36Sopenharmony_ci	if (!buffer)
14162306a36Sopenharmony_ci		return -ENOMEM;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
14462306a36Sopenharmony_ci	memcpy(alignbuffer, key, keylen);
14562306a36Sopenharmony_ci	ret = tfm->setkey(tfm, alignbuffer, keylen);
14662306a36Sopenharmony_ci	kfree_sensitive(buffer);
14762306a36Sopenharmony_ci	return ret;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key,
15162306a36Sopenharmony_ci			  unsigned int keylen)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	return -ENOSYS;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void ahash_set_needkey(struct crypto_ahash *tfm)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	const struct hash_alg_common *alg = crypto_hash_alg_common(tfm);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (tfm->setkey != ahash_nosetkey &&
16162306a36Sopenharmony_ci	    !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
16262306a36Sopenharmony_ci		crypto_ahash_set_flags(tfm, CRYPTO_TFM_NEED_KEY);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ciint crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
16662306a36Sopenharmony_ci			unsigned int keylen)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	unsigned long alignmask = crypto_ahash_alignmask(tfm);
16962306a36Sopenharmony_ci	int err;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if ((unsigned long)key & alignmask)
17262306a36Sopenharmony_ci		err = ahash_setkey_unaligned(tfm, key, keylen);
17362306a36Sopenharmony_ci	else
17462306a36Sopenharmony_ci		err = tfm->setkey(tfm, key, keylen);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (unlikely(err)) {
17762306a36Sopenharmony_ci		ahash_set_needkey(tfm);
17862306a36Sopenharmony_ci		return err;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
18262306a36Sopenharmony_ci	return 0;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ahash_setkey);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt,
18762306a36Sopenharmony_ci			  bool has_state)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
19062306a36Sopenharmony_ci	unsigned long alignmask = crypto_ahash_alignmask(tfm);
19162306a36Sopenharmony_ci	unsigned int ds = crypto_ahash_digestsize(tfm);
19262306a36Sopenharmony_ci	struct ahash_request *subreq;
19362306a36Sopenharmony_ci	unsigned int subreq_size;
19462306a36Sopenharmony_ci	unsigned int reqsize;
19562306a36Sopenharmony_ci	u8 *result;
19662306a36Sopenharmony_ci	gfp_t gfp;
19762306a36Sopenharmony_ci	u32 flags;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	subreq_size = sizeof(*subreq);
20062306a36Sopenharmony_ci	reqsize = crypto_ahash_reqsize(tfm);
20162306a36Sopenharmony_ci	reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment());
20262306a36Sopenharmony_ci	subreq_size += reqsize;
20362306a36Sopenharmony_ci	subreq_size += ds;
20462306a36Sopenharmony_ci	subreq_size += alignmask & ~(crypto_tfm_ctx_alignment() - 1);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	flags = ahash_request_flags(req);
20762306a36Sopenharmony_ci	gfp = (flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?  GFP_KERNEL : GFP_ATOMIC;
20862306a36Sopenharmony_ci	subreq = kmalloc(subreq_size, gfp);
20962306a36Sopenharmony_ci	if (!subreq)
21062306a36Sopenharmony_ci		return -ENOMEM;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	ahash_request_set_tfm(subreq, tfm);
21362306a36Sopenharmony_ci	ahash_request_set_callback(subreq, flags, cplt, req);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	result = (u8 *)(subreq + 1) + reqsize;
21662306a36Sopenharmony_ci	result = PTR_ALIGN(result, alignmask + 1);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	ahash_request_set_crypt(subreq, req->src, result, req->nbytes);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (has_state) {
22162306a36Sopenharmony_ci		void *state;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		state = kmalloc(crypto_ahash_statesize(tfm), gfp);
22462306a36Sopenharmony_ci		if (!state) {
22562306a36Sopenharmony_ci			kfree(subreq);
22662306a36Sopenharmony_ci			return -ENOMEM;
22762306a36Sopenharmony_ci		}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		crypto_ahash_export(req, state);
23062306a36Sopenharmony_ci		crypto_ahash_import(subreq, state);
23162306a36Sopenharmony_ci		kfree_sensitive(state);
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	req->priv = subreq;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic void ahash_restore_req(struct ahash_request *req, int err)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct ahash_request *subreq = req->priv;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (!err)
24462306a36Sopenharmony_ci		memcpy(req->result, subreq->result,
24562306a36Sopenharmony_ci		       crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	req->priv = NULL;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	kfree_sensitive(subreq);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic void ahash_op_unaligned_done(void *data, int err)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct ahash_request *areq = data;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (err == -EINPROGRESS)
25762306a36Sopenharmony_ci		goto out;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/* First copy req->result into req->priv.result */
26062306a36Sopenharmony_ci	ahash_restore_req(areq, err);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ciout:
26362306a36Sopenharmony_ci	/* Complete the ORIGINAL request. */
26462306a36Sopenharmony_ci	ahash_request_complete(areq, err);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int ahash_op_unaligned(struct ahash_request *req,
26862306a36Sopenharmony_ci			      int (*op)(struct ahash_request *),
26962306a36Sopenharmony_ci			      bool has_state)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	int err;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	err = ahash_save_req(req, ahash_op_unaligned_done, has_state);
27462306a36Sopenharmony_ci	if (err)
27562306a36Sopenharmony_ci		return err;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	err = op(req->priv);
27862306a36Sopenharmony_ci	if (err == -EINPROGRESS || err == -EBUSY)
27962306a36Sopenharmony_ci		return err;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	ahash_restore_req(req, err);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return err;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic int crypto_ahash_op(struct ahash_request *req,
28762306a36Sopenharmony_ci			   int (*op)(struct ahash_request *),
28862306a36Sopenharmony_ci			   bool has_state)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
29162306a36Sopenharmony_ci	unsigned long alignmask = crypto_ahash_alignmask(tfm);
29262306a36Sopenharmony_ci	int err;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if ((unsigned long)req->result & alignmask)
29562306a36Sopenharmony_ci		err = ahash_op_unaligned(req, op, has_state);
29662306a36Sopenharmony_ci	else
29762306a36Sopenharmony_ci		err = op(req);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return crypto_hash_errstat(crypto_hash_alg_common(tfm), err);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ciint crypto_ahash_final(struct ahash_request *req)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
30562306a36Sopenharmony_ci	struct hash_alg_common *alg = crypto_hash_alg_common(tfm);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_STATS))
30862306a36Sopenharmony_ci		atomic64_inc(&hash_get_stat(alg)->hash_cnt);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	return crypto_ahash_op(req, tfm->final, true);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ahash_final);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ciint crypto_ahash_finup(struct ahash_request *req)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
31762306a36Sopenharmony_ci	struct hash_alg_common *alg = crypto_hash_alg_common(tfm);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_STATS)) {
32062306a36Sopenharmony_ci		struct crypto_istat_hash *istat = hash_get_stat(alg);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		atomic64_inc(&istat->hash_cnt);
32362306a36Sopenharmony_ci		atomic64_add(req->nbytes, &istat->hash_tlen);
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return crypto_ahash_op(req, tfm->finup, true);
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ahash_finup);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ciint crypto_ahash_digest(struct ahash_request *req)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
33362306a36Sopenharmony_ci	struct hash_alg_common *alg = crypto_hash_alg_common(tfm);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_STATS)) {
33662306a36Sopenharmony_ci		struct crypto_istat_hash *istat = hash_get_stat(alg);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		atomic64_inc(&istat->hash_cnt);
33962306a36Sopenharmony_ci		atomic64_add(req->nbytes, &istat->hash_tlen);
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
34362306a36Sopenharmony_ci		return crypto_hash_errstat(alg, -ENOKEY);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return crypto_ahash_op(req, tfm->digest, false);
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ahash_digest);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic void ahash_def_finup_done2(void *data, int err)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	struct ahash_request *areq = data;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (err == -EINPROGRESS)
35462306a36Sopenharmony_ci		return;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	ahash_restore_req(areq, err);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	ahash_request_complete(areq, err);
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic int ahash_def_finup_finish1(struct ahash_request *req, int err)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	struct ahash_request *subreq = req->priv;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (err)
36662306a36Sopenharmony_ci		goto out;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	subreq->base.complete = ahash_def_finup_done2;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	err = crypto_ahash_reqtfm(req)->final(subreq);
37162306a36Sopenharmony_ci	if (err == -EINPROGRESS || err == -EBUSY)
37262306a36Sopenharmony_ci		return err;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ciout:
37562306a36Sopenharmony_ci	ahash_restore_req(req, err);
37662306a36Sopenharmony_ci	return err;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic void ahash_def_finup_done1(void *data, int err)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct ahash_request *areq = data;
38262306a36Sopenharmony_ci	struct ahash_request *subreq;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (err == -EINPROGRESS)
38562306a36Sopenharmony_ci		goto out;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	subreq = areq->priv;
38862306a36Sopenharmony_ci	subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	err = ahash_def_finup_finish1(areq, err);
39162306a36Sopenharmony_ci	if (err == -EINPROGRESS || err == -EBUSY)
39262306a36Sopenharmony_ci		return;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ciout:
39562306a36Sopenharmony_ci	ahash_request_complete(areq, err);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int ahash_def_finup(struct ahash_request *req)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
40162306a36Sopenharmony_ci	int err;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	err = ahash_save_req(req, ahash_def_finup_done1, true);
40462306a36Sopenharmony_ci	if (err)
40562306a36Sopenharmony_ci		return err;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	err = tfm->update(req->priv);
40862306a36Sopenharmony_ci	if (err == -EINPROGRESS || err == -EBUSY)
40962306a36Sopenharmony_ci		return err;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	return ahash_def_finup_finish1(req, err);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic void crypto_ahash_exit_tfm(struct crypto_tfm *tfm)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
41762306a36Sopenharmony_ci	struct ahash_alg *alg = crypto_ahash_alg(hash);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	alg->exit_tfm(hash);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
42562306a36Sopenharmony_ci	struct ahash_alg *alg = crypto_ahash_alg(hash);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	hash->setkey = ahash_nosetkey;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	crypto_ahash_set_statesize(hash, alg->halg.statesize);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
43262306a36Sopenharmony_ci		return crypto_init_shash_ops_async(tfm);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	hash->init = alg->init;
43562306a36Sopenharmony_ci	hash->update = alg->update;
43662306a36Sopenharmony_ci	hash->final = alg->final;
43762306a36Sopenharmony_ci	hash->finup = alg->finup ?: ahash_def_finup;
43862306a36Sopenharmony_ci	hash->digest = alg->digest;
43962306a36Sopenharmony_ci	hash->export = alg->export;
44062306a36Sopenharmony_ci	hash->import = alg->import;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (alg->setkey) {
44362306a36Sopenharmony_ci		hash->setkey = alg->setkey;
44462306a36Sopenharmony_ci		ahash_set_needkey(hash);
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	if (alg->exit_tfm)
44862306a36Sopenharmony_ci		tfm->exit = crypto_ahash_exit_tfm;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return alg->init_tfm ? alg->init_tfm(hash) : 0;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic unsigned int crypto_ahash_extsize(struct crypto_alg *alg)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	if (alg->cra_type != &crypto_ahash_type)
45662306a36Sopenharmony_ci		return sizeof(struct crypto_shash *);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return crypto_alg_extsize(alg);
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic void crypto_ahash_free_instance(struct crypto_instance *inst)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct ahash_instance *ahash = ahash_instance(inst);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	ahash->free(ahash);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic int __maybe_unused crypto_ahash_report(
46962306a36Sopenharmony_ci	struct sk_buff *skb, struct crypto_alg *alg)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct crypto_report_hash rhash;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	memset(&rhash, 0, sizeof(rhash));
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	strscpy(rhash.type, "ahash", sizeof(rhash.type));
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	rhash.blocksize = alg->cra_blocksize;
47862306a36Sopenharmony_ci	rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
48462306a36Sopenharmony_ci	__maybe_unused;
48562306a36Sopenharmony_cistatic void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	seq_printf(m, "type         : ahash\n");
48862306a36Sopenharmony_ci	seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
48962306a36Sopenharmony_ci					     "yes" : "no");
49062306a36Sopenharmony_ci	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
49162306a36Sopenharmony_ci	seq_printf(m, "digestsize   : %u\n",
49262306a36Sopenharmony_ci		   __crypto_hash_alg_common(alg)->digestsize);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic int __maybe_unused crypto_ahash_report_stat(
49662306a36Sopenharmony_ci	struct sk_buff *skb, struct crypto_alg *alg)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	return crypto_hash_report_stat(skb, alg, "ahash");
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic const struct crypto_type crypto_ahash_type = {
50262306a36Sopenharmony_ci	.extsize = crypto_ahash_extsize,
50362306a36Sopenharmony_ci	.init_tfm = crypto_ahash_init_tfm,
50462306a36Sopenharmony_ci	.free = crypto_ahash_free_instance,
50562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
50662306a36Sopenharmony_ci	.show = crypto_ahash_show,
50762306a36Sopenharmony_ci#endif
50862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CRYPTO_USER)
50962306a36Sopenharmony_ci	.report = crypto_ahash_report,
51062306a36Sopenharmony_ci#endif
51162306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_STATS
51262306a36Sopenharmony_ci	.report_stat = crypto_ahash_report_stat,
51362306a36Sopenharmony_ci#endif
51462306a36Sopenharmony_ci	.maskclear = ~CRYPTO_ALG_TYPE_MASK,
51562306a36Sopenharmony_ci	.maskset = CRYPTO_ALG_TYPE_AHASH_MASK,
51662306a36Sopenharmony_ci	.type = CRYPTO_ALG_TYPE_AHASH,
51762306a36Sopenharmony_ci	.tfmsize = offsetof(struct crypto_ahash, base),
51862306a36Sopenharmony_ci};
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ciint crypto_grab_ahash(struct crypto_ahash_spawn *spawn,
52162306a36Sopenharmony_ci		      struct crypto_instance *inst,
52262306a36Sopenharmony_ci		      const char *name, u32 type, u32 mask)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	spawn->base.frontend = &crypto_ahash_type;
52562306a36Sopenharmony_ci	return crypto_grab_spawn(&spawn->base, inst, name, type, mask);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_grab_ahash);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistruct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type,
53062306a36Sopenharmony_ci					u32 mask)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask);
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_alloc_ahash);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ciint crypto_has_ahash(const char *alg_name, u32 type, u32 mask)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_has_ahash);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistruct crypto_ahash *crypto_clone_ahash(struct crypto_ahash *hash)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct hash_alg_common *halg = crypto_hash_alg_common(hash);
54562306a36Sopenharmony_ci	struct crypto_tfm *tfm = crypto_ahash_tfm(hash);
54662306a36Sopenharmony_ci	struct crypto_ahash *nhash;
54762306a36Sopenharmony_ci	struct ahash_alg *alg;
54862306a36Sopenharmony_ci	int err;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (!crypto_hash_alg_has_setkey(halg)) {
55162306a36Sopenharmony_ci		tfm = crypto_tfm_get(tfm);
55262306a36Sopenharmony_ci		if (IS_ERR(tfm))
55362306a36Sopenharmony_ci			return ERR_CAST(tfm);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		return hash;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	nhash = crypto_clone_tfm(&crypto_ahash_type, tfm);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (IS_ERR(nhash))
56162306a36Sopenharmony_ci		return nhash;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	nhash->init = hash->init;
56462306a36Sopenharmony_ci	nhash->update = hash->update;
56562306a36Sopenharmony_ci	nhash->final = hash->final;
56662306a36Sopenharmony_ci	nhash->finup = hash->finup;
56762306a36Sopenharmony_ci	nhash->digest = hash->digest;
56862306a36Sopenharmony_ci	nhash->export = hash->export;
56962306a36Sopenharmony_ci	nhash->import = hash->import;
57062306a36Sopenharmony_ci	nhash->setkey = hash->setkey;
57162306a36Sopenharmony_ci	nhash->reqsize = hash->reqsize;
57262306a36Sopenharmony_ci	nhash->statesize = hash->statesize;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
57562306a36Sopenharmony_ci		return crypto_clone_shash_ops_async(nhash, hash);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	err = -ENOSYS;
57862306a36Sopenharmony_ci	alg = crypto_ahash_alg(hash);
57962306a36Sopenharmony_ci	if (!alg->clone_tfm)
58062306a36Sopenharmony_ci		goto out_free_nhash;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	err = alg->clone_tfm(nhash, hash);
58362306a36Sopenharmony_ci	if (err)
58462306a36Sopenharmony_ci		goto out_free_nhash;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	return nhash;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ciout_free_nhash:
58962306a36Sopenharmony_ci	crypto_free_ahash(nhash);
59062306a36Sopenharmony_ci	return ERR_PTR(err);
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_clone_ahash);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic int ahash_prepare_alg(struct ahash_alg *alg)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct crypto_alg *base = &alg->halg.base;
59762306a36Sopenharmony_ci	int err;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (alg->halg.statesize == 0)
60062306a36Sopenharmony_ci		return -EINVAL;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	err = hash_prepare_alg(&alg->halg);
60362306a36Sopenharmony_ci	if (err)
60462306a36Sopenharmony_ci		return err;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	base->cra_type = &crypto_ahash_type;
60762306a36Sopenharmony_ci	base->cra_flags |= CRYPTO_ALG_TYPE_AHASH;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	return 0;
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ciint crypto_register_ahash(struct ahash_alg *alg)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	struct crypto_alg *base = &alg->halg.base;
61562306a36Sopenharmony_ci	int err;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	err = ahash_prepare_alg(alg);
61862306a36Sopenharmony_ci	if (err)
61962306a36Sopenharmony_ci		return err;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	return crypto_register_alg(base);
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_register_ahash);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_civoid crypto_unregister_ahash(struct ahash_alg *alg)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	crypto_unregister_alg(&alg->halg.base);
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_unregister_ahash);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ciint crypto_register_ahashes(struct ahash_alg *algs, int count)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	int i, ret;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
63662306a36Sopenharmony_ci		ret = crypto_register_ahash(&algs[i]);
63762306a36Sopenharmony_ci		if (ret)
63862306a36Sopenharmony_ci			goto err;
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	return 0;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cierr:
64462306a36Sopenharmony_ci	for (--i; i >= 0; --i)
64562306a36Sopenharmony_ci		crypto_unregister_ahash(&algs[i]);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	return ret;
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_register_ahashes);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_civoid crypto_unregister_ahashes(struct ahash_alg *algs, int count)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	int i;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	for (i = count - 1; i >= 0; --i)
65662306a36Sopenharmony_ci		crypto_unregister_ahash(&algs[i]);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_unregister_ahashes);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ciint ahash_register_instance(struct crypto_template *tmpl,
66162306a36Sopenharmony_ci			    struct ahash_instance *inst)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	int err;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (WARN_ON(!inst->free))
66662306a36Sopenharmony_ci		return -EINVAL;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	err = ahash_prepare_alg(&inst->alg);
66962306a36Sopenharmony_ci	if (err)
67062306a36Sopenharmony_ci		return err;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	return crypto_register_instance(tmpl, ahash_crypto_instance(inst));
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ahash_register_instance);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cibool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	struct crypto_alg *alg = &halg->base;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (alg->cra_type != &crypto_ahash_type)
68162306a36Sopenharmony_ci		return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	return __crypto_ahash_alg(alg)->setkey != NULL;
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
68862306a36Sopenharmony_ciMODULE_DESCRIPTION("Asynchronous cryptographic hash type");
689