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/scatterwalk.h>
1242808e5dSHerbert Xu #include <linux/cryptouser.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>
1942808e5dSHerbert Xu #include <linux/string.h>
206238cbaeSSteffen Klassert #include <net/netlink.h>
21004a403cSLoc Ho
2242808e5dSHerbert Xu #include "hash.h"
23004a403cSLoc Ho
246d1b41fcSEric Biggers static const struct crypto_type crypto_ahash_type;
256d1b41fcSEric Biggers
2666f6ce5eSHerbert Xu struct ahash_request_priv {
2766f6ce5eSHerbert Xu crypto_completion_t complete;
2866f6ce5eSHerbert Xu void *data;
2966f6ce5eSHerbert Xu u8 *result;
30ef0579b6SHerbert Xu u32 flags;
3166f6ce5eSHerbert Xu void *ubuf[] CRYPTO_MINALIGN_ATTR;
3266f6ce5eSHerbert Xu };
3366f6ce5eSHerbert Xu
hash_walk_next(struct crypto_hash_walk * walk)3488056ec3SHerbert Xu static int hash_walk_next(struct crypto_hash_walk *walk)
3588056ec3SHerbert Xu {
3688056ec3SHerbert Xu unsigned int alignmask = walk->alignmask;
3788056ec3SHerbert Xu unsigned int offset = walk->offset;
3888056ec3SHerbert Xu unsigned int nbytes = min(walk->entrylen,
3988056ec3SHerbert Xu ((unsigned int)(PAGE_SIZE)) - offset);
4020036252SHerbert Xu
4120036252SHerbert Xu walk->data = kmap_local_page(walk->pg);
4220036252SHerbert Xu walk->data += offset;
4320036252SHerbert Xu
4420036252SHerbert Xu if (offset & alignmask) {
4520036252SHerbert Xu unsigned int unaligned = alignmask + 1 - (offset & alignmask);
4620036252SHerbert Xu
47aa969515SArd Biesheuvel if (nbytes > unaligned)
4820036252SHerbert Xu nbytes = unaligned;
4920036252SHerbert Xu }
5023a75eeeSSzilveszter Ördög
5123a75eeeSSzilveszter Ördög walk->entrylen -= nbytes;
52b516d514SJoshua I. James return nbytes;
5323a75eeeSSzilveszter Ördög }
5423a75eeeSSzilveszter Ördög
hash_walk_new_entry(struct crypto_hash_walk * walk)5523a75eeeSSzilveszter Ördög static int hash_walk_new_entry(struct crypto_hash_walk *walk)
5620036252SHerbert Xu {
5720036252SHerbert Xu struct scatterlist *sg;
5820036252SHerbert Xu
5920036252SHerbert Xu sg = walk->sg;
6020036252SHerbert Xu walk->offset = sg->offset;
6120036252SHerbert Xu walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT);
6220036252SHerbert Xu walk->offset = offset_in_page(walk->offset);
6320036252SHerbert Xu walk->entrylen = sg->length;
6420036252SHerbert Xu
6520036252SHerbert Xu if (walk->entrylen > walk->total)
6620036252SHerbert Xu walk->entrylen = walk->total;
6713f4bb78SHerbert Xu walk->total -= walk->entrylen;
6813f4bb78SHerbert Xu
6920036252SHerbert Xu return hash_walk_next(walk);
7020036252SHerbert Xu }
7120036252SHerbert Xu
crypto_hash_walk_done(struct crypto_hash_walk * walk,int err)7220036252SHerbert Xu int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err)
7320036252SHerbert Xu {
7420036252SHerbert Xu unsigned int alignmask = walk->alignmask;
7520036252SHerbert Xu
7620036252SHerbert Xu walk->data -= walk->offset;
7720036252SHerbert Xu
7820036252SHerbert Xu if (walk->entrylen && (walk->offset & alignmask) && !err) {
7920036252SHerbert Xu unsigned int nbytes;
8020036252SHerbert Xu
8120036252SHerbert Xu walk->offset = ALIGN(walk->offset, alignmask + 1);
8220036252SHerbert Xu nbytes = min(walk->entrylen,
8320036252SHerbert Xu (unsigned int)(PAGE_SIZE - walk->offset));
8477568e53SEric Biggers if (nbytes) {
8577568e53SEric Biggers walk->entrylen -= nbytes;
8620036252SHerbert Xu walk->data += walk->offset;
8777568e53SEric Biggers return nbytes;
8877568e53SEric Biggers }
8977568e53SEric Biggers }
90900a081fSHerbert Xu
9177568e53SEric Biggers kunmap_local(walk->data);
92900a081fSHerbert Xu crypto_yield(walk->flags);
9320036252SHerbert Xu
9420036252SHerbert Xu if (err)
95900a081fSHerbert Xu return err;
9620036252SHerbert Xu
97aa969515SArd Biesheuvel if (walk->entrylen) {
9820036252SHerbert Xu walk->offset = 0;
9920036252SHerbert Xu walk->pg++;
10020036252SHerbert Xu return hash_walk_next(walk);
10120036252SHerbert Xu }
10220036252SHerbert Xu
10377568e53SEric Biggers if (!walk->total)
10420036252SHerbert Xu return 0;
105d315a0e0SHerbert Xu
10620036252SHerbert Xu walk->sg = sg_next(walk->sg);
107d315a0e0SHerbert Xu
10820036252SHerbert Xu return hash_walk_new_entry(walk);
10920036252SHerbert Xu }
11020036252SHerbert Xu EXPORT_SYMBOL_GPL(crypto_hash_walk_done);
11120036252SHerbert Xu
crypto_hash_walk_first(struct ahash_request * req,struct crypto_hash_walk * walk)1125be4d4c9SCristian Stoica int crypto_hash_walk_first(struct ahash_request *req,
11320036252SHerbert Xu struct crypto_hash_walk *walk)
11420036252SHerbert Xu {
11520036252SHerbert Xu walk->total = req->nbytes;
11620036252SHerbert Xu
11720036252SHerbert Xu if (!walk->total) {
11820036252SHerbert Xu walk->entrylen = 0;
11920036252SHerbert Xu return 0;
12020036252SHerbert Xu }
12120036252SHerbert Xu
12220036252SHerbert Xu walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req));
1236d9529c5STim Chen walk->sg = req->src;
1246d9529c5STim Chen walk->flags = req->base.flags;
12520036252SHerbert Xu
1266d9529c5STim Chen return hash_walk_new_entry(walk);
12720036252SHerbert Xu }
12820036252SHerbert Xu EXPORT_SYMBOL_GPL(crypto_hash_walk_first);
12920036252SHerbert Xu
ahash_setkey_unaligned(struct crypto_ahash * tfm,const u8 * key,unsigned int keylen)1308afa25aaSIra Weiny static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
13120036252SHerbert Xu unsigned int keylen)
13220036252SHerbert Xu {
13320036252SHerbert Xu unsigned long alignmask = crypto_ahash_alignmask(tfm);
13420036252SHerbert Xu int ret;
13520036252SHerbert Xu u8 *buffer, *alignbuffer;
136004a403cSLoc Ho unsigned long absize;
137004a403cSLoc Ho
138004a403cSLoc Ho absize = keylen + alignmask;
139004a403cSLoc Ho buffer = kmalloc(absize, GFP_KERNEL);
140004a403cSLoc Ho if (!buffer)
141004a403cSLoc Ho return -ENOMEM;
142004a403cSLoc Ho
143004a403cSLoc Ho alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
144004a403cSLoc Ho memcpy(alignbuffer, key, keylen);
145093900c2SHerbert Xu ret = tfm->setkey(tfm, alignbuffer, keylen);
146004a403cSLoc Ho kfree_sensitive(buffer);
147004a403cSLoc Ho return ret;
148004a403cSLoc Ho }
149004a403cSLoc Ho
ahash_nosetkey(struct crypto_ahash * tfm,const u8 * key,unsigned int keylen)150004a403cSLoc Ho static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key,
151a70c5225SHerbert Xu unsigned int keylen)
152453431a5SWaiman Long {
153004a403cSLoc Ho return -ENOSYS;
154004a403cSLoc Ho }
155004a403cSLoc Ho
ahash_set_needkey(struct crypto_ahash * tfm)156ba7d7433SEric Biggers static void ahash_set_needkey(struct crypto_ahash *tfm)
157ba7d7433SEric Biggers {
158ba7d7433SEric Biggers const struct hash_alg_common *alg = crypto_hash_alg_common(tfm);
159ba7d7433SEric Biggers
160ba7d7433SEric Biggers if (tfm->setkey != ahash_nosetkey &&
161ba7d7433SEric Biggers !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
162ba7d7433SEric Biggers crypto_ahash_set_flags(tfm, CRYPTO_TFM_NEED_KEY);
163ba7d7433SEric Biggers }
164ba7d7433SEric Biggers
crypto_ahash_setkey(struct crypto_ahash * tfm,const u8 * key,unsigned int keylen)165ba7d7433SEric Biggers int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
166ba7d7433SEric Biggers unsigned int keylen)
167ba7d7433SEric Biggers {
168ba7d7433SEric Biggers unsigned long alignmask = crypto_ahash_alignmask(tfm);
169ba7d7433SEric Biggers int err;
170ba7d7433SEric Biggers
17166f6ce5eSHerbert Xu if ((unsigned long)key & alignmask)
172004a403cSLoc Ho err = ahash_setkey_unaligned(tfm, key, keylen);
173004a403cSLoc Ho else
174004a403cSLoc Ho err = tfm->setkey(tfm, key, keylen);
1759fa68f62SEric Biggers
176004a403cSLoc Ho if (unlikely(err)) {
177004a403cSLoc Ho ahash_set_needkey(tfm);
1789fa68f62SEric Biggers return err;
1799fa68f62SEric Biggers }
1809fa68f62SEric Biggers
181004a403cSLoc Ho crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
182ba7d7433SEric Biggers return 0;
183ba7d7433SEric Biggers }
1849fa68f62SEric Biggers EXPORT_SYMBOL_GPL(crypto_ahash_setkey);
185ba7d7433SEric Biggers
ahash_save_req(struct ahash_request * req,crypto_completion_t cplt,bool has_state)1869fa68f62SEric Biggers static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt,
1879fa68f62SEric Biggers bool has_state)
1889fa68f62SEric Biggers {
189004a403cSLoc Ho struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
19066f6ce5eSHerbert Xu unsigned long alignmask = crypto_ahash_alignmask(tfm);
191004a403cSLoc Ho unsigned int ds = crypto_ahash_digestsize(tfm);
192d9588045SHerbert Xu struct ahash_request *subreq;
193d9588045SHerbert Xu unsigned int subreq_size;
19466f6ce5eSHerbert Xu unsigned int reqsize;
19566f6ce5eSHerbert Xu u8 *result;
19666f6ce5eSHerbert Xu gfp_t gfp;
19766f6ce5eSHerbert Xu u32 flags;
198d9588045SHerbert Xu
199d9588045SHerbert Xu subreq_size = sizeof(*subreq);
200d9588045SHerbert Xu reqsize = crypto_ahash_reqsize(tfm);
201d9588045SHerbert Xu reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment());
202d9588045SHerbert Xu subreq_size += reqsize;
203d9588045SHerbert Xu subreq_size += ds;
20466f6ce5eSHerbert Xu subreq_size += alignmask & ~(crypto_tfm_ctx_alignment() - 1);
205d9588045SHerbert Xu
206d9588045SHerbert Xu flags = ahash_request_flags(req);
207d9588045SHerbert Xu gfp = (flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC;
208d9588045SHerbert Xu subreq = kmalloc(subreq_size, gfp);
209d9588045SHerbert Xu if (!subreq)
210d9588045SHerbert Xu return -ENOMEM;
211d9588045SHerbert Xu
212d9588045SHerbert Xu ahash_request_set_tfm(subreq, tfm);
213d9588045SHerbert Xu ahash_request_set_callback(subreq, flags, cplt, req);
214d9588045SHerbert Xu
215d9588045SHerbert Xu result = (u8 *)(subreq + 1) + reqsize;
21666f6ce5eSHerbert Xu result = PTR_ALIGN(result, alignmask + 1);
21766f6ce5eSHerbert Xu
218d9588045SHerbert Xu ahash_request_set_crypt(subreq, req->src, result, req->nbytes);
219d9588045SHerbert Xu
220ab6bf4e5SMarek Vasut if (has_state) {
221d9588045SHerbert Xu void *state;
222d9588045SHerbert Xu
223ef0579b6SHerbert Xu state = kmalloc(crypto_ahash_statesize(tfm), gfp);
224d9588045SHerbert Xu if (!state) {
22566f6ce5eSHerbert Xu kfree(subreq);
226d9588045SHerbert Xu return -ENOMEM;
227d9588045SHerbert Xu }
228d9588045SHerbert Xu
229d9588045SHerbert Xu crypto_ahash_export(req, state);
230d9588045SHerbert Xu crypto_ahash_import(subreq, state);
231d9588045SHerbert Xu kfree_sensitive(state);
232d9588045SHerbert Xu }
233d9588045SHerbert Xu
234d9588045SHerbert Xu req->priv = subreq;
235d9588045SHerbert Xu
236d9588045SHerbert Xu return 0;
237d9588045SHerbert Xu }
238d9588045SHerbert Xu
ahash_restore_req(struct ahash_request * req,int err)239d9588045SHerbert Xu static void ahash_restore_req(struct ahash_request *req, int err)
240d9588045SHerbert Xu {
24166f6ce5eSHerbert Xu struct ahash_request *subreq = req->priv;
2421ffc9fbdSMarek Vasut
2431ffc9fbdSMarek Vasut if (!err)
2441ffc9fbdSMarek Vasut memcpy(req->result, subreq->result,
245ef0579b6SHerbert Xu crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
2461ffc9fbdSMarek Vasut
247d9588045SHerbert Xu req->priv = NULL;
2481ffc9fbdSMarek Vasut
249ef0579b6SHerbert Xu kfree_sensitive(subreq);
250d9588045SHerbert Xu }
251ef0579b6SHerbert Xu
ahash_op_unaligned_done(void * data,int err)252ef0579b6SHerbert Xu static void ahash_op_unaligned_done(void *data, int err)
2531ffc9fbdSMarek Vasut {
2541ffc9fbdSMarek Vasut struct ahash_request *areq = data;
255d9588045SHerbert Xu
2561ffc9fbdSMarek Vasut if (err == -EINPROGRESS)
2571ffc9fbdSMarek Vasut goto out;
258255e48ebSHerbert Xu
2591ffc9fbdSMarek Vasut /* First copy req->result into req->priv.result */
260255e48ebSHerbert Xu ahash_restore_req(areq, err);
2611ffc9fbdSMarek Vasut
262d9588045SHerbert Xu out:
263d9588045SHerbert Xu /* Complete the ORIGINAL request. */
2641ffc9fbdSMarek Vasut ahash_request_complete(areq, err);
2651ffc9fbdSMarek Vasut }
266ef0579b6SHerbert Xu
ahash_op_unaligned(struct ahash_request * req,int (* op)(struct ahash_request *),bool has_state)2671ffc9fbdSMarek Vasut static int ahash_op_unaligned(struct ahash_request *req,
268d9588045SHerbert Xu int (*op)(struct ahash_request *),
2691ffc9fbdSMarek Vasut bool has_state)
270d9588045SHerbert Xu {
2711ffc9fbdSMarek Vasut int err;
2721ffc9fbdSMarek Vasut
2731ffc9fbdSMarek Vasut err = ahash_save_req(req, ahash_op_unaligned_done, has_state);
274d9588045SHerbert Xu if (err)
275d9588045SHerbert Xu return err;
2761ffc9fbdSMarek Vasut
2771ffc9fbdSMarek Vasut err = op(req->priv);
2781ffc9fbdSMarek Vasut if (err == -EINPROGRESS || err == -EBUSY)
279d9588045SHerbert Xu return err;
2801ffc9fbdSMarek Vasut
2811ffc9fbdSMarek Vasut ahash_restore_req(req, err);
2821ffc9fbdSMarek Vasut
283d9588045SHerbert Xu return err;
2844e5b0ad5SGilad Ben-Yossef }
285ef0579b6SHerbert Xu
crypto_ahash_op(struct ahash_request * req,int (* op)(struct ahash_request *),bool has_state)286ef0579b6SHerbert Xu static int crypto_ahash_op(struct ahash_request *req,
287ef0579b6SHerbert Xu int (*op)(struct ahash_request *),
28866f6ce5eSHerbert Xu bool has_state)
28966f6ce5eSHerbert Xu {
29066f6ce5eSHerbert Xu struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
29166f6ce5eSHerbert Xu unsigned long alignmask = crypto_ahash_alignmask(tfm);
29266f6ce5eSHerbert Xu int err;
293d9588045SHerbert Xu
294d9588045SHerbert Xu if ((unsigned long)req->result & alignmask)
29566f6ce5eSHerbert Xu err = ahash_op_unaligned(req, op, has_state);
29666f6ce5eSHerbert Xu else
29766f6ce5eSHerbert Xu err = op(req);
29842808e5dSHerbert Xu
29966f6ce5eSHerbert Xu return crypto_hash_errstat(crypto_hash_alg_common(tfm), err);
30066f6ce5eSHerbert Xu }
30142808e5dSHerbert Xu
crypto_ahash_final(struct ahash_request * req)30242808e5dSHerbert Xu int crypto_ahash_final(struct ahash_request *req)
30342808e5dSHerbert Xu {
30466f6ce5eSHerbert Xu struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
30542808e5dSHerbert Xu struct hash_alg_common *alg = crypto_hash_alg_common(tfm);
30666f6ce5eSHerbert Xu
30766f6ce5eSHerbert Xu if (IS_ENABLED(CONFIG_CRYPTO_STATS))
30866f6ce5eSHerbert Xu atomic64_inc(&hash_get_stat(alg)->hash_cnt);
30966f6ce5eSHerbert Xu
310f7d76e05SCorentin Labbe return crypto_ahash_op(req, tfm->final, true);
31142808e5dSHerbert Xu }
312cac5818cSCorentin Labbe EXPORT_SYMBOL_GPL(crypto_ahash_final);
31342808e5dSHerbert Xu
crypto_ahash_finup(struct ahash_request * req)31442808e5dSHerbert Xu int crypto_ahash_finup(struct ahash_request *req)
31542808e5dSHerbert Xu {
31642808e5dSHerbert Xu struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
31766f6ce5eSHerbert Xu struct hash_alg_common *alg = crypto_hash_alg_common(tfm);
31866f6ce5eSHerbert Xu
31966f6ce5eSHerbert Xu if (IS_ENABLED(CONFIG_CRYPTO_STATS)) {
32066f6ce5eSHerbert Xu struct crypto_istat_hash *istat = hash_get_stat(alg);
32166f6ce5eSHerbert Xu
322f7d76e05SCorentin Labbe atomic64_inc(&istat->hash_cnt);
32342808e5dSHerbert Xu atomic64_add(req->nbytes, &istat->hash_tlen);
324cac5818cSCorentin Labbe }
32542808e5dSHerbert Xu
32642808e5dSHerbert Xu return crypto_ahash_op(req, tfm->finup, true);
32742808e5dSHerbert Xu }
32842808e5dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_ahash_finup);
32942808e5dSHerbert Xu
crypto_ahash_digest(struct ahash_request * req)33042808e5dSHerbert Xu int crypto_ahash_digest(struct ahash_request *req)
33142808e5dSHerbert Xu {
33242808e5dSHerbert Xu struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
33366f6ce5eSHerbert Xu struct hash_alg_common *alg = crypto_hash_alg_common(tfm);
33466f6ce5eSHerbert Xu
33566f6ce5eSHerbert Xu if (IS_ENABLED(CONFIG_CRYPTO_STATS)) {
33666f6ce5eSHerbert Xu struct crypto_istat_hash *istat = hash_get_stat(alg);
33766f6ce5eSHerbert Xu
3389fa68f62SEric Biggers atomic64_inc(&istat->hash_cnt);
33942808e5dSHerbert Xu atomic64_add(req->nbytes, &istat->hash_tlen);
3409fa68f62SEric Biggers }
34142808e5dSHerbert Xu
34242808e5dSHerbert Xu if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
34342808e5dSHerbert Xu return crypto_hash_errstat(alg, -ENOKEY);
34442808e5dSHerbert Xu
34542808e5dSHerbert Xu return crypto_ahash_op(req, tfm->digest, false);
34642808e5dSHerbert Xu }
34742808e5dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_ahash_digest);
3489fa68f62SEric Biggers
ahash_def_finup_done2(void * data,int err)34942808e5dSHerbert Xu static void ahash_def_finup_done2(void *data, int err)
35042808e5dSHerbert Xu {
35142808e5dSHerbert Xu struct ahash_request *areq = data;
35266f6ce5eSHerbert Xu
35366f6ce5eSHerbert Xu if (err == -EINPROGRESS)
35466f6ce5eSHerbert Xu return;
355255e48ebSHerbert Xu
35666f6ce5eSHerbert Xu ahash_restore_req(areq, err);
357255e48ebSHerbert Xu
35866f6ce5eSHerbert Xu ahash_request_complete(areq, err);
359ef0579b6SHerbert Xu }
360ef0579b6SHerbert Xu
ahash_def_finup_finish1(struct ahash_request * req,int err)361ef0579b6SHerbert Xu static int ahash_def_finup_finish1(struct ahash_request *req, int err)
362ef0579b6SHerbert Xu {
36366f6ce5eSHerbert Xu struct ahash_request *subreq = req->priv;
364d9588045SHerbert Xu
36566f6ce5eSHerbert Xu if (err)
36666f6ce5eSHerbert Xu goto out;
36766f6ce5eSHerbert Xu
36866f6ce5eSHerbert Xu subreq->base.complete = ahash_def_finup_done2;
369d9588045SHerbert Xu
370d9588045SHerbert Xu err = crypto_ahash_reqtfm(req)->final(subreq);
37166f6ce5eSHerbert Xu if (err == -EINPROGRESS || err == -EBUSY)
37266f6ce5eSHerbert Xu return err;
37366f6ce5eSHerbert Xu
374d9588045SHerbert Xu out:
375ef0579b6SHerbert Xu ahash_restore_req(req, err);
376d9588045SHerbert Xu return err;
3774e5b0ad5SGilad Ben-Yossef }
378ef0579b6SHerbert Xu
ahash_def_finup_done1(void * data,int err)37966f6ce5eSHerbert Xu static void ahash_def_finup_done1(void *data, int err)
38066f6ce5eSHerbert Xu {
381ef0579b6SHerbert Xu struct ahash_request *areq = data;
38266f6ce5eSHerbert Xu struct ahash_request *subreq;
38366f6ce5eSHerbert Xu
38466f6ce5eSHerbert Xu if (err == -EINPROGRESS)
385255e48ebSHerbert Xu goto out;
38666f6ce5eSHerbert Xu
387255e48ebSHerbert Xu subreq = areq->priv;
388d9588045SHerbert Xu subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;
38966f6ce5eSHerbert Xu
390d9588045SHerbert Xu err = ahash_def_finup_finish1(areq, err);
391d9588045SHerbert Xu if (err == -EINPROGRESS || err == -EBUSY)
392ef0579b6SHerbert Xu return;
393d9588045SHerbert Xu
394d9588045SHerbert Xu out:
395ef0579b6SHerbert Xu ahash_request_complete(areq, err);
39666f6ce5eSHerbert Xu }
397d9588045SHerbert Xu
ahash_def_finup(struct ahash_request * req)398ef0579b6SHerbert Xu static int ahash_def_finup(struct ahash_request *req)
39966f6ce5eSHerbert Xu {
400d9588045SHerbert Xu struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
401d9588045SHerbert Xu int err;
40266f6ce5eSHerbert Xu
40366f6ce5eSHerbert Xu err = ahash_save_req(req, ahash_def_finup_done1, true);
40466f6ce5eSHerbert Xu if (err)
40566f6ce5eSHerbert Xu return err;
40666f6ce5eSHerbert Xu
407d4a7a0fbSMarek Vasut err = tfm->update(req->priv);
40866f6ce5eSHerbert Xu if (err == -EINPROGRESS || err == -EBUSY)
409d9588045SHerbert Xu return err;
410d4a7a0fbSMarek Vasut
411d4a7a0fbSMarek Vasut return ahash_def_finup_finish1(req, err);
41266f6ce5eSHerbert Xu }
413d9588045SHerbert Xu
crypto_ahash_exit_tfm(struct crypto_tfm * tfm)4144e5b0ad5SGilad Ben-Yossef static void crypto_ahash_exit_tfm(struct crypto_tfm *tfm)
415ef0579b6SHerbert Xu {
416ef0579b6SHerbert Xu struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
417d4a7a0fbSMarek Vasut struct ahash_alg *alg = crypto_ahash_alg(hash);
41866f6ce5eSHerbert Xu
41966f6ce5eSHerbert Xu alg->exit_tfm(hash);
420e73d340dSHerbert Xu }
421e73d340dSHerbert Xu
crypto_ahash_init_tfm(struct crypto_tfm * tfm)422e73d340dSHerbert Xu static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
423e73d340dSHerbert Xu {
424e73d340dSHerbert Xu struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
425e73d340dSHerbert Xu struct ahash_alg *alg = crypto_ahash_alg(hash);
426e73d340dSHerbert Xu
427e73d340dSHerbert Xu hash->setkey = ahash_nosetkey;
42888056ec3SHerbert Xu
42988056ec3SHerbert Xu crypto_ahash_set_statesize(hash, alg->halg.statesize);
43088056ec3SHerbert Xu
43188056ec3SHerbert Xu if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
43288056ec3SHerbert Xu return crypto_init_shash_ops_async(tfm);
43366f6ce5eSHerbert Xu
43466f6ce5eSHerbert Xu hash->init = alg->init;
43588056ec3SHerbert Xu hash->update = alg->update;
43688056ec3SHerbert Xu hash->final = alg->final;
43788056ec3SHerbert Xu hash->finup = alg->finup ?: ahash_def_finup;
43888056ec3SHerbert Xu hash->digest = alg->digest;
43988056ec3SHerbert Xu hash->export = alg->export;
44088056ec3SHerbert Xu hash->import = alg->import;
44166f6ce5eSHerbert Xu
44288056ec3SHerbert Xu if (alg->setkey) {
4436f221f7eSKamil Konieczny hash->setkey = alg->setkey;
4446f221f7eSKamil Konieczny ahash_set_needkey(hash);
44566f6ce5eSHerbert Xu }
446a5596d63SHerbert Xu
44766f6ce5eSHerbert Xu if (alg->exit_tfm)
448ba7d7433SEric Biggers tfm->exit = crypto_ahash_exit_tfm;
449a5596d63SHerbert Xu
45088056ec3SHerbert Xu return alg->init_tfm ? alg->init_tfm(hash) : 0;
451e73d340dSHerbert Xu }
452e73d340dSHerbert Xu
crypto_ahash_extsize(struct crypto_alg * alg)453e73d340dSHerbert Xu static unsigned int crypto_ahash_extsize(struct crypto_alg *alg)
454e73d340dSHerbert Xu {
45588056ec3SHerbert Xu if (alg->cra_type != &crypto_ahash_type)
45688056ec3SHerbert Xu return sizeof(struct crypto_shash *);
45788056ec3SHerbert Xu
45888056ec3SHerbert Xu return crypto_alg_extsize(alg);
4592495cf25SHerbert Xu }
46088056ec3SHerbert Xu
crypto_ahash_free_instance(struct crypto_instance * inst)4612495cf25SHerbert Xu static void crypto_ahash_free_instance(struct crypto_instance *inst)
4622495cf25SHerbert Xu {
46388056ec3SHerbert Xu struct ahash_instance *ahash = ahash_instance(inst);
46488056ec3SHerbert Xu
46548fb3e57SEric Biggers ahash->free(ahash);
46648fb3e57SEric Biggers }
46748fb3e57SEric Biggers
crypto_ahash_report(struct sk_buff * skb,struct crypto_alg * alg)46848fb3e57SEric Biggers static int __maybe_unused crypto_ahash_report(
46948fb3e57SEric Biggers struct sk_buff *skb, struct crypto_alg *alg)
47048fb3e57SEric Biggers {
47148fb3e57SEric Biggers struct crypto_report_hash rhash;
472c0f9e01dSHerbert Xu
473c0f9e01dSHerbert Xu memset(&rhash, 0, sizeof(rhash));
4746238cbaeSSteffen Klassert
4756238cbaeSSteffen Klassert strscpy(rhash.type, "ahash", sizeof(rhash.type));
4766238cbaeSSteffen Klassert
47737db69e0SEric Biggers rhash.blocksize = alg->cra_blocksize;
47837db69e0SEric Biggers rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize;
47937db69e0SEric Biggers
4806238cbaeSSteffen Klassert return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash);
4816238cbaeSSteffen Klassert }
4826238cbaeSSteffen Klassert
4836238cbaeSSteffen Klassert static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
48437db69e0SEric Biggers __maybe_unused;
crypto_ahash_show(struct seq_file * m,struct crypto_alg * alg)4856238cbaeSSteffen Klassert static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
4866238cbaeSSteffen Klassert {
487004a403cSLoc Ho seq_printf(m, "type : ahash\n");
488d8c34b94SGideon Israel Dsouza seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
489004a403cSLoc Ho "yes" : "no");
490004a403cSLoc Ho seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
491004a403cSLoc Ho seq_printf(m, "digestsize : %u\n",
492004a403cSLoc Ho __crypto_hash_alg_common(alg)->digestsize);
493004a403cSLoc Ho }
494004a403cSLoc Ho
crypto_ahash_report_stat(struct sk_buff * skb,struct crypto_alg * alg)49588056ec3SHerbert Xu static int __maybe_unused crypto_ahash_report_stat(
49688056ec3SHerbert Xu struct sk_buff *skb, struct crypto_alg *alg)
497004a403cSLoc Ho {
498004a403cSLoc Ho return crypto_hash_report_stat(skb, alg, "ahash");
49942808e5dSHerbert Xu }
50042808e5dSHerbert Xu
50142808e5dSHerbert Xu static const struct crypto_type crypto_ahash_type = {
50242808e5dSHerbert Xu .extsize = crypto_ahash_extsize,
50342808e5dSHerbert Xu .init_tfm = crypto_ahash_init_tfm,
50442808e5dSHerbert Xu .free = crypto_ahash_free_instance,
5056d1b41fcSEric Biggers #ifdef CONFIG_PROC_FS
50688056ec3SHerbert Xu .show = crypto_ahash_show,
50788056ec3SHerbert Xu #endif
50848fb3e57SEric Biggers #if IS_ENABLED(CONFIG_CRYPTO_USER)
509004a403cSLoc Ho .report = crypto_ahash_report,
510004a403cSLoc Ho #endif
511004a403cSLoc Ho #ifdef CONFIG_CRYPTO_STATS
512*b8969a1bSOndrej Mosnacek .report_stat = crypto_ahash_report_stat,
5136238cbaeSSteffen Klassert #endif
514c0f9e01dSHerbert Xu .maskclear = ~CRYPTO_ALG_TYPE_MASK,
51542808e5dSHerbert Xu .maskset = CRYPTO_ALG_TYPE_AHASH_MASK,
51642808e5dSHerbert Xu .type = CRYPTO_ALG_TYPE_AHASH,
51742808e5dSHerbert Xu .tfmsize = offsetof(struct crypto_ahash, base),
51888056ec3SHerbert Xu };
51988056ec3SHerbert Xu
crypto_grab_ahash(struct crypto_ahash_spawn * spawn,struct crypto_instance * inst,const char * name,u32 type,u32 mask)52088056ec3SHerbert Xu int crypto_grab_ahash(struct crypto_ahash_spawn *spawn,
52188056ec3SHerbert Xu struct crypto_instance *inst,
522004a403cSLoc Ho const char *name, u32 type, u32 mask)
523004a403cSLoc Ho {
52484a9c938SEric Biggers spawn->base.frontend = &crypto_ahash_type;
52584a9c938SEric Biggers return crypto_grab_spawn(&spawn->base, inst, name, type, mask);
52684a9c938SEric Biggers }
52784a9c938SEric Biggers EXPORT_SYMBOL_GPL(crypto_grab_ahash);
52884a9c938SEric Biggers
crypto_alloc_ahash(const char * alg_name,u32 type,u32 mask)52984a9c938SEric Biggers struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type,
53084a9c938SEric Biggers u32 mask)
53184a9c938SEric Biggers {
53284a9c938SEric Biggers return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask);
53388056ec3SHerbert Xu }
53488056ec3SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alloc_ahash);
53588056ec3SHerbert Xu
crypto_has_ahash(const char * alg_name,u32 type,u32 mask)53688056ec3SHerbert Xu int crypto_has_ahash(const char *alg_name, u32 type, u32 mask)
53788056ec3SHerbert Xu {
53888056ec3SHerbert Xu return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask);
53988056ec3SHerbert Xu }
5408d18e34cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_has_ahash);
5418d18e34cSHerbert Xu
crypto_clone_ahash(struct crypto_ahash * hash)5428d18e34cSHerbert Xu struct crypto_ahash *crypto_clone_ahash(struct crypto_ahash *hash)
5438d18e34cSHerbert Xu {
5448d18e34cSHerbert Xu struct hash_alg_common *halg = crypto_hash_alg_common(hash);
5458d18e34cSHerbert Xu struct crypto_tfm *tfm = crypto_ahash_tfm(hash);
546ed3630b8SHerbert Xu struct crypto_ahash *nhash;
547ed3630b8SHerbert Xu struct ahash_alg *alg;
548ed3630b8SHerbert Xu int err;
549ed3630b8SHerbert Xu
550ed3630b8SHerbert Xu if (!crypto_hash_alg_has_setkey(halg)) {
551ed3630b8SHerbert Xu tfm = crypto_tfm_get(tfm);
552ed3630b8SHerbert Xu if (IS_ERR(tfm))
553ed3630b8SHerbert Xu return ERR_CAST(tfm);
554ed3630b8SHerbert Xu
555ed3630b8SHerbert Xu return hash;
556ed3630b8SHerbert Xu }
557ed3630b8SHerbert Xu
558ed3630b8SHerbert Xu nhash = crypto_clone_tfm(&crypto_ahash_type, tfm);
559ed3630b8SHerbert Xu
560ed3630b8SHerbert Xu if (IS_ERR(nhash))
561ed3630b8SHerbert Xu return nhash;
562ed3630b8SHerbert Xu
563ed3630b8SHerbert Xu nhash->init = hash->init;
564ed3630b8SHerbert Xu nhash->update = hash->update;
565ed3630b8SHerbert Xu nhash->final = hash->final;
566ed3630b8SHerbert Xu nhash->finup = hash->finup;
567ed3630b8SHerbert Xu nhash->digest = hash->digest;
568ed3630b8SHerbert Xu nhash->export = hash->export;
569ed3630b8SHerbert Xu nhash->import = hash->import;
570ed3630b8SHerbert Xu nhash->setkey = hash->setkey;
571ed3630b8SHerbert Xu nhash->reqsize = hash->reqsize;
572ed3630b8SHerbert Xu nhash->statesize = hash->statesize;
573ed3630b8SHerbert Xu
574ed3630b8SHerbert Xu if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
575ed3630b8SHerbert Xu return crypto_clone_shash_ops_async(nhash, hash);
576ed3630b8SHerbert Xu
577ed3630b8SHerbert Xu err = -ENOSYS;
578ed3630b8SHerbert Xu alg = crypto_ahash_alg(hash);
579ed3630b8SHerbert Xu if (!alg->clone_tfm)
580ed3630b8SHerbert Xu goto out_free_nhash;
581ed3630b8SHerbert Xu
582ed3630b8SHerbert Xu err = alg->clone_tfm(nhash, hash);
583ed3630b8SHerbert Xu if (err)
584ed3630b8SHerbert Xu goto out_free_nhash;
585ed3630b8SHerbert Xu
586ed3630b8SHerbert Xu return nhash;
587ed3630b8SHerbert Xu
588ed3630b8SHerbert Xu out_free_nhash:
589ed3630b8SHerbert Xu crypto_free_ahash(nhash);
590ed3630b8SHerbert Xu return ERR_PTR(err);
591ed3630b8SHerbert Xu }
592ed3630b8SHerbert Xu EXPORT_SYMBOL_GPL(crypto_clone_ahash);
593ed3630b8SHerbert Xu
ahash_prepare_alg(struct ahash_alg * alg)594ed3630b8SHerbert Xu static int ahash_prepare_alg(struct ahash_alg *alg)
595ed3630b8SHerbert Xu {
596ed3630b8SHerbert Xu struct crypto_alg *base = &alg->halg.base;
59701c2deceSHerbert Xu int err;
59801c2deceSHerbert Xu
59901c2deceSHerbert Xu if (alg->halg.statesize == 0)
60042808e5dSHerbert Xu return -EINVAL;
60101c2deceSHerbert Xu
60242808e5dSHerbert Xu err = hash_prepare_alg(&alg->halg);
60301c2deceSHerbert Xu if (err)
60401c2deceSHerbert Xu return err;
60542808e5dSHerbert Xu
60642808e5dSHerbert Xu base->cra_type = &crypto_ahash_type;
60742808e5dSHerbert Xu base->cra_flags |= CRYPTO_ALG_TYPE_AHASH;
60842808e5dSHerbert Xu
60901c2deceSHerbert Xu return 0;
61001c2deceSHerbert Xu }
61101c2deceSHerbert Xu
crypto_register_ahash(struct ahash_alg * alg)61201c2deceSHerbert Xu int crypto_register_ahash(struct ahash_alg *alg)
61301c2deceSHerbert Xu {
61401c2deceSHerbert Xu struct crypto_alg *base = &alg->halg.base;
61501c2deceSHerbert Xu int err;
61601c2deceSHerbert Xu
61701c2deceSHerbert Xu err = ahash_prepare_alg(alg);
61801c2deceSHerbert Xu if (err)
61901c2deceSHerbert Xu return err;
62001c2deceSHerbert Xu
62101c2deceSHerbert Xu return crypto_register_alg(base);
62201c2deceSHerbert Xu }
62301c2deceSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_ahash);
62401c2deceSHerbert Xu
crypto_unregister_ahash(struct ahash_alg * alg)62501c2deceSHerbert Xu void crypto_unregister_ahash(struct ahash_alg *alg)
62601c2deceSHerbert Xu {
62701c2deceSHerbert Xu crypto_unregister_alg(&alg->halg.base);
628c6d633a9SEric Biggers }
62901c2deceSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_ahash);
630c6d633a9SEric Biggers
crypto_register_ahashes(struct ahash_alg * algs,int count)63101c2deceSHerbert Xu int crypto_register_ahashes(struct ahash_alg *algs, int count)
63201c2deceSHerbert Xu {
63301c2deceSHerbert Xu int i, ret;
6346f7473c5SRabin Vincent
6356f7473c5SRabin Vincent for (i = 0; i < count; i++) {
6366f7473c5SRabin Vincent ret = crypto_register_ahash(&algs[i]);
6376f7473c5SRabin Vincent if (ret)
6386f7473c5SRabin Vincent goto err;
6396f7473c5SRabin Vincent }
6406f7473c5SRabin Vincent
6416f7473c5SRabin Vincent return 0;
6426f7473c5SRabin Vincent
6436f7473c5SRabin Vincent err:
6446f7473c5SRabin Vincent for (--i; i >= 0; --i)
6456f7473c5SRabin Vincent crypto_unregister_ahash(&algs[i]);
6466f7473c5SRabin Vincent
6476f7473c5SRabin Vincent return ret;
6486f7473c5SRabin Vincent }
6496f7473c5SRabin Vincent EXPORT_SYMBOL_GPL(crypto_register_ahashes);
6506f7473c5SRabin Vincent
crypto_unregister_ahashes(struct ahash_alg * algs,int count)6516f7473c5SRabin Vincent void crypto_unregister_ahashes(struct ahash_alg *algs, int count)
6526f7473c5SRabin Vincent {
6536f7473c5SRabin Vincent int i;
6546f7473c5SRabin Vincent
6556f7473c5SRabin Vincent for (i = count - 1; i >= 0; --i)
6566f7473c5SRabin Vincent crypto_unregister_ahash(&algs[i]);
6576f7473c5SRabin Vincent }
6586f7473c5SRabin Vincent EXPORT_SYMBOL_GPL(crypto_unregister_ahashes);
6596f7473c5SRabin Vincent
ahash_register_instance(struct crypto_template * tmpl,struct ahash_instance * inst)6606f7473c5SRabin Vincent int ahash_register_instance(struct crypto_template *tmpl,
6616f7473c5SRabin Vincent struct ahash_instance *inst)
6626f7473c5SRabin Vincent {
66301c2deceSHerbert Xu int err;
66401c2deceSHerbert Xu
66501c2deceSHerbert Xu if (WARN_ON(!inst->free))
66601c2deceSHerbert Xu return -EINVAL;
66701c2deceSHerbert Xu
668d4fdc2dfSEric Biggers err = ahash_prepare_alg(&inst->alg);
669d4fdc2dfSEric Biggers if (err)
670d4fdc2dfSEric Biggers return err;
67101c2deceSHerbert Xu
67201c2deceSHerbert Xu return crypto_register_instance(tmpl, ahash_crypto_instance(inst));
67301c2deceSHerbert Xu }
67401c2deceSHerbert Xu EXPORT_SYMBOL_GPL(ahash_register_instance);
67501c2deceSHerbert Xu
crypto_hash_alg_has_setkey(struct hash_alg_common * halg)67601c2deceSHerbert Xu bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
67701c2deceSHerbert Xu {
67801c2deceSHerbert Xu struct crypto_alg *alg = &halg->base;
679cd6ed77aSEric Biggers
680cd6ed77aSEric Biggers if (alg->cra_type != &crypto_ahash_type)
681cd6ed77aSEric Biggers return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
682cd6ed77aSEric Biggers
683cd6ed77aSEric Biggers return __crypto_ahash_alg(alg)->setkey != NULL;
684cd6ed77aSEric Biggers }
685cd6ed77aSEric Biggers EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
686cd6ed77aSEric Biggers
687cd6ed77aSEric Biggers MODULE_LICENSE("GPL");
688cd6ed77aSEric Biggers MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
689cd6ed77aSEric Biggers