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 193*d9588045SHerbert Xu static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt, 194*d9588045SHerbert 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); 199*d9588045SHerbert Xu struct ahash_request *subreq; 200*d9588045SHerbert Xu unsigned int subreq_size; 201*d9588045SHerbert Xu unsigned int reqsize; 202*d9588045SHerbert Xu u8 *result; 203*d9588045SHerbert Xu gfp_t gfp; 204*d9588045SHerbert Xu u32 flags; 20566f6ce5eSHerbert Xu 206*d9588045SHerbert Xu subreq_size = sizeof(*subreq); 207*d9588045SHerbert Xu reqsize = crypto_ahash_reqsize(tfm); 208*d9588045SHerbert Xu reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment()); 209*d9588045SHerbert Xu subreq_size += reqsize; 210*d9588045SHerbert Xu subreq_size += ds; 211*d9588045SHerbert Xu subreq_size += alignmask & ~(crypto_tfm_ctx_alignment() - 1); 212*d9588045SHerbert Xu 213*d9588045SHerbert Xu flags = ahash_request_flags(req); 214*d9588045SHerbert Xu gfp = (flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; 215*d9588045SHerbert Xu subreq = kmalloc(subreq_size, gfp); 216*d9588045SHerbert Xu if (!subreq) 21766f6ce5eSHerbert Xu return -ENOMEM; 21866f6ce5eSHerbert Xu 219*d9588045SHerbert Xu ahash_request_set_tfm(subreq, tfm); 220*d9588045SHerbert Xu ahash_request_set_callback(subreq, flags, cplt, req); 221ab6bf4e5SMarek Vasut 222*d9588045SHerbert Xu result = (u8 *)(subreq + 1) + reqsize; 223*d9588045SHerbert Xu result = PTR_ALIGN(result, alignmask + 1); 224ef0579b6SHerbert Xu 225*d9588045SHerbert Xu ahash_request_set_crypt(subreq, req->src, result, req->nbytes); 22666f6ce5eSHerbert Xu 227*d9588045SHerbert Xu if (has_state) { 228*d9588045SHerbert Xu void *state; 229*d9588045SHerbert Xu 230*d9588045SHerbert Xu state = kmalloc(crypto_ahash_statesize(tfm), gfp); 231*d9588045SHerbert Xu if (!state) { 232*d9588045SHerbert Xu kfree(subreq); 233*d9588045SHerbert Xu return -ENOMEM; 234*d9588045SHerbert Xu } 235*d9588045SHerbert Xu 236*d9588045SHerbert Xu crypto_ahash_export(req, state); 237*d9588045SHerbert Xu crypto_ahash_import(subreq, state); 238*d9588045SHerbert Xu kfree_sensitive(state); 239*d9588045SHerbert Xu } 240*d9588045SHerbert Xu 241*d9588045SHerbert 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 { 248*d9588045SHerbert Xu struct ahash_request *subreq = req->priv; 2491ffc9fbdSMarek Vasut 250ef0579b6SHerbert Xu if (!err) 251*d9588045SHerbert Xu memcpy(req->result, subreq->result, 252ef0579b6SHerbert Xu crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); 253ef0579b6SHerbert Xu 2541ffc9fbdSMarek Vasut req->priv = NULL; 2551ffc9fbdSMarek Vasut 256*d9588045SHerbert Xu kfree_sensitive(subreq); 2571ffc9fbdSMarek Vasut } 2581ffc9fbdSMarek Vasut 2591ffc9fbdSMarek Vasut static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) 2601ffc9fbdSMarek Vasut { 2611ffc9fbdSMarek Vasut struct ahash_request *areq = req->data; 2621ffc9fbdSMarek Vasut 263*d9588045SHerbert Xu if (err == -EINPROGRESS) 264*d9588045SHerbert Xu goto out; 2651ffc9fbdSMarek Vasut 2661ffc9fbdSMarek Vasut /* First copy req->result into req->priv.result */ 267ef0579b6SHerbert Xu ahash_restore_req(areq, err); 2681ffc9fbdSMarek Vasut 269*d9588045SHerbert Xu out: 2701ffc9fbdSMarek Vasut /* Complete the ORIGINAL request. */ 271*d9588045SHerbert Xu ahash_request_complete(areq, err); 2721ffc9fbdSMarek Vasut } 2731ffc9fbdSMarek Vasut 2741ffc9fbdSMarek Vasut static int ahash_op_unaligned(struct ahash_request *req, 275*d9588045SHerbert Xu int (*op)(struct ahash_request *), 276*d9588045SHerbert Xu bool has_state) 2771ffc9fbdSMarek Vasut { 2781ffc9fbdSMarek Vasut int err; 2791ffc9fbdSMarek Vasut 280*d9588045SHerbert Xu err = ahash_save_req(req, ahash_op_unaligned_done, has_state); 2811ffc9fbdSMarek Vasut if (err) 2821ffc9fbdSMarek Vasut return err; 2831ffc9fbdSMarek Vasut 284*d9588045SHerbert 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, 294*d9588045SHerbert Xu int (*op)(struct ahash_request *), 295*d9588045SHerbert 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) 301*d9588045SHerbert 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); 314*d9588045SHerbert 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); 328*d9588045SHerbert 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 345*d9588045SHerbert 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 35166f6ce5eSHerbert Xu static void ahash_def_finup_done2(struct crypto_async_request *req, int err) 35266f6ce5eSHerbert Xu { 35366f6ce5eSHerbert Xu struct ahash_request *areq = req->data; 35466f6ce5eSHerbert Xu 355ef0579b6SHerbert Xu if (err == -EINPROGRESS) 356ef0579b6SHerbert Xu return; 357ef0579b6SHerbert Xu 358ef0579b6SHerbert Xu ahash_restore_req(areq, err); 35966f6ce5eSHerbert Xu 360*d9588045SHerbert 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 { 365*d9588045SHerbert Xu struct ahash_request *subreq = req->priv; 366*d9588045SHerbert Xu 36766f6ce5eSHerbert Xu if (err) 36866f6ce5eSHerbert Xu goto out; 36966f6ce5eSHerbert Xu 370*d9588045SHerbert Xu subreq->base.complete = ahash_def_finup_done2; 371ef0579b6SHerbert Xu 372*d9588045SHerbert 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 38166f6ce5eSHerbert Xu static void ahash_def_finup_done1(struct crypto_async_request *req, int err) 38266f6ce5eSHerbert Xu { 38366f6ce5eSHerbert Xu struct ahash_request *areq = req->data; 384*d9588045SHerbert Xu struct ahash_request *subreq; 38566f6ce5eSHerbert Xu 386*d9588045SHerbert Xu if (err == -EINPROGRESS) 387*d9588045SHerbert Xu goto out; 388ef0579b6SHerbert Xu 389*d9588045SHerbert Xu subreq = areq->priv; 390*d9588045SHerbert Xu subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG; 391ef0579b6SHerbert Xu 39266f6ce5eSHerbert Xu err = ahash_def_finup_finish1(areq, err); 393*d9588045SHerbert Xu if (err == -EINPROGRESS || err == -EBUSY) 394ef0579b6SHerbert Xu return; 39566f6ce5eSHerbert Xu 396*d9588045SHerbert Xu out: 397*d9588045SHerbert 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 405*d9588045SHerbert Xu err = ahash_save_req(req, ahash_def_finup_done1, true); 406d4a7a0fbSMarek Vasut if (err) 407d4a7a0fbSMarek Vasut return err; 40866f6ce5eSHerbert Xu 409*d9588045SHerbert 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