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