xref: /openbmc/linux/crypto/ahash.c (revision 255e48eb17684157336bd6dd98d22c1b2d9e3f43)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2004a403cSLoc Ho /*
3004a403cSLoc Ho  * Asynchronous Cryptographic Hash operations.
4004a403cSLoc Ho  *
5004a403cSLoc Ho  * This is the asynchronous version of hash.c with notification of
6004a403cSLoc Ho  * completion via a callback.
7004a403cSLoc Ho  *
8004a403cSLoc Ho  * Copyright (c) 2008 Loc Ho <lho@amcc.com>
9004a403cSLoc Ho  */
10004a403cSLoc Ho 
1120036252SHerbert Xu #include <crypto/internal/hash.h>
1220036252SHerbert Xu #include <crypto/scatterwalk.h>
13004a403cSLoc Ho #include <linux/err.h>
14004a403cSLoc Ho #include <linux/kernel.h>
15004a403cSLoc Ho #include <linux/module.h>
16004a403cSLoc Ho #include <linux/sched.h>
17004a403cSLoc Ho #include <linux/slab.h>
18004a403cSLoc Ho #include <linux/seq_file.h>
196238cbaeSSteffen Klassert #include <linux/cryptouser.h>
20d8c34b94SGideon Israel Dsouza #include <linux/compiler.h>
216238cbaeSSteffen Klassert #include <net/netlink.h>
22004a403cSLoc Ho 
23004a403cSLoc Ho #include "internal.h"
24004a403cSLoc Ho 
256d1b41fcSEric Biggers static const struct crypto_type crypto_ahash_type;
266d1b41fcSEric Biggers 
2766f6ce5eSHerbert Xu struct ahash_request_priv {
2866f6ce5eSHerbert Xu 	crypto_completion_t complete;
2966f6ce5eSHerbert Xu 	void *data;
3066f6ce5eSHerbert Xu 	u8 *result;
31ef0579b6SHerbert Xu 	u32 flags;
3266f6ce5eSHerbert Xu 	void *ubuf[] CRYPTO_MINALIGN_ATTR;
3366f6ce5eSHerbert Xu };
3466f6ce5eSHerbert Xu 
3588056ec3SHerbert Xu static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash)
3688056ec3SHerbert Xu {
3788056ec3SHerbert Xu 	return container_of(crypto_hash_alg_common(hash), struct ahash_alg,
3888056ec3SHerbert Xu 			    halg);
3988056ec3SHerbert Xu }
4088056ec3SHerbert Xu 
4120036252SHerbert Xu static int hash_walk_next(struct crypto_hash_walk *walk)
4220036252SHerbert Xu {
4320036252SHerbert Xu 	unsigned int alignmask = walk->alignmask;
4420036252SHerbert Xu 	unsigned int offset = walk->offset;
4520036252SHerbert Xu 	unsigned int nbytes = min(walk->entrylen,
4620036252SHerbert Xu 				  ((unsigned int)(PAGE_SIZE)) - offset);
4720036252SHerbert Xu 
48aa969515SArd Biesheuvel 	walk->data = kmap_local_page(walk->pg);
4920036252SHerbert Xu 	walk->data += offset;
5020036252SHerbert Xu 
5123a75eeeSSzilveszter Ördög 	if (offset & alignmask) {
5223a75eeeSSzilveszter Ördög 		unsigned int unaligned = alignmask + 1 - (offset & alignmask);
53b516d514SJoshua I. James 
5423a75eeeSSzilveszter Ördög 		if (nbytes > unaligned)
5523a75eeeSSzilveszter Ördög 			nbytes = unaligned;
5623a75eeeSSzilveszter Ördög 	}
5720036252SHerbert Xu 
5820036252SHerbert Xu 	walk->entrylen -= nbytes;
5920036252SHerbert Xu 	return nbytes;
6020036252SHerbert Xu }
6120036252SHerbert Xu 
6220036252SHerbert Xu static int hash_walk_new_entry(struct crypto_hash_walk *walk)
6320036252SHerbert Xu {
6420036252SHerbert Xu 	struct scatterlist *sg;
6520036252SHerbert Xu 
6620036252SHerbert Xu 	sg = walk->sg;
6720036252SHerbert Xu 	walk->offset = sg->offset;
6813f4bb78SHerbert Xu 	walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT);
6913f4bb78SHerbert Xu 	walk->offset = offset_in_page(walk->offset);
7020036252SHerbert Xu 	walk->entrylen = sg->length;
7120036252SHerbert Xu 
7220036252SHerbert Xu 	if (walk->entrylen > walk->total)
7320036252SHerbert Xu 		walk->entrylen = walk->total;
7420036252SHerbert Xu 	walk->total -= walk->entrylen;
7520036252SHerbert Xu 
7620036252SHerbert Xu 	return hash_walk_next(walk);
7720036252SHerbert Xu }
7820036252SHerbert Xu 
7920036252SHerbert Xu int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err)
8020036252SHerbert Xu {
8120036252SHerbert Xu 	unsigned int alignmask = walk->alignmask;
8220036252SHerbert Xu 
8320036252SHerbert Xu 	walk->data -= walk->offset;
8420036252SHerbert Xu 
8577568e53SEric Biggers 	if (walk->entrylen && (walk->offset & alignmask) && !err) {
8677568e53SEric Biggers 		unsigned int nbytes;
8720036252SHerbert Xu 
8877568e53SEric Biggers 		walk->offset = ALIGN(walk->offset, alignmask + 1);
8977568e53SEric Biggers 		nbytes = min(walk->entrylen,
9077568e53SEric Biggers 			     (unsigned int)(PAGE_SIZE - walk->offset));
91900a081fSHerbert Xu 		if (nbytes) {
9277568e53SEric Biggers 			walk->entrylen -= nbytes;
93900a081fSHerbert Xu 			walk->data += walk->offset;
9420036252SHerbert Xu 			return nbytes;
9520036252SHerbert Xu 		}
96900a081fSHerbert Xu 	}
9720036252SHerbert Xu 
98aa969515SArd Biesheuvel 	kunmap_local(walk->data);
9920036252SHerbert Xu 	crypto_yield(walk->flags);
10020036252SHerbert Xu 
10120036252SHerbert Xu 	if (err)
10220036252SHerbert Xu 		return err;
10320036252SHerbert Xu 
10477568e53SEric Biggers 	if (walk->entrylen) {
10520036252SHerbert Xu 		walk->offset = 0;
106d315a0e0SHerbert Xu 		walk->pg++;
10720036252SHerbert Xu 		return hash_walk_next(walk);
108d315a0e0SHerbert Xu 	}
10920036252SHerbert Xu 
11020036252SHerbert Xu 	if (!walk->total)
11120036252SHerbert Xu 		return 0;
11220036252SHerbert Xu 
1135be4d4c9SCristian Stoica 	walk->sg = sg_next(walk->sg);
11420036252SHerbert Xu 
11520036252SHerbert Xu 	return hash_walk_new_entry(walk);
11620036252SHerbert Xu }
11720036252SHerbert Xu EXPORT_SYMBOL_GPL(crypto_hash_walk_done);
11820036252SHerbert Xu 
11920036252SHerbert Xu int crypto_hash_walk_first(struct ahash_request *req,
12020036252SHerbert Xu 			   struct crypto_hash_walk *walk)
12120036252SHerbert Xu {
12220036252SHerbert Xu 	walk->total = req->nbytes;
12320036252SHerbert Xu 
1246d9529c5STim Chen 	if (!walk->total) {
1256d9529c5STim Chen 		walk->entrylen = 0;
12620036252SHerbert Xu 		return 0;
1276d9529c5STim Chen 	}
12820036252SHerbert Xu 
12920036252SHerbert Xu 	walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req));
13020036252SHerbert Xu 	walk->sg = req->src;
1318afa25aaSIra Weiny 	walk->flags = req->base.flags;
13220036252SHerbert Xu 
13320036252SHerbert Xu 	return hash_walk_new_entry(walk);
13420036252SHerbert Xu }
13520036252SHerbert Xu EXPORT_SYMBOL_GPL(crypto_hash_walk_first);
13620036252SHerbert Xu 
137004a403cSLoc Ho static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
138004a403cSLoc Ho 				unsigned int keylen)
139004a403cSLoc Ho {
140004a403cSLoc Ho 	unsigned long alignmask = crypto_ahash_alignmask(tfm);
141004a403cSLoc Ho 	int ret;
142004a403cSLoc Ho 	u8 *buffer, *alignbuffer;
143004a403cSLoc Ho 	unsigned long absize;
144004a403cSLoc Ho 
145004a403cSLoc Ho 	absize = keylen + alignmask;
146093900c2SHerbert Xu 	buffer = kmalloc(absize, GFP_KERNEL);
147004a403cSLoc Ho 	if (!buffer)
148004a403cSLoc Ho 		return -ENOMEM;
149004a403cSLoc Ho 
150004a403cSLoc Ho 	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
151004a403cSLoc Ho 	memcpy(alignbuffer, key, keylen);
152a70c5225SHerbert Xu 	ret = tfm->setkey(tfm, alignbuffer, keylen);
153453431a5SWaiman Long 	kfree_sensitive(buffer);
154004a403cSLoc Ho 	return ret;
155004a403cSLoc Ho }
156004a403cSLoc Ho 
157ba7d7433SEric Biggers static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key,
158ba7d7433SEric Biggers 			  unsigned int keylen)
159ba7d7433SEric Biggers {
160ba7d7433SEric Biggers 	return -ENOSYS;
161ba7d7433SEric Biggers }
162ba7d7433SEric Biggers 
163ba7d7433SEric Biggers static void ahash_set_needkey(struct crypto_ahash *tfm)
164ba7d7433SEric Biggers {
165ba7d7433SEric Biggers 	const struct hash_alg_common *alg = crypto_hash_alg_common(tfm);
166ba7d7433SEric Biggers 
167ba7d7433SEric Biggers 	if (tfm->setkey != ahash_nosetkey &&
168ba7d7433SEric Biggers 	    !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
169ba7d7433SEric Biggers 		crypto_ahash_set_flags(tfm, CRYPTO_TFM_NEED_KEY);
170ba7d7433SEric Biggers }
171ba7d7433SEric Biggers 
17266f6ce5eSHerbert Xu int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
173004a403cSLoc Ho 			unsigned int keylen)
174004a403cSLoc Ho {
175004a403cSLoc Ho 	unsigned long alignmask = crypto_ahash_alignmask(tfm);
1769fa68f62SEric Biggers 	int err;
177004a403cSLoc Ho 
178004a403cSLoc Ho 	if ((unsigned long)key & alignmask)
1799fa68f62SEric Biggers 		err = ahash_setkey_unaligned(tfm, key, keylen);
1809fa68f62SEric Biggers 	else
1819fa68f62SEric Biggers 		err = tfm->setkey(tfm, key, keylen);
182004a403cSLoc Ho 
183ba7d7433SEric Biggers 	if (unlikely(err)) {
184ba7d7433SEric Biggers 		ahash_set_needkey(tfm);
1859fa68f62SEric Biggers 		return err;
186ba7d7433SEric Biggers 	}
1879fa68f62SEric Biggers 
1889fa68f62SEric Biggers 	crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
1899fa68f62SEric Biggers 	return 0;
190004a403cSLoc Ho }
19166f6ce5eSHerbert Xu EXPORT_SYMBOL_GPL(crypto_ahash_setkey);
192004a403cSLoc Ho 
193d9588045SHerbert Xu static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt,
194d9588045SHerbert Xu 			  bool has_state)
19566f6ce5eSHerbert Xu {
19666f6ce5eSHerbert Xu 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
19766f6ce5eSHerbert Xu 	unsigned long alignmask = crypto_ahash_alignmask(tfm);
19866f6ce5eSHerbert Xu 	unsigned int ds = crypto_ahash_digestsize(tfm);
199d9588045SHerbert Xu 	struct ahash_request *subreq;
200d9588045SHerbert Xu 	unsigned int subreq_size;
201d9588045SHerbert Xu 	unsigned int reqsize;
202d9588045SHerbert Xu 	u8 *result;
203d9588045SHerbert Xu 	gfp_t gfp;
204d9588045SHerbert Xu 	u32 flags;
20566f6ce5eSHerbert Xu 
206d9588045SHerbert Xu 	subreq_size = sizeof(*subreq);
207d9588045SHerbert Xu 	reqsize = crypto_ahash_reqsize(tfm);
208d9588045SHerbert Xu 	reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment());
209d9588045SHerbert Xu 	subreq_size += reqsize;
210d9588045SHerbert Xu 	subreq_size += ds;
211d9588045SHerbert Xu 	subreq_size += alignmask & ~(crypto_tfm_ctx_alignment() - 1);
212d9588045SHerbert Xu 
213d9588045SHerbert Xu 	flags = ahash_request_flags(req);
214d9588045SHerbert Xu 	gfp = (flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?  GFP_KERNEL : GFP_ATOMIC;
215d9588045SHerbert Xu 	subreq = kmalloc(subreq_size, gfp);
216d9588045SHerbert Xu 	if (!subreq)
21766f6ce5eSHerbert Xu 		return -ENOMEM;
21866f6ce5eSHerbert Xu 
219d9588045SHerbert Xu 	ahash_request_set_tfm(subreq, tfm);
220d9588045SHerbert Xu 	ahash_request_set_callback(subreq, flags, cplt, req);
221ab6bf4e5SMarek Vasut 
222d9588045SHerbert Xu 	result = (u8 *)(subreq + 1) + reqsize;
223d9588045SHerbert Xu 	result = PTR_ALIGN(result, alignmask + 1);
224ef0579b6SHerbert Xu 
225d9588045SHerbert Xu 	ahash_request_set_crypt(subreq, req->src, result, req->nbytes);
22666f6ce5eSHerbert Xu 
227d9588045SHerbert Xu 	if (has_state) {
228d9588045SHerbert Xu 		void *state;
229d9588045SHerbert Xu 
230d9588045SHerbert Xu 		state = kmalloc(crypto_ahash_statesize(tfm), gfp);
231d9588045SHerbert Xu 		if (!state) {
232d9588045SHerbert Xu 			kfree(subreq);
233d9588045SHerbert Xu 			return -ENOMEM;
234d9588045SHerbert Xu 		}
235d9588045SHerbert Xu 
236d9588045SHerbert Xu 		crypto_ahash_export(req, state);
237d9588045SHerbert Xu 		crypto_ahash_import(subreq, state);
238d9588045SHerbert Xu 		kfree_sensitive(state);
239d9588045SHerbert Xu 	}
240d9588045SHerbert Xu 
241d9588045SHerbert Xu 	req->priv = subreq;
24266f6ce5eSHerbert Xu 
2431ffc9fbdSMarek Vasut 	return 0;
2441ffc9fbdSMarek Vasut }
2451ffc9fbdSMarek Vasut 
246ef0579b6SHerbert Xu static void ahash_restore_req(struct ahash_request *req, int err)
2471ffc9fbdSMarek Vasut {
248d9588045SHerbert Xu 	struct ahash_request *subreq = req->priv;
2491ffc9fbdSMarek Vasut 
250ef0579b6SHerbert Xu 	if (!err)
251d9588045SHerbert Xu 		memcpy(req->result, subreq->result,
252ef0579b6SHerbert Xu 		       crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
253ef0579b6SHerbert Xu 
2541ffc9fbdSMarek Vasut 	req->priv = NULL;
2551ffc9fbdSMarek Vasut 
256d9588045SHerbert Xu 	kfree_sensitive(subreq);
2571ffc9fbdSMarek Vasut }
2581ffc9fbdSMarek Vasut 
259*255e48ebSHerbert Xu static void ahash_op_unaligned_done(void *data, int err)
2601ffc9fbdSMarek Vasut {
261*255e48ebSHerbert Xu 	struct ahash_request *areq = data;
2621ffc9fbdSMarek Vasut 
263d9588045SHerbert Xu 	if (err == -EINPROGRESS)
264d9588045SHerbert Xu 		goto out;
2651ffc9fbdSMarek Vasut 
2661ffc9fbdSMarek Vasut 	/* First copy req->result into req->priv.result */
267ef0579b6SHerbert Xu 	ahash_restore_req(areq, err);
2681ffc9fbdSMarek Vasut 
269d9588045SHerbert Xu out:
2701ffc9fbdSMarek Vasut 	/* Complete the ORIGINAL request. */
271d9588045SHerbert Xu 	ahash_request_complete(areq, err);
2721ffc9fbdSMarek Vasut }
2731ffc9fbdSMarek Vasut 
2741ffc9fbdSMarek Vasut static int ahash_op_unaligned(struct ahash_request *req,
275d9588045SHerbert Xu 			      int (*op)(struct ahash_request *),
276d9588045SHerbert Xu 			      bool has_state)
2771ffc9fbdSMarek Vasut {
2781ffc9fbdSMarek Vasut 	int err;
2791ffc9fbdSMarek Vasut 
280d9588045SHerbert Xu 	err = ahash_save_req(req, ahash_op_unaligned_done, has_state);
2811ffc9fbdSMarek Vasut 	if (err)
2821ffc9fbdSMarek Vasut 		return err;
2831ffc9fbdSMarek Vasut 
284d9588045SHerbert Xu 	err = op(req->priv);
2854e5b0ad5SGilad Ben-Yossef 	if (err == -EINPROGRESS || err == -EBUSY)
286ef0579b6SHerbert Xu 		return err;
287ef0579b6SHerbert Xu 
288ef0579b6SHerbert Xu 	ahash_restore_req(req, err);
28966f6ce5eSHerbert Xu 
29066f6ce5eSHerbert Xu 	return err;
29166f6ce5eSHerbert Xu }
29266f6ce5eSHerbert Xu 
29366f6ce5eSHerbert Xu static int crypto_ahash_op(struct ahash_request *req,
294d9588045SHerbert Xu 			   int (*op)(struct ahash_request *),
295d9588045SHerbert Xu 			   bool has_state)
29666f6ce5eSHerbert Xu {
29766f6ce5eSHerbert Xu 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
29866f6ce5eSHerbert Xu 	unsigned long alignmask = crypto_ahash_alignmask(tfm);
29966f6ce5eSHerbert Xu 
30066f6ce5eSHerbert Xu 	if ((unsigned long)req->result & alignmask)
301d9588045SHerbert Xu 		return ahash_op_unaligned(req, op, has_state);
30266f6ce5eSHerbert Xu 
30366f6ce5eSHerbert Xu 	return op(req);
30466f6ce5eSHerbert Xu }
30566f6ce5eSHerbert Xu 
30666f6ce5eSHerbert Xu int crypto_ahash_final(struct ahash_request *req)
30766f6ce5eSHerbert Xu {
308f7d76e05SCorentin Labbe 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
309f7d76e05SCorentin Labbe 	struct crypto_alg *alg = tfm->base.__crt_alg;
310f7d76e05SCorentin Labbe 	unsigned int nbytes = req->nbytes;
311cac5818cSCorentin Labbe 	int ret;
312cac5818cSCorentin Labbe 
313f7d76e05SCorentin Labbe 	crypto_stats_get(alg);
314d9588045SHerbert Xu 	ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final, true);
315f7d76e05SCorentin Labbe 	crypto_stats_ahash_final(nbytes, ret, alg);
316cac5818cSCorentin Labbe 	return ret;
31766f6ce5eSHerbert Xu }
31866f6ce5eSHerbert Xu EXPORT_SYMBOL_GPL(crypto_ahash_final);
31966f6ce5eSHerbert Xu 
32066f6ce5eSHerbert Xu int crypto_ahash_finup(struct ahash_request *req)
32166f6ce5eSHerbert Xu {
322f7d76e05SCorentin Labbe 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
323f7d76e05SCorentin Labbe 	struct crypto_alg *alg = tfm->base.__crt_alg;
324f7d76e05SCorentin Labbe 	unsigned int nbytes = req->nbytes;
325cac5818cSCorentin Labbe 	int ret;
326cac5818cSCorentin Labbe 
327f7d76e05SCorentin Labbe 	crypto_stats_get(alg);
328d9588045SHerbert Xu 	ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup, true);
329f7d76e05SCorentin Labbe 	crypto_stats_ahash_final(nbytes, ret, alg);
330cac5818cSCorentin Labbe 	return ret;
33166f6ce5eSHerbert Xu }
33266f6ce5eSHerbert Xu EXPORT_SYMBOL_GPL(crypto_ahash_finup);
33366f6ce5eSHerbert Xu 
33466f6ce5eSHerbert Xu int crypto_ahash_digest(struct ahash_request *req)
33566f6ce5eSHerbert Xu {
3369fa68f62SEric Biggers 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
337f7d76e05SCorentin Labbe 	struct crypto_alg *alg = tfm->base.__crt_alg;
338f7d76e05SCorentin Labbe 	unsigned int nbytes = req->nbytes;
339cac5818cSCorentin Labbe 	int ret;
3409fa68f62SEric Biggers 
341f7d76e05SCorentin Labbe 	crypto_stats_get(alg);
3429fa68f62SEric Biggers 	if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
343cac5818cSCorentin Labbe 		ret = -ENOKEY;
344cac5818cSCorentin Labbe 	else
345d9588045SHerbert Xu 		ret = crypto_ahash_op(req, tfm->digest, false);
346f7d76e05SCorentin Labbe 	crypto_stats_ahash_final(nbytes, ret, alg);
347cac5818cSCorentin Labbe 	return ret;
34866f6ce5eSHerbert Xu }
34966f6ce5eSHerbert Xu EXPORT_SYMBOL_GPL(crypto_ahash_digest);
35066f6ce5eSHerbert Xu 
351*255e48ebSHerbert Xu static void ahash_def_finup_done2(void *data, int err)
35266f6ce5eSHerbert Xu {
353*255e48ebSHerbert Xu 	struct ahash_request *areq = data;
35466f6ce5eSHerbert Xu 
355ef0579b6SHerbert Xu 	if (err == -EINPROGRESS)
356ef0579b6SHerbert Xu 		return;
357ef0579b6SHerbert Xu 
358ef0579b6SHerbert Xu 	ahash_restore_req(areq, err);
35966f6ce5eSHerbert Xu 
360d9588045SHerbert Xu 	ahash_request_complete(areq, err);
36166f6ce5eSHerbert Xu }
36266f6ce5eSHerbert Xu 
36366f6ce5eSHerbert Xu static int ahash_def_finup_finish1(struct ahash_request *req, int err)
36466f6ce5eSHerbert Xu {
365d9588045SHerbert Xu 	struct ahash_request *subreq = req->priv;
366d9588045SHerbert Xu 
36766f6ce5eSHerbert Xu 	if (err)
36866f6ce5eSHerbert Xu 		goto out;
36966f6ce5eSHerbert Xu 
370d9588045SHerbert Xu 	subreq->base.complete = ahash_def_finup_done2;
371ef0579b6SHerbert Xu 
372d9588045SHerbert Xu 	err = crypto_ahash_reqtfm(req)->final(subreq);
3734e5b0ad5SGilad Ben-Yossef 	if (err == -EINPROGRESS || err == -EBUSY)
374ef0579b6SHerbert Xu 		return err;
37566f6ce5eSHerbert Xu 
37666f6ce5eSHerbert Xu out:
377ef0579b6SHerbert Xu 	ahash_restore_req(req, err);
37866f6ce5eSHerbert Xu 	return err;
37966f6ce5eSHerbert Xu }
38066f6ce5eSHerbert Xu 
381*255e48ebSHerbert Xu static void ahash_def_finup_done1(void *data, int err)
38266f6ce5eSHerbert Xu {
383*255e48ebSHerbert Xu 	struct ahash_request *areq = data;
384d9588045SHerbert Xu 	struct ahash_request *subreq;
38566f6ce5eSHerbert Xu 
386d9588045SHerbert Xu 	if (err == -EINPROGRESS)
387d9588045SHerbert Xu 		goto out;
388ef0579b6SHerbert Xu 
389d9588045SHerbert Xu 	subreq = areq->priv;
390d9588045SHerbert Xu 	subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
391ef0579b6SHerbert Xu 
39266f6ce5eSHerbert Xu 	err = ahash_def_finup_finish1(areq, err);
393d9588045SHerbert Xu 	if (err == -EINPROGRESS || err == -EBUSY)
394ef0579b6SHerbert Xu 		return;
39566f6ce5eSHerbert Xu 
396d9588045SHerbert Xu out:
397d9588045SHerbert Xu 	ahash_request_complete(areq, err);
39866f6ce5eSHerbert Xu }
39966f6ce5eSHerbert Xu 
40066f6ce5eSHerbert Xu static int ahash_def_finup(struct ahash_request *req)
40166f6ce5eSHerbert Xu {
40266f6ce5eSHerbert Xu 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
403d4a7a0fbSMarek Vasut 	int err;
40466f6ce5eSHerbert Xu 
405d9588045SHerbert Xu 	err = ahash_save_req(req, ahash_def_finup_done1, true);
406d4a7a0fbSMarek Vasut 	if (err)
407d4a7a0fbSMarek Vasut 		return err;
40866f6ce5eSHerbert Xu 
409d9588045SHerbert Xu 	err = tfm->update(req->priv);
4104e5b0ad5SGilad Ben-Yossef 	if (err == -EINPROGRESS || err == -EBUSY)
411ef0579b6SHerbert Xu 		return err;
412ef0579b6SHerbert Xu 
413d4a7a0fbSMarek Vasut 	return ahash_def_finup_finish1(req, err);
41466f6ce5eSHerbert Xu }
41566f6ce5eSHerbert Xu 
416e73d340dSHerbert Xu static void crypto_ahash_exit_tfm(struct crypto_tfm *tfm)
417e73d340dSHerbert Xu {
418e73d340dSHerbert Xu 	struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
419e73d340dSHerbert Xu 	struct ahash_alg *alg = crypto_ahash_alg(hash);
420e73d340dSHerbert Xu 
421e73d340dSHerbert Xu 	alg->exit_tfm(hash);
422e73d340dSHerbert Xu }
423e73d340dSHerbert Xu 
42488056ec3SHerbert Xu static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
42588056ec3SHerbert Xu {
42688056ec3SHerbert Xu 	struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
42788056ec3SHerbert Xu 	struct ahash_alg *alg = crypto_ahash_alg(hash);
42888056ec3SHerbert Xu 
42966f6ce5eSHerbert Xu 	hash->setkey = ahash_nosetkey;
43066f6ce5eSHerbert Xu 
43188056ec3SHerbert Xu 	if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
43288056ec3SHerbert Xu 		return crypto_init_shash_ops_async(tfm);
43388056ec3SHerbert Xu 
43488056ec3SHerbert Xu 	hash->init = alg->init;
43588056ec3SHerbert Xu 	hash->update = alg->update;
43688056ec3SHerbert Xu 	hash->final = alg->final;
43766f6ce5eSHerbert Xu 	hash->finup = alg->finup ?: ahash_def_finup;
43888056ec3SHerbert Xu 	hash->digest = alg->digest;
4396f221f7eSKamil Konieczny 	hash->export = alg->export;
4406f221f7eSKamil Konieczny 	hash->import = alg->import;
44166f6ce5eSHerbert Xu 
442a5596d63SHerbert Xu 	if (alg->setkey) {
44366f6ce5eSHerbert Xu 		hash->setkey = alg->setkey;
444ba7d7433SEric Biggers 		ahash_set_needkey(hash);
445a5596d63SHerbert Xu 	}
44688056ec3SHerbert Xu 
447e73d340dSHerbert Xu 	if (alg->exit_tfm)
448e73d340dSHerbert Xu 		tfm->exit = crypto_ahash_exit_tfm;
449e73d340dSHerbert Xu 
450e73d340dSHerbert Xu 	return alg->init_tfm ? alg->init_tfm(hash) : 0;
45188056ec3SHerbert Xu }
45288056ec3SHerbert Xu 
45388056ec3SHerbert Xu static unsigned int crypto_ahash_extsize(struct crypto_alg *alg)
45488056ec3SHerbert Xu {
4552495cf25SHerbert Xu 	if (alg->cra_type != &crypto_ahash_type)
45688056ec3SHerbert Xu 		return sizeof(struct crypto_shash *);
4572495cf25SHerbert Xu 
4582495cf25SHerbert Xu 	return crypto_alg_extsize(alg);
45988056ec3SHerbert Xu }
46088056ec3SHerbert Xu 
46148fb3e57SEric Biggers static void crypto_ahash_free_instance(struct crypto_instance *inst)
46248fb3e57SEric Biggers {
46348fb3e57SEric Biggers 	struct ahash_instance *ahash = ahash_instance(inst);
46448fb3e57SEric Biggers 
46548fb3e57SEric Biggers 	ahash->free(ahash);
46648fb3e57SEric Biggers }
46748fb3e57SEric Biggers 
4683acc8473SHerbert Xu #ifdef CONFIG_NET
4696238cbaeSSteffen Klassert static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
4706238cbaeSSteffen Klassert {
4716238cbaeSSteffen Klassert 	struct crypto_report_hash rhash;
4726238cbaeSSteffen Klassert 
47337db69e0SEric Biggers 	memset(&rhash, 0, sizeof(rhash));
47437db69e0SEric Biggers 
47537db69e0SEric Biggers 	strscpy(rhash.type, "ahash", sizeof(rhash.type));
4766238cbaeSSteffen Klassert 
4776238cbaeSSteffen Klassert 	rhash.blocksize = alg->cra_blocksize;
4786238cbaeSSteffen Klassert 	rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize;
4796238cbaeSSteffen Klassert 
48037db69e0SEric Biggers 	return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash);
4816238cbaeSSteffen Klassert }
4823acc8473SHerbert Xu #else
4833acc8473SHerbert Xu static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
4843acc8473SHerbert Xu {
4853acc8473SHerbert Xu 	return -ENOSYS;
4863acc8473SHerbert Xu }
4873acc8473SHerbert Xu #endif
4886238cbaeSSteffen Klassert 
489004a403cSLoc Ho static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
490d8c34b94SGideon Israel Dsouza 	__maybe_unused;
491004a403cSLoc Ho static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
492004a403cSLoc Ho {
493004a403cSLoc Ho 	seq_printf(m, "type         : ahash\n");
494004a403cSLoc Ho 	seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
495004a403cSLoc Ho 					     "yes" : "no");
496004a403cSLoc Ho 	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
49788056ec3SHerbert Xu 	seq_printf(m, "digestsize   : %u\n",
49888056ec3SHerbert Xu 		   __crypto_hash_alg_common(alg)->digestsize);
499004a403cSLoc Ho }
500004a403cSLoc Ho 
5016d1b41fcSEric Biggers static const struct crypto_type crypto_ahash_type = {
50288056ec3SHerbert Xu 	.extsize = crypto_ahash_extsize,
50388056ec3SHerbert Xu 	.init_tfm = crypto_ahash_init_tfm,
50448fb3e57SEric Biggers 	.free = crypto_ahash_free_instance,
505004a403cSLoc Ho #ifdef CONFIG_PROC_FS
506004a403cSLoc Ho 	.show = crypto_ahash_show,
507004a403cSLoc Ho #endif
5086238cbaeSSteffen Klassert 	.report = crypto_ahash_report,
50988056ec3SHerbert Xu 	.maskclear = ~CRYPTO_ALG_TYPE_MASK,
51088056ec3SHerbert Xu 	.maskset = CRYPTO_ALG_TYPE_AHASH_MASK,
51188056ec3SHerbert Xu 	.type = CRYPTO_ALG_TYPE_AHASH,
51288056ec3SHerbert Xu 	.tfmsize = offsetof(struct crypto_ahash, base),
513004a403cSLoc Ho };
514004a403cSLoc Ho 
51584a9c938SEric Biggers int crypto_grab_ahash(struct crypto_ahash_spawn *spawn,
51684a9c938SEric Biggers 		      struct crypto_instance *inst,
51784a9c938SEric Biggers 		      const char *name, u32 type, u32 mask)
51884a9c938SEric Biggers {
51984a9c938SEric Biggers 	spawn->base.frontend = &crypto_ahash_type;
52084a9c938SEric Biggers 	return crypto_grab_spawn(&spawn->base, inst, name, type, mask);
52184a9c938SEric Biggers }
52284a9c938SEric Biggers EXPORT_SYMBOL_GPL(crypto_grab_ahash);
52384a9c938SEric Biggers 
52488056ec3SHerbert Xu struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type,
52588056ec3SHerbert Xu 					u32 mask)
52688056ec3SHerbert Xu {
52788056ec3SHerbert Xu 	return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask);
52888056ec3SHerbert Xu }
52988056ec3SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alloc_ahash);
53088056ec3SHerbert Xu 
5318d18e34cSHerbert Xu int crypto_has_ahash(const char *alg_name, u32 type, u32 mask)
5328d18e34cSHerbert Xu {
5338d18e34cSHerbert Xu 	return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask);
5348d18e34cSHerbert Xu }
5358d18e34cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_has_ahash);
5368d18e34cSHerbert Xu 
53701c2deceSHerbert Xu static int ahash_prepare_alg(struct ahash_alg *alg)
53801c2deceSHerbert Xu {
53901c2deceSHerbert Xu 	struct crypto_alg *base = &alg->halg.base;
54001c2deceSHerbert Xu 
541b68a7ec1SKees Cook 	if (alg->halg.digestsize > HASH_MAX_DIGESTSIZE ||
542b68a7ec1SKees Cook 	    alg->halg.statesize > HASH_MAX_STATESIZE ||
5438996eafdSRussell King 	    alg->halg.statesize == 0)
54401c2deceSHerbert Xu 		return -EINVAL;
54501c2deceSHerbert Xu 
54601c2deceSHerbert Xu 	base->cra_type = &crypto_ahash_type;
54701c2deceSHerbert Xu 	base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
54801c2deceSHerbert Xu 	base->cra_flags |= CRYPTO_ALG_TYPE_AHASH;
54901c2deceSHerbert Xu 
55001c2deceSHerbert Xu 	return 0;
55101c2deceSHerbert Xu }
55201c2deceSHerbert Xu 
55301c2deceSHerbert Xu int crypto_register_ahash(struct ahash_alg *alg)
55401c2deceSHerbert Xu {
55501c2deceSHerbert Xu 	struct crypto_alg *base = &alg->halg.base;
55601c2deceSHerbert Xu 	int err;
55701c2deceSHerbert Xu 
55801c2deceSHerbert Xu 	err = ahash_prepare_alg(alg);
55901c2deceSHerbert Xu 	if (err)
56001c2deceSHerbert Xu 		return err;
56101c2deceSHerbert Xu 
56201c2deceSHerbert Xu 	return crypto_register_alg(base);
56301c2deceSHerbert Xu }
56401c2deceSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_ahash);
56501c2deceSHerbert Xu 
566c6d633a9SEric Biggers void crypto_unregister_ahash(struct ahash_alg *alg)
56701c2deceSHerbert Xu {
568c6d633a9SEric Biggers 	crypto_unregister_alg(&alg->halg.base);
56901c2deceSHerbert Xu }
57001c2deceSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_ahash);
57101c2deceSHerbert Xu 
5726f7473c5SRabin Vincent int crypto_register_ahashes(struct ahash_alg *algs, int count)
5736f7473c5SRabin Vincent {
5746f7473c5SRabin Vincent 	int i, ret;
5756f7473c5SRabin Vincent 
5766f7473c5SRabin Vincent 	for (i = 0; i < count; i++) {
5776f7473c5SRabin Vincent 		ret = crypto_register_ahash(&algs[i]);
5786f7473c5SRabin Vincent 		if (ret)
5796f7473c5SRabin Vincent 			goto err;
5806f7473c5SRabin Vincent 	}
5816f7473c5SRabin Vincent 
5826f7473c5SRabin Vincent 	return 0;
5836f7473c5SRabin Vincent 
5846f7473c5SRabin Vincent err:
5856f7473c5SRabin Vincent 	for (--i; i >= 0; --i)
5866f7473c5SRabin Vincent 		crypto_unregister_ahash(&algs[i]);
5876f7473c5SRabin Vincent 
5886f7473c5SRabin Vincent 	return ret;
5896f7473c5SRabin Vincent }
5906f7473c5SRabin Vincent EXPORT_SYMBOL_GPL(crypto_register_ahashes);
5916f7473c5SRabin Vincent 
5926f7473c5SRabin Vincent void crypto_unregister_ahashes(struct ahash_alg *algs, int count)
5936f7473c5SRabin Vincent {
5946f7473c5SRabin Vincent 	int i;
5956f7473c5SRabin Vincent 
5966f7473c5SRabin Vincent 	for (i = count - 1; i >= 0; --i)
5976f7473c5SRabin Vincent 		crypto_unregister_ahash(&algs[i]);
5986f7473c5SRabin Vincent }
5996f7473c5SRabin Vincent EXPORT_SYMBOL_GPL(crypto_unregister_ahashes);
6006f7473c5SRabin Vincent 
60101c2deceSHerbert Xu int ahash_register_instance(struct crypto_template *tmpl,
60201c2deceSHerbert Xu 			    struct ahash_instance *inst)
60301c2deceSHerbert Xu {
60401c2deceSHerbert Xu 	int err;
60501c2deceSHerbert Xu 
606d4fdc2dfSEric Biggers 	if (WARN_ON(!inst->free))
607d4fdc2dfSEric Biggers 		return -EINVAL;
608d4fdc2dfSEric Biggers 
60901c2deceSHerbert Xu 	err = ahash_prepare_alg(&inst->alg);
61001c2deceSHerbert Xu 	if (err)
61101c2deceSHerbert Xu 		return err;
61201c2deceSHerbert Xu 
61301c2deceSHerbert Xu 	return crypto_register_instance(tmpl, ahash_crypto_instance(inst));
61401c2deceSHerbert Xu }
61501c2deceSHerbert Xu EXPORT_SYMBOL_GPL(ahash_register_instance);
61601c2deceSHerbert Xu 
617cd6ed77aSEric Biggers bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
618cd6ed77aSEric Biggers {
619cd6ed77aSEric Biggers 	struct crypto_alg *alg = &halg->base;
620cd6ed77aSEric Biggers 
621cd6ed77aSEric Biggers 	if (alg->cra_type != &crypto_ahash_type)
622cd6ed77aSEric Biggers 		return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
623cd6ed77aSEric Biggers 
624cd6ed77aSEric Biggers 	return __crypto_ahash_alg(alg)->setkey != NULL;
625cd6ed77aSEric Biggers }
626cd6ed77aSEric Biggers EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
627cd6ed77aSEric Biggers 
628004a403cSLoc Ho MODULE_LICENSE("GPL");
629004a403cSLoc Ho MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
630