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 3488056ec3SHerbert Xu static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) 3588056ec3SHerbert Xu { 3688056ec3SHerbert Xu return container_of(crypto_hash_alg_common(hash), struct ahash_alg, 3788056ec3SHerbert Xu halg); 3888056ec3SHerbert Xu } 3988056ec3SHerbert Xu 4020036252SHerbert Xu static int hash_walk_next(struct crypto_hash_walk *walk) 4120036252SHerbert Xu { 4220036252SHerbert Xu unsigned int alignmask = walk->alignmask; 4320036252SHerbert Xu unsigned int offset = walk->offset; 4420036252SHerbert Xu unsigned int nbytes = min(walk->entrylen, 4520036252SHerbert Xu ((unsigned int)(PAGE_SIZE)) - offset); 4620036252SHerbert Xu 47aa969515SArd Biesheuvel walk->data = kmap_local_page(walk->pg); 4820036252SHerbert Xu walk->data += offset; 4920036252SHerbert Xu 5023a75eeeSSzilveszter Ördög if (offset & alignmask) { 5123a75eeeSSzilveszter Ördög unsigned int unaligned = alignmask + 1 - (offset & alignmask); 52b516d514SJoshua I. James 5323a75eeeSSzilveszter Ördög if (nbytes > unaligned) 5423a75eeeSSzilveszter Ördög nbytes = unaligned; 5523a75eeeSSzilveszter Ördög } 5620036252SHerbert Xu 5720036252SHerbert Xu walk->entrylen -= nbytes; 5820036252SHerbert Xu return nbytes; 5920036252SHerbert Xu } 6020036252SHerbert Xu 6120036252SHerbert Xu static int hash_walk_new_entry(struct crypto_hash_walk *walk) 6220036252SHerbert Xu { 6320036252SHerbert Xu struct scatterlist *sg; 6420036252SHerbert Xu 6520036252SHerbert Xu sg = walk->sg; 6620036252SHerbert Xu walk->offset = sg->offset; 6713f4bb78SHerbert Xu walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT); 6813f4bb78SHerbert Xu walk->offset = offset_in_page(walk->offset); 6920036252SHerbert Xu walk->entrylen = sg->length; 7020036252SHerbert Xu 7120036252SHerbert Xu if (walk->entrylen > walk->total) 7220036252SHerbert Xu walk->entrylen = walk->total; 7320036252SHerbert Xu walk->total -= walk->entrylen; 7420036252SHerbert Xu 7520036252SHerbert Xu return hash_walk_next(walk); 7620036252SHerbert Xu } 7720036252SHerbert Xu 7820036252SHerbert Xu int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) 7920036252SHerbert Xu { 8020036252SHerbert Xu unsigned int alignmask = walk->alignmask; 8120036252SHerbert Xu 8220036252SHerbert Xu walk->data -= walk->offset; 8320036252SHerbert Xu 8477568e53SEric Biggers if (walk->entrylen && (walk->offset & alignmask) && !err) { 8577568e53SEric Biggers unsigned int nbytes; 8620036252SHerbert Xu 8777568e53SEric Biggers walk->offset = ALIGN(walk->offset, alignmask + 1); 8877568e53SEric Biggers nbytes = min(walk->entrylen, 8977568e53SEric Biggers (unsigned int)(PAGE_SIZE - walk->offset)); 90900a081fSHerbert Xu if (nbytes) { 9177568e53SEric Biggers walk->entrylen -= nbytes; 92900a081fSHerbert Xu walk->data += walk->offset; 9320036252SHerbert Xu return nbytes; 9420036252SHerbert Xu } 95900a081fSHerbert Xu } 9620036252SHerbert Xu 97aa969515SArd Biesheuvel kunmap_local(walk->data); 9820036252SHerbert Xu crypto_yield(walk->flags); 9920036252SHerbert Xu 10020036252SHerbert Xu if (err) 10120036252SHerbert Xu return err; 10220036252SHerbert Xu 10377568e53SEric Biggers if (walk->entrylen) { 10420036252SHerbert Xu walk->offset = 0; 105d315a0e0SHerbert Xu walk->pg++; 10620036252SHerbert Xu return hash_walk_next(walk); 107d315a0e0SHerbert Xu } 10820036252SHerbert Xu 10920036252SHerbert Xu if (!walk->total) 11020036252SHerbert Xu return 0; 11120036252SHerbert Xu 1125be4d4c9SCristian Stoica walk->sg = sg_next(walk->sg); 11320036252SHerbert Xu 11420036252SHerbert Xu return hash_walk_new_entry(walk); 11520036252SHerbert Xu } 11620036252SHerbert Xu EXPORT_SYMBOL_GPL(crypto_hash_walk_done); 11720036252SHerbert Xu 11820036252SHerbert Xu int crypto_hash_walk_first(struct ahash_request *req, 11920036252SHerbert Xu struct crypto_hash_walk *walk) 12020036252SHerbert Xu { 12120036252SHerbert Xu walk->total = req->nbytes; 12220036252SHerbert Xu 1236d9529c5STim Chen if (!walk->total) { 1246d9529c5STim Chen walk->entrylen = 0; 12520036252SHerbert Xu return 0; 1266d9529c5STim Chen } 12720036252SHerbert Xu 12820036252SHerbert Xu walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req)); 12920036252SHerbert Xu walk->sg = req->src; 1308afa25aaSIra Weiny walk->flags = req->base.flags; 13120036252SHerbert Xu 13220036252SHerbert Xu return hash_walk_new_entry(walk); 13320036252SHerbert Xu } 13420036252SHerbert Xu EXPORT_SYMBOL_GPL(crypto_hash_walk_first); 13520036252SHerbert Xu 136004a403cSLoc Ho static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, 137004a403cSLoc Ho unsigned int keylen) 138004a403cSLoc Ho { 139004a403cSLoc Ho unsigned long alignmask = crypto_ahash_alignmask(tfm); 140004a403cSLoc Ho int ret; 141004a403cSLoc Ho u8 *buffer, *alignbuffer; 142004a403cSLoc Ho unsigned long absize; 143004a403cSLoc Ho 144004a403cSLoc Ho absize = keylen + alignmask; 145093900c2SHerbert Xu buffer = kmalloc(absize, GFP_KERNEL); 146004a403cSLoc Ho if (!buffer) 147004a403cSLoc Ho return -ENOMEM; 148004a403cSLoc Ho 149004a403cSLoc Ho alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 150004a403cSLoc Ho memcpy(alignbuffer, key, keylen); 151a70c5225SHerbert Xu ret = tfm->setkey(tfm, alignbuffer, keylen); 152453431a5SWaiman Long kfree_sensitive(buffer); 153004a403cSLoc Ho return ret; 154004a403cSLoc Ho } 155004a403cSLoc Ho 156ba7d7433SEric Biggers static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, 157ba7d7433SEric Biggers unsigned int keylen) 158ba7d7433SEric Biggers { 159ba7d7433SEric Biggers return -ENOSYS; 160ba7d7433SEric Biggers } 161ba7d7433SEric Biggers 162ba7d7433SEric Biggers static void ahash_set_needkey(struct crypto_ahash *tfm) 163ba7d7433SEric Biggers { 164ba7d7433SEric Biggers const struct hash_alg_common *alg = crypto_hash_alg_common(tfm); 165ba7d7433SEric Biggers 166ba7d7433SEric Biggers if (tfm->setkey != ahash_nosetkey && 167ba7d7433SEric Biggers !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) 168ba7d7433SEric Biggers crypto_ahash_set_flags(tfm, CRYPTO_TFM_NEED_KEY); 169ba7d7433SEric Biggers } 170ba7d7433SEric Biggers 17166f6ce5eSHerbert Xu int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, 172004a403cSLoc Ho unsigned int keylen) 173004a403cSLoc Ho { 174004a403cSLoc Ho unsigned long alignmask = crypto_ahash_alignmask(tfm); 1759fa68f62SEric Biggers int err; 176004a403cSLoc Ho 177004a403cSLoc Ho if ((unsigned long)key & alignmask) 1789fa68f62SEric Biggers err = ahash_setkey_unaligned(tfm, key, keylen); 1799fa68f62SEric Biggers else 1809fa68f62SEric Biggers err = tfm->setkey(tfm, key, keylen); 181004a403cSLoc Ho 182ba7d7433SEric Biggers if (unlikely(err)) { 183ba7d7433SEric Biggers ahash_set_needkey(tfm); 1849fa68f62SEric Biggers return err; 185ba7d7433SEric Biggers } 1869fa68f62SEric Biggers 1879fa68f62SEric Biggers crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); 1889fa68f62SEric Biggers return 0; 189004a403cSLoc Ho } 19066f6ce5eSHerbert Xu EXPORT_SYMBOL_GPL(crypto_ahash_setkey); 191004a403cSLoc Ho 192d9588045SHerbert Xu static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt, 193d9588045SHerbert Xu bool has_state) 19466f6ce5eSHerbert Xu { 19566f6ce5eSHerbert Xu struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 19666f6ce5eSHerbert Xu unsigned long alignmask = crypto_ahash_alignmask(tfm); 19766f6ce5eSHerbert Xu unsigned int ds = crypto_ahash_digestsize(tfm); 198d9588045SHerbert Xu struct ahash_request *subreq; 199d9588045SHerbert Xu unsigned int subreq_size; 200d9588045SHerbert Xu unsigned int reqsize; 201d9588045SHerbert Xu u8 *result; 202d9588045SHerbert Xu gfp_t gfp; 203d9588045SHerbert Xu u32 flags; 20466f6ce5eSHerbert Xu 205d9588045SHerbert Xu subreq_size = sizeof(*subreq); 206d9588045SHerbert Xu reqsize = crypto_ahash_reqsize(tfm); 207d9588045SHerbert Xu reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment()); 208d9588045SHerbert Xu subreq_size += reqsize; 209d9588045SHerbert Xu subreq_size += ds; 210d9588045SHerbert Xu subreq_size += alignmask & ~(crypto_tfm_ctx_alignment() - 1); 211d9588045SHerbert Xu 212d9588045SHerbert Xu flags = ahash_request_flags(req); 213d9588045SHerbert Xu gfp = (flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; 214d9588045SHerbert Xu subreq = kmalloc(subreq_size, gfp); 215d9588045SHerbert Xu if (!subreq) 21666f6ce5eSHerbert Xu return -ENOMEM; 21766f6ce5eSHerbert Xu 218d9588045SHerbert Xu ahash_request_set_tfm(subreq, tfm); 219d9588045SHerbert Xu ahash_request_set_callback(subreq, flags, cplt, req); 220ab6bf4e5SMarek Vasut 221d9588045SHerbert Xu result = (u8 *)(subreq + 1) + reqsize; 222d9588045SHerbert Xu result = PTR_ALIGN(result, alignmask + 1); 223ef0579b6SHerbert Xu 224d9588045SHerbert Xu ahash_request_set_crypt(subreq, req->src, result, req->nbytes); 22566f6ce5eSHerbert Xu 226d9588045SHerbert Xu if (has_state) { 227d9588045SHerbert Xu void *state; 228d9588045SHerbert Xu 229d9588045SHerbert Xu state = kmalloc(crypto_ahash_statesize(tfm), gfp); 230d9588045SHerbert Xu if (!state) { 231d9588045SHerbert Xu kfree(subreq); 232d9588045SHerbert Xu return -ENOMEM; 233d9588045SHerbert Xu } 234d9588045SHerbert Xu 235d9588045SHerbert Xu crypto_ahash_export(req, state); 236d9588045SHerbert Xu crypto_ahash_import(subreq, state); 237d9588045SHerbert Xu kfree_sensitive(state); 238d9588045SHerbert Xu } 239d9588045SHerbert Xu 240d9588045SHerbert Xu req->priv = subreq; 24166f6ce5eSHerbert Xu 2421ffc9fbdSMarek Vasut return 0; 2431ffc9fbdSMarek Vasut } 2441ffc9fbdSMarek Vasut 245ef0579b6SHerbert Xu static void ahash_restore_req(struct ahash_request *req, int err) 2461ffc9fbdSMarek Vasut { 247d9588045SHerbert Xu struct ahash_request *subreq = req->priv; 2481ffc9fbdSMarek Vasut 249ef0579b6SHerbert Xu if (!err) 250d9588045SHerbert Xu memcpy(req->result, subreq->result, 251ef0579b6SHerbert Xu crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); 252ef0579b6SHerbert Xu 2531ffc9fbdSMarek Vasut req->priv = NULL; 2541ffc9fbdSMarek Vasut 255d9588045SHerbert Xu kfree_sensitive(subreq); 2561ffc9fbdSMarek Vasut } 2571ffc9fbdSMarek Vasut 258255e48ebSHerbert Xu static void ahash_op_unaligned_done(void *data, int err) 2591ffc9fbdSMarek Vasut { 260255e48ebSHerbert Xu struct ahash_request *areq = data; 2611ffc9fbdSMarek Vasut 262d9588045SHerbert Xu if (err == -EINPROGRESS) 263d9588045SHerbert Xu goto out; 2641ffc9fbdSMarek Vasut 2651ffc9fbdSMarek Vasut /* First copy req->result into req->priv.result */ 266ef0579b6SHerbert Xu ahash_restore_req(areq, err); 2671ffc9fbdSMarek Vasut 268d9588045SHerbert Xu out: 2691ffc9fbdSMarek Vasut /* Complete the ORIGINAL request. */ 270d9588045SHerbert Xu ahash_request_complete(areq, err); 2711ffc9fbdSMarek Vasut } 2721ffc9fbdSMarek Vasut 2731ffc9fbdSMarek Vasut static int ahash_op_unaligned(struct ahash_request *req, 274d9588045SHerbert Xu int (*op)(struct ahash_request *), 275d9588045SHerbert Xu bool has_state) 2761ffc9fbdSMarek Vasut { 2771ffc9fbdSMarek Vasut int err; 2781ffc9fbdSMarek Vasut 279d9588045SHerbert Xu err = ahash_save_req(req, ahash_op_unaligned_done, has_state); 2801ffc9fbdSMarek Vasut if (err) 2811ffc9fbdSMarek Vasut return err; 2821ffc9fbdSMarek Vasut 283d9588045SHerbert Xu err = op(req->priv); 2844e5b0ad5SGilad Ben-Yossef if (err == -EINPROGRESS || err == -EBUSY) 285ef0579b6SHerbert Xu return err; 286ef0579b6SHerbert Xu 287ef0579b6SHerbert Xu ahash_restore_req(req, err); 28866f6ce5eSHerbert Xu 28966f6ce5eSHerbert Xu return err; 29066f6ce5eSHerbert Xu } 29166f6ce5eSHerbert Xu 29266f6ce5eSHerbert Xu static int crypto_ahash_op(struct ahash_request *req, 293d9588045SHerbert Xu int (*op)(struct ahash_request *), 294d9588045SHerbert Xu bool has_state) 29566f6ce5eSHerbert Xu { 29666f6ce5eSHerbert Xu struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 29766f6ce5eSHerbert Xu unsigned long alignmask = crypto_ahash_alignmask(tfm); 29842808e5dSHerbert Xu int err; 29966f6ce5eSHerbert Xu 30066f6ce5eSHerbert Xu if ((unsigned long)req->result & alignmask) 30142808e5dSHerbert Xu err = ahash_op_unaligned(req, op, has_state); 30242808e5dSHerbert Xu else 30342808e5dSHerbert Xu err = op(req); 30466f6ce5eSHerbert Xu 30542808e5dSHerbert Xu return crypto_hash_errstat(crypto_hash_alg_common(tfm), err); 30666f6ce5eSHerbert Xu } 30766f6ce5eSHerbert Xu 30866f6ce5eSHerbert Xu int crypto_ahash_final(struct ahash_request *req) 30966f6ce5eSHerbert Xu { 310f7d76e05SCorentin Labbe struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 31142808e5dSHerbert Xu struct hash_alg_common *alg = crypto_hash_alg_common(tfm); 312cac5818cSCorentin Labbe 31342808e5dSHerbert Xu if (IS_ENABLED(CONFIG_CRYPTO_STATS)) 31442808e5dSHerbert Xu atomic64_inc(&hash_get_stat(alg)->hash_cnt); 31542808e5dSHerbert Xu 31642808e5dSHerbert Xu return crypto_ahash_op(req, tfm->final, true); 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); 32342808e5dSHerbert Xu struct hash_alg_common *alg = crypto_hash_alg_common(tfm); 324cac5818cSCorentin Labbe 32542808e5dSHerbert Xu if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { 32642808e5dSHerbert Xu struct crypto_istat_hash *istat = hash_get_stat(alg); 32742808e5dSHerbert Xu 32842808e5dSHerbert Xu atomic64_inc(&istat->hash_cnt); 32942808e5dSHerbert Xu atomic64_add(req->nbytes, &istat->hash_tlen); 33042808e5dSHerbert Xu } 33142808e5dSHerbert Xu 33242808e5dSHerbert Xu return crypto_ahash_op(req, tfm->finup, true); 33366f6ce5eSHerbert Xu } 33466f6ce5eSHerbert Xu EXPORT_SYMBOL_GPL(crypto_ahash_finup); 33566f6ce5eSHerbert Xu 33666f6ce5eSHerbert Xu int crypto_ahash_digest(struct ahash_request *req) 33766f6ce5eSHerbert Xu { 3389fa68f62SEric Biggers struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 33942808e5dSHerbert Xu struct hash_alg_common *alg = crypto_hash_alg_common(tfm); 3409fa68f62SEric Biggers 34142808e5dSHerbert Xu if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { 34242808e5dSHerbert Xu struct crypto_istat_hash *istat = hash_get_stat(alg); 34342808e5dSHerbert Xu 34442808e5dSHerbert Xu atomic64_inc(&istat->hash_cnt); 34542808e5dSHerbert Xu atomic64_add(req->nbytes, &istat->hash_tlen); 34642808e5dSHerbert Xu } 34742808e5dSHerbert Xu 3489fa68f62SEric Biggers if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) 34942808e5dSHerbert Xu return crypto_hash_errstat(alg, -ENOKEY); 35042808e5dSHerbert Xu 35142808e5dSHerbert Xu return crypto_ahash_op(req, tfm->digest, false); 35266f6ce5eSHerbert Xu } 35366f6ce5eSHerbert Xu EXPORT_SYMBOL_GPL(crypto_ahash_digest); 35466f6ce5eSHerbert Xu 355255e48ebSHerbert Xu static void ahash_def_finup_done2(void *data, int err) 35666f6ce5eSHerbert Xu { 357255e48ebSHerbert Xu struct ahash_request *areq = data; 35866f6ce5eSHerbert Xu 359ef0579b6SHerbert Xu if (err == -EINPROGRESS) 360ef0579b6SHerbert Xu return; 361ef0579b6SHerbert Xu 362ef0579b6SHerbert Xu ahash_restore_req(areq, err); 36366f6ce5eSHerbert Xu 364d9588045SHerbert Xu ahash_request_complete(areq, err); 36566f6ce5eSHerbert Xu } 36666f6ce5eSHerbert Xu 36766f6ce5eSHerbert Xu static int ahash_def_finup_finish1(struct ahash_request *req, int err) 36866f6ce5eSHerbert Xu { 369d9588045SHerbert Xu struct ahash_request *subreq = req->priv; 370d9588045SHerbert Xu 37166f6ce5eSHerbert Xu if (err) 37266f6ce5eSHerbert Xu goto out; 37366f6ce5eSHerbert Xu 374d9588045SHerbert Xu subreq->base.complete = ahash_def_finup_done2; 375ef0579b6SHerbert Xu 376d9588045SHerbert Xu err = crypto_ahash_reqtfm(req)->final(subreq); 3774e5b0ad5SGilad Ben-Yossef if (err == -EINPROGRESS || err == -EBUSY) 378ef0579b6SHerbert Xu return err; 37966f6ce5eSHerbert Xu 38066f6ce5eSHerbert Xu out: 381ef0579b6SHerbert Xu ahash_restore_req(req, err); 38266f6ce5eSHerbert Xu return err; 38366f6ce5eSHerbert Xu } 38466f6ce5eSHerbert Xu 385255e48ebSHerbert Xu static void ahash_def_finup_done1(void *data, int err) 38666f6ce5eSHerbert Xu { 387255e48ebSHerbert Xu struct ahash_request *areq = data; 388d9588045SHerbert Xu struct ahash_request *subreq; 38966f6ce5eSHerbert Xu 390d9588045SHerbert Xu if (err == -EINPROGRESS) 391d9588045SHerbert Xu goto out; 392ef0579b6SHerbert Xu 393d9588045SHerbert Xu subreq = areq->priv; 394d9588045SHerbert Xu subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG; 395ef0579b6SHerbert Xu 39666f6ce5eSHerbert Xu err = ahash_def_finup_finish1(areq, err); 397d9588045SHerbert Xu if (err == -EINPROGRESS || err == -EBUSY) 398ef0579b6SHerbert Xu return; 39966f6ce5eSHerbert Xu 400d9588045SHerbert Xu out: 401d9588045SHerbert Xu ahash_request_complete(areq, err); 40266f6ce5eSHerbert Xu } 40366f6ce5eSHerbert Xu 40466f6ce5eSHerbert Xu static int ahash_def_finup(struct ahash_request *req) 40566f6ce5eSHerbert Xu { 40666f6ce5eSHerbert Xu struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 407d4a7a0fbSMarek Vasut int err; 40866f6ce5eSHerbert Xu 409d9588045SHerbert Xu err = ahash_save_req(req, ahash_def_finup_done1, true); 410d4a7a0fbSMarek Vasut if (err) 411d4a7a0fbSMarek Vasut return err; 41266f6ce5eSHerbert Xu 413d9588045SHerbert Xu err = tfm->update(req->priv); 4144e5b0ad5SGilad Ben-Yossef if (err == -EINPROGRESS || err == -EBUSY) 415ef0579b6SHerbert Xu return err; 416ef0579b6SHerbert Xu 417d4a7a0fbSMarek Vasut return ahash_def_finup_finish1(req, err); 41866f6ce5eSHerbert Xu } 41966f6ce5eSHerbert Xu 420e73d340dSHerbert Xu static void crypto_ahash_exit_tfm(struct crypto_tfm *tfm) 421e73d340dSHerbert Xu { 422e73d340dSHerbert Xu struct crypto_ahash *hash = __crypto_ahash_cast(tfm); 423e73d340dSHerbert Xu struct ahash_alg *alg = crypto_ahash_alg(hash); 424e73d340dSHerbert Xu 425e73d340dSHerbert Xu alg->exit_tfm(hash); 426e73d340dSHerbert Xu } 427e73d340dSHerbert Xu 42888056ec3SHerbert Xu static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) 42988056ec3SHerbert Xu { 43088056ec3SHerbert Xu struct crypto_ahash *hash = __crypto_ahash_cast(tfm); 43188056ec3SHerbert Xu struct ahash_alg *alg = crypto_ahash_alg(hash); 43288056ec3SHerbert Xu 43366f6ce5eSHerbert Xu hash->setkey = ahash_nosetkey; 43466f6ce5eSHerbert Xu 43588056ec3SHerbert Xu if (tfm->__crt_alg->cra_type != &crypto_ahash_type) 43688056ec3SHerbert Xu return crypto_init_shash_ops_async(tfm); 43788056ec3SHerbert Xu 43888056ec3SHerbert Xu hash->init = alg->init; 43988056ec3SHerbert Xu hash->update = alg->update; 44088056ec3SHerbert Xu hash->final = alg->final; 44166f6ce5eSHerbert Xu hash->finup = alg->finup ?: ahash_def_finup; 44288056ec3SHerbert Xu hash->digest = alg->digest; 4436f221f7eSKamil Konieczny hash->export = alg->export; 4446f221f7eSKamil Konieczny hash->import = alg->import; 44566f6ce5eSHerbert Xu 446a5596d63SHerbert Xu if (alg->setkey) { 44766f6ce5eSHerbert Xu hash->setkey = alg->setkey; 448ba7d7433SEric Biggers ahash_set_needkey(hash); 449a5596d63SHerbert Xu } 45088056ec3SHerbert Xu 451e73d340dSHerbert Xu if (alg->exit_tfm) 452e73d340dSHerbert Xu tfm->exit = crypto_ahash_exit_tfm; 453e73d340dSHerbert Xu 454e73d340dSHerbert Xu return alg->init_tfm ? alg->init_tfm(hash) : 0; 45588056ec3SHerbert Xu } 45688056ec3SHerbert Xu 45788056ec3SHerbert Xu static unsigned int crypto_ahash_extsize(struct crypto_alg *alg) 45888056ec3SHerbert Xu { 4592495cf25SHerbert Xu if (alg->cra_type != &crypto_ahash_type) 46088056ec3SHerbert Xu return sizeof(struct crypto_shash *); 4612495cf25SHerbert Xu 4622495cf25SHerbert Xu return crypto_alg_extsize(alg); 46388056ec3SHerbert Xu } 46488056ec3SHerbert Xu 46548fb3e57SEric Biggers static void crypto_ahash_free_instance(struct crypto_instance *inst) 46648fb3e57SEric Biggers { 46748fb3e57SEric Biggers struct ahash_instance *ahash = ahash_instance(inst); 46848fb3e57SEric Biggers 46948fb3e57SEric Biggers ahash->free(ahash); 47048fb3e57SEric Biggers } 47148fb3e57SEric Biggers 472*c0f9e01dSHerbert Xu static int __maybe_unused crypto_ahash_report( 473*c0f9e01dSHerbert Xu struct sk_buff *skb, struct crypto_alg *alg) 4746238cbaeSSteffen Klassert { 4756238cbaeSSteffen Klassert struct crypto_report_hash rhash; 4766238cbaeSSteffen Klassert 47737db69e0SEric Biggers memset(&rhash, 0, sizeof(rhash)); 47837db69e0SEric Biggers 47937db69e0SEric Biggers strscpy(rhash.type, "ahash", sizeof(rhash.type)); 4806238cbaeSSteffen Klassert 4816238cbaeSSteffen Klassert rhash.blocksize = alg->cra_blocksize; 4826238cbaeSSteffen Klassert rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize; 4836238cbaeSSteffen Klassert 48437db69e0SEric Biggers return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash); 4856238cbaeSSteffen Klassert } 4866238cbaeSSteffen Klassert 487004a403cSLoc Ho static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) 488d8c34b94SGideon Israel Dsouza __maybe_unused; 489004a403cSLoc Ho static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) 490004a403cSLoc Ho { 491004a403cSLoc Ho seq_printf(m, "type : ahash\n"); 492004a403cSLoc Ho seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? 493004a403cSLoc Ho "yes" : "no"); 494004a403cSLoc Ho seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); 49588056ec3SHerbert Xu seq_printf(m, "digestsize : %u\n", 49688056ec3SHerbert Xu __crypto_hash_alg_common(alg)->digestsize); 497004a403cSLoc Ho } 498004a403cSLoc Ho 49942808e5dSHerbert Xu static int __maybe_unused crypto_ahash_report_stat( 50042808e5dSHerbert Xu struct sk_buff *skb, struct crypto_alg *alg) 50142808e5dSHerbert Xu { 50242808e5dSHerbert Xu return crypto_hash_report_stat(skb, alg, "ahash"); 50342808e5dSHerbert Xu } 50442808e5dSHerbert Xu 5056d1b41fcSEric Biggers static const struct crypto_type crypto_ahash_type = { 50688056ec3SHerbert Xu .extsize = crypto_ahash_extsize, 50788056ec3SHerbert Xu .init_tfm = crypto_ahash_init_tfm, 50848fb3e57SEric Biggers .free = crypto_ahash_free_instance, 509004a403cSLoc Ho #ifdef CONFIG_PROC_FS 510004a403cSLoc Ho .show = crypto_ahash_show, 511004a403cSLoc Ho #endif 512*c0f9e01dSHerbert Xu #ifdef CONFIG_CRYPTO_USER 5136238cbaeSSteffen Klassert .report = crypto_ahash_report, 514*c0f9e01dSHerbert Xu #endif 51542808e5dSHerbert Xu #ifdef CONFIG_CRYPTO_STATS 51642808e5dSHerbert Xu .report_stat = crypto_ahash_report_stat, 51742808e5dSHerbert Xu #endif 51888056ec3SHerbert Xu .maskclear = ~CRYPTO_ALG_TYPE_MASK, 51988056ec3SHerbert Xu .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, 52088056ec3SHerbert Xu .type = CRYPTO_ALG_TYPE_AHASH, 52188056ec3SHerbert Xu .tfmsize = offsetof(struct crypto_ahash, base), 522004a403cSLoc Ho }; 523004a403cSLoc Ho 52484a9c938SEric Biggers int crypto_grab_ahash(struct crypto_ahash_spawn *spawn, 52584a9c938SEric Biggers struct crypto_instance *inst, 52684a9c938SEric Biggers const char *name, u32 type, u32 mask) 52784a9c938SEric Biggers { 52884a9c938SEric Biggers spawn->base.frontend = &crypto_ahash_type; 52984a9c938SEric Biggers return crypto_grab_spawn(&spawn->base, inst, name, type, mask); 53084a9c938SEric Biggers } 53184a9c938SEric Biggers EXPORT_SYMBOL_GPL(crypto_grab_ahash); 53284a9c938SEric Biggers 53388056ec3SHerbert Xu struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, 53488056ec3SHerbert Xu u32 mask) 53588056ec3SHerbert Xu { 53688056ec3SHerbert Xu return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask); 53788056ec3SHerbert Xu } 53888056ec3SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alloc_ahash); 53988056ec3SHerbert Xu 5408d18e34cSHerbert Xu int crypto_has_ahash(const char *alg_name, u32 type, u32 mask) 5418d18e34cSHerbert Xu { 5428d18e34cSHerbert Xu return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask); 5438d18e34cSHerbert Xu } 5448d18e34cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_has_ahash); 5458d18e34cSHerbert Xu 54601c2deceSHerbert Xu static int ahash_prepare_alg(struct ahash_alg *alg) 54701c2deceSHerbert Xu { 54801c2deceSHerbert Xu struct crypto_alg *base = &alg->halg.base; 54942808e5dSHerbert Xu int err; 55001c2deceSHerbert Xu 55142808e5dSHerbert Xu if (alg->halg.statesize == 0) 55201c2deceSHerbert Xu return -EINVAL; 55301c2deceSHerbert Xu 55442808e5dSHerbert Xu err = hash_prepare_alg(&alg->halg); 55542808e5dSHerbert Xu if (err) 55642808e5dSHerbert Xu return err; 55742808e5dSHerbert Xu 55801c2deceSHerbert Xu base->cra_type = &crypto_ahash_type; 55901c2deceSHerbert Xu base->cra_flags |= CRYPTO_ALG_TYPE_AHASH; 56001c2deceSHerbert Xu 56101c2deceSHerbert Xu return 0; 56201c2deceSHerbert Xu } 56301c2deceSHerbert Xu 56401c2deceSHerbert Xu int crypto_register_ahash(struct ahash_alg *alg) 56501c2deceSHerbert Xu { 56601c2deceSHerbert Xu struct crypto_alg *base = &alg->halg.base; 56701c2deceSHerbert Xu int err; 56801c2deceSHerbert Xu 56901c2deceSHerbert Xu err = ahash_prepare_alg(alg); 57001c2deceSHerbert Xu if (err) 57101c2deceSHerbert Xu return err; 57201c2deceSHerbert Xu 57301c2deceSHerbert Xu return crypto_register_alg(base); 57401c2deceSHerbert Xu } 57501c2deceSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_ahash); 57601c2deceSHerbert Xu 577c6d633a9SEric Biggers void crypto_unregister_ahash(struct ahash_alg *alg) 57801c2deceSHerbert Xu { 579c6d633a9SEric Biggers crypto_unregister_alg(&alg->halg.base); 58001c2deceSHerbert Xu } 58101c2deceSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_ahash); 58201c2deceSHerbert Xu 5836f7473c5SRabin Vincent int crypto_register_ahashes(struct ahash_alg *algs, int count) 5846f7473c5SRabin Vincent { 5856f7473c5SRabin Vincent int i, ret; 5866f7473c5SRabin Vincent 5876f7473c5SRabin Vincent for (i = 0; i < count; i++) { 5886f7473c5SRabin Vincent ret = crypto_register_ahash(&algs[i]); 5896f7473c5SRabin Vincent if (ret) 5906f7473c5SRabin Vincent goto err; 5916f7473c5SRabin Vincent } 5926f7473c5SRabin Vincent 5936f7473c5SRabin Vincent return 0; 5946f7473c5SRabin Vincent 5956f7473c5SRabin Vincent err: 5966f7473c5SRabin Vincent for (--i; i >= 0; --i) 5976f7473c5SRabin Vincent crypto_unregister_ahash(&algs[i]); 5986f7473c5SRabin Vincent 5996f7473c5SRabin Vincent return ret; 6006f7473c5SRabin Vincent } 6016f7473c5SRabin Vincent EXPORT_SYMBOL_GPL(crypto_register_ahashes); 6026f7473c5SRabin Vincent 6036f7473c5SRabin Vincent void crypto_unregister_ahashes(struct ahash_alg *algs, int count) 6046f7473c5SRabin Vincent { 6056f7473c5SRabin Vincent int i; 6066f7473c5SRabin Vincent 6076f7473c5SRabin Vincent for (i = count - 1; i >= 0; --i) 6086f7473c5SRabin Vincent crypto_unregister_ahash(&algs[i]); 6096f7473c5SRabin Vincent } 6106f7473c5SRabin Vincent EXPORT_SYMBOL_GPL(crypto_unregister_ahashes); 6116f7473c5SRabin Vincent 61201c2deceSHerbert Xu int ahash_register_instance(struct crypto_template *tmpl, 61301c2deceSHerbert Xu struct ahash_instance *inst) 61401c2deceSHerbert Xu { 61501c2deceSHerbert Xu int err; 61601c2deceSHerbert Xu 617d4fdc2dfSEric Biggers if (WARN_ON(!inst->free)) 618d4fdc2dfSEric Biggers return -EINVAL; 619d4fdc2dfSEric Biggers 62001c2deceSHerbert Xu err = ahash_prepare_alg(&inst->alg); 62101c2deceSHerbert Xu if (err) 62201c2deceSHerbert Xu return err; 62301c2deceSHerbert Xu 62401c2deceSHerbert Xu return crypto_register_instance(tmpl, ahash_crypto_instance(inst)); 62501c2deceSHerbert Xu } 62601c2deceSHerbert Xu EXPORT_SYMBOL_GPL(ahash_register_instance); 62701c2deceSHerbert Xu 628cd6ed77aSEric Biggers bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg) 629cd6ed77aSEric Biggers { 630cd6ed77aSEric Biggers struct crypto_alg *alg = &halg->base; 631cd6ed77aSEric Biggers 632cd6ed77aSEric Biggers if (alg->cra_type != &crypto_ahash_type) 633cd6ed77aSEric Biggers return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg)); 634cd6ed77aSEric Biggers 635cd6ed77aSEric Biggers return __crypto_ahash_alg(alg)->setkey != NULL; 636cd6ed77aSEric Biggers } 637cd6ed77aSEric Biggers EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey); 638cd6ed77aSEric Biggers 639004a403cSLoc Ho MODULE_LICENSE("GPL"); 640004a403cSLoc Ho MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); 641