18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Asynchronous Cryptographic Hash operations. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This is the asynchronous version of hash.c with notification of 68c2ecf20Sopenharmony_ci * completion via a callback. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (c) 2008 Loc Ho <lho@amcc.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 128c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/sched.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 198c2ecf20Sopenharmony_ci#include <linux/cryptouser.h> 208c2ecf20Sopenharmony_ci#include <linux/compiler.h> 218c2ecf20Sopenharmony_ci#include <net/netlink.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "internal.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const struct crypto_type crypto_ahash_type; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct ahash_request_priv { 288c2ecf20Sopenharmony_ci crypto_completion_t complete; 298c2ecf20Sopenharmony_ci void *data; 308c2ecf20Sopenharmony_ci u8 *result; 318c2ecf20Sopenharmony_ci u32 flags; 328c2ecf20Sopenharmony_ci void *ubuf[] CRYPTO_MINALIGN_ATTR; 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci return container_of(crypto_hash_alg_common(hash), struct ahash_alg, 388c2ecf20Sopenharmony_ci halg); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int hash_walk_next(struct crypto_hash_walk *walk) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci unsigned int alignmask = walk->alignmask; 448c2ecf20Sopenharmony_ci unsigned int offset = walk->offset; 458c2ecf20Sopenharmony_ci unsigned int nbytes = min(walk->entrylen, 468c2ecf20Sopenharmony_ci ((unsigned int)(PAGE_SIZE)) - offset); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci walk->data = kmap_atomic(walk->pg); 498c2ecf20Sopenharmony_ci walk->data += offset; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (offset & alignmask) { 528c2ecf20Sopenharmony_ci unsigned int unaligned = alignmask + 1 - (offset & alignmask); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (nbytes > unaligned) 558c2ecf20Sopenharmony_ci nbytes = unaligned; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci walk->entrylen -= nbytes; 598c2ecf20Sopenharmony_ci return nbytes; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int hash_walk_new_entry(struct crypto_hash_walk *walk) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct scatterlist *sg; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci sg = walk->sg; 678c2ecf20Sopenharmony_ci walk->offset = sg->offset; 688c2ecf20Sopenharmony_ci walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT); 698c2ecf20Sopenharmony_ci walk->offset = offset_in_page(walk->offset); 708c2ecf20Sopenharmony_ci walk->entrylen = sg->length; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (walk->entrylen > walk->total) 738c2ecf20Sopenharmony_ci walk->entrylen = walk->total; 748c2ecf20Sopenharmony_ci walk->total -= walk->entrylen; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return hash_walk_next(walk); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciint crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci unsigned int alignmask = walk->alignmask; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci walk->data -= walk->offset; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (walk->entrylen && (walk->offset & alignmask) && !err) { 868c2ecf20Sopenharmony_ci unsigned int nbytes; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci walk->offset = ALIGN(walk->offset, alignmask + 1); 898c2ecf20Sopenharmony_ci nbytes = min(walk->entrylen, 908c2ecf20Sopenharmony_ci (unsigned int)(PAGE_SIZE - walk->offset)); 918c2ecf20Sopenharmony_ci if (nbytes) { 928c2ecf20Sopenharmony_ci walk->entrylen -= nbytes; 938c2ecf20Sopenharmony_ci walk->data += walk->offset; 948c2ecf20Sopenharmony_ci return nbytes; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci kunmap_atomic(walk->data); 998c2ecf20Sopenharmony_ci crypto_yield(walk->flags); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (err) 1028c2ecf20Sopenharmony_ci return err; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (walk->entrylen) { 1058c2ecf20Sopenharmony_ci walk->offset = 0; 1068c2ecf20Sopenharmony_ci walk->pg++; 1078c2ecf20Sopenharmony_ci return hash_walk_next(walk); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (!walk->total) 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci walk->sg = sg_next(walk->sg); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return hash_walk_new_entry(walk); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_hash_walk_done); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ciint crypto_hash_walk_first(struct ahash_request *req, 1208c2ecf20Sopenharmony_ci struct crypto_hash_walk *walk) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci walk->total = req->nbytes; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (!walk->total) { 1258c2ecf20Sopenharmony_ci walk->entrylen = 0; 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req)); 1308c2ecf20Sopenharmony_ci walk->sg = req->src; 1318c2ecf20Sopenharmony_ci walk->flags = req->base.flags; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return hash_walk_new_entry(walk); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_hash_walk_first); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, 1388c2ecf20Sopenharmony_ci unsigned int keylen) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci unsigned long alignmask = crypto_ahash_alignmask(tfm); 1418c2ecf20Sopenharmony_ci int ret; 1428c2ecf20Sopenharmony_ci u8 *buffer, *alignbuffer; 1438c2ecf20Sopenharmony_ci unsigned long absize; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci absize = keylen + alignmask; 1468c2ecf20Sopenharmony_ci buffer = kmalloc(absize, GFP_KERNEL); 1478c2ecf20Sopenharmony_ci if (!buffer) 1488c2ecf20Sopenharmony_ci return -ENOMEM; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 1518c2ecf20Sopenharmony_ci memcpy(alignbuffer, key, keylen); 1528c2ecf20Sopenharmony_ci ret = tfm->setkey(tfm, alignbuffer, keylen); 1538c2ecf20Sopenharmony_ci kfree_sensitive(buffer); 1548c2ecf20Sopenharmony_ci return ret; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, 1588c2ecf20Sopenharmony_ci unsigned int keylen) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci return -ENOSYS; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void ahash_set_needkey(struct crypto_ahash *tfm) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci const struct hash_alg_common *alg = crypto_hash_alg_common(tfm); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (tfm->setkey != ahash_nosetkey && 1688c2ecf20Sopenharmony_ci !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) 1698c2ecf20Sopenharmony_ci crypto_ahash_set_flags(tfm, CRYPTO_TFM_NEED_KEY); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ciint crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, 1738c2ecf20Sopenharmony_ci unsigned int keylen) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci unsigned long alignmask = crypto_ahash_alignmask(tfm); 1768c2ecf20Sopenharmony_ci int err; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if ((unsigned long)key & alignmask) 1798c2ecf20Sopenharmony_ci err = ahash_setkey_unaligned(tfm, key, keylen); 1808c2ecf20Sopenharmony_ci else 1818c2ecf20Sopenharmony_ci err = tfm->setkey(tfm, key, keylen); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (unlikely(err)) { 1848c2ecf20Sopenharmony_ci ahash_set_needkey(tfm); 1858c2ecf20Sopenharmony_ci return err; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ahash_setkey); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic inline unsigned int ahash_align_buffer_size(unsigned len, 1948c2ecf20Sopenharmony_ci unsigned long mask) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci return len + (mask & ~(crypto_tfm_ctx_alignment() - 1)); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 2028c2ecf20Sopenharmony_ci unsigned long alignmask = crypto_ahash_alignmask(tfm); 2038c2ecf20Sopenharmony_ci unsigned int ds = crypto_ahash_digestsize(tfm); 2048c2ecf20Sopenharmony_ci struct ahash_request_priv *priv; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), 2078c2ecf20Sopenharmony_ci (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? 2088c2ecf20Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC); 2098c2ecf20Sopenharmony_ci if (!priv) 2108c2ecf20Sopenharmony_ci return -ENOMEM; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * WARNING: Voodoo programming below! 2148c2ecf20Sopenharmony_ci * 2158c2ecf20Sopenharmony_ci * The code below is obscure and hard to understand, thus explanation 2168c2ecf20Sopenharmony_ci * is necessary. See include/crypto/hash.h and include/linux/crypto.h 2178c2ecf20Sopenharmony_ci * to understand the layout of structures used here! 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci * The code here will replace portions of the ORIGINAL request with 2208c2ecf20Sopenharmony_ci * pointers to new code and buffers so the hashing operation can store 2218c2ecf20Sopenharmony_ci * the result in aligned buffer. We will call the modified request 2228c2ecf20Sopenharmony_ci * an ADJUSTED request. 2238c2ecf20Sopenharmony_ci * 2248c2ecf20Sopenharmony_ci * The newly mangled request will look as such: 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * req { 2278c2ecf20Sopenharmony_ci * .result = ADJUSTED[new aligned buffer] 2288c2ecf20Sopenharmony_ci * .base.complete = ADJUSTED[pointer to completion function] 2298c2ecf20Sopenharmony_ci * .base.data = ADJUSTED[*req (pointer to self)] 2308c2ecf20Sopenharmony_ci * .priv = ADJUSTED[new priv] { 2318c2ecf20Sopenharmony_ci * .result = ORIGINAL(result) 2328c2ecf20Sopenharmony_ci * .complete = ORIGINAL(base.complete) 2338c2ecf20Sopenharmony_ci * .data = ORIGINAL(base.data) 2348c2ecf20Sopenharmony_ci * } 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci priv->result = req->result; 2388c2ecf20Sopenharmony_ci priv->complete = req->base.complete; 2398c2ecf20Sopenharmony_ci priv->data = req->base.data; 2408c2ecf20Sopenharmony_ci priv->flags = req->base.flags; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* 2438c2ecf20Sopenharmony_ci * WARNING: We do not backup req->priv here! The req->priv 2448c2ecf20Sopenharmony_ci * is for internal use of the Crypto API and the 2458c2ecf20Sopenharmony_ci * user must _NOT_ _EVER_ depend on it's content! 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); 2498c2ecf20Sopenharmony_ci req->base.complete = cplt; 2508c2ecf20Sopenharmony_ci req->base.data = req; 2518c2ecf20Sopenharmony_ci req->priv = priv; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic void ahash_restore_req(struct ahash_request *req, int err) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct ahash_request_priv *priv = req->priv; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (!err) 2618c2ecf20Sopenharmony_ci memcpy(priv->result, req->result, 2628c2ecf20Sopenharmony_ci crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Restore the original crypto request. */ 2658c2ecf20Sopenharmony_ci req->result = priv->result; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci ahash_request_set_callback(req, priv->flags, 2688c2ecf20Sopenharmony_ci priv->complete, priv->data); 2698c2ecf20Sopenharmony_ci req->priv = NULL; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Free the req->priv.priv from the ADJUSTED request. */ 2728c2ecf20Sopenharmony_ci kfree_sensitive(priv); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void ahash_notify_einprogress(struct ahash_request *req) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct ahash_request_priv *priv = req->priv; 2788c2ecf20Sopenharmony_ci struct crypto_async_request oreq; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci oreq.data = priv->data; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci priv->complete(&oreq, -EINPROGRESS); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void ahash_op_unaligned_done(struct crypto_async_request *req, int err) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct ahash_request *areq = req->data; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) { 2908c2ecf20Sopenharmony_ci ahash_notify_einprogress(areq); 2918c2ecf20Sopenharmony_ci return; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* 2958c2ecf20Sopenharmony_ci * Restore the original request, see ahash_op_unaligned() for what 2968c2ecf20Sopenharmony_ci * goes where. 2978c2ecf20Sopenharmony_ci * 2988c2ecf20Sopenharmony_ci * The "struct ahash_request *req" here is in fact the "req.base" 2998c2ecf20Sopenharmony_ci * from the ADJUSTED request from ahash_op_unaligned(), thus as it 3008c2ecf20Sopenharmony_ci * is a pointer to self, it is also the ADJUSTED "req" . 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* First copy req->result into req->priv.result */ 3048c2ecf20Sopenharmony_ci ahash_restore_req(areq, err); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* Complete the ORIGINAL request. */ 3078c2ecf20Sopenharmony_ci areq->base.complete(&areq->base, err); 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int ahash_op_unaligned(struct ahash_request *req, 3118c2ecf20Sopenharmony_ci int (*op)(struct ahash_request *)) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci int err; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci err = ahash_save_req(req, ahash_op_unaligned_done); 3168c2ecf20Sopenharmony_ci if (err) 3178c2ecf20Sopenharmony_ci return err; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci err = op(req); 3208c2ecf20Sopenharmony_ci if (err == -EINPROGRESS || err == -EBUSY) 3218c2ecf20Sopenharmony_ci return err; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ahash_restore_req(req, err); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return err; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic int crypto_ahash_op(struct ahash_request *req, 3298c2ecf20Sopenharmony_ci int (*op)(struct ahash_request *)) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 3328c2ecf20Sopenharmony_ci unsigned long alignmask = crypto_ahash_alignmask(tfm); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if ((unsigned long)req->result & alignmask) 3358c2ecf20Sopenharmony_ci return ahash_op_unaligned(req, op); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return op(req); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ciint crypto_ahash_final(struct ahash_request *req) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 3438c2ecf20Sopenharmony_ci struct crypto_alg *alg = tfm->base.__crt_alg; 3448c2ecf20Sopenharmony_ci unsigned int nbytes = req->nbytes; 3458c2ecf20Sopenharmony_ci int ret; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci crypto_stats_get(alg); 3488c2ecf20Sopenharmony_ci ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final); 3498c2ecf20Sopenharmony_ci crypto_stats_ahash_final(nbytes, ret, alg); 3508c2ecf20Sopenharmony_ci return ret; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ahash_final); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ciint crypto_ahash_finup(struct ahash_request *req) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 3578c2ecf20Sopenharmony_ci struct crypto_alg *alg = tfm->base.__crt_alg; 3588c2ecf20Sopenharmony_ci unsigned int nbytes = req->nbytes; 3598c2ecf20Sopenharmony_ci int ret; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci crypto_stats_get(alg); 3628c2ecf20Sopenharmony_ci ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup); 3638c2ecf20Sopenharmony_ci crypto_stats_ahash_final(nbytes, ret, alg); 3648c2ecf20Sopenharmony_ci return ret; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ahash_finup); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ciint crypto_ahash_digest(struct ahash_request *req) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 3718c2ecf20Sopenharmony_ci struct crypto_alg *alg = tfm->base.__crt_alg; 3728c2ecf20Sopenharmony_ci unsigned int nbytes = req->nbytes; 3738c2ecf20Sopenharmony_ci int ret; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci crypto_stats_get(alg); 3768c2ecf20Sopenharmony_ci if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) 3778c2ecf20Sopenharmony_ci ret = -ENOKEY; 3788c2ecf20Sopenharmony_ci else 3798c2ecf20Sopenharmony_ci ret = crypto_ahash_op(req, tfm->digest); 3808c2ecf20Sopenharmony_ci crypto_stats_ahash_final(nbytes, ret, alg); 3818c2ecf20Sopenharmony_ci return ret; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ahash_digest); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic void ahash_def_finup_done2(struct crypto_async_request *req, int err) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct ahash_request *areq = req->data; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 3908c2ecf20Sopenharmony_ci return; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ahash_restore_req(areq, err); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci areq->base.complete(&areq->base, err); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int ahash_def_finup_finish1(struct ahash_request *req, int err) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci if (err) 4008c2ecf20Sopenharmony_ci goto out; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci req->base.complete = ahash_def_finup_done2; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci err = crypto_ahash_reqtfm(req)->final(req); 4058c2ecf20Sopenharmony_ci if (err == -EINPROGRESS || err == -EBUSY) 4068c2ecf20Sopenharmony_ci return err; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ciout: 4098c2ecf20Sopenharmony_ci ahash_restore_req(req, err); 4108c2ecf20Sopenharmony_ci return err; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic void ahash_def_finup_done1(struct crypto_async_request *req, int err) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct ahash_request *areq = req->data; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) { 4188c2ecf20Sopenharmony_ci ahash_notify_einprogress(areq); 4198c2ecf20Sopenharmony_ci return; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci err = ahash_def_finup_finish1(areq, err); 4258c2ecf20Sopenharmony_ci if (areq->priv) 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci areq->base.complete(&areq->base, err); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int ahash_def_finup(struct ahash_request *req) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 4348c2ecf20Sopenharmony_ci int err; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci err = ahash_save_req(req, ahash_def_finup_done1); 4378c2ecf20Sopenharmony_ci if (err) 4388c2ecf20Sopenharmony_ci return err; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci err = tfm->update(req); 4418c2ecf20Sopenharmony_ci if (err == -EINPROGRESS || err == -EBUSY) 4428c2ecf20Sopenharmony_ci return err; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return ahash_def_finup_finish1(req, err); 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic void crypto_ahash_exit_tfm(struct crypto_tfm *tfm) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct crypto_ahash *hash = __crypto_ahash_cast(tfm); 4508c2ecf20Sopenharmony_ci struct ahash_alg *alg = crypto_ahash_alg(hash); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci alg->exit_tfm(hash); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic int crypto_ahash_init_tfm(struct crypto_tfm *tfm) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct crypto_ahash *hash = __crypto_ahash_cast(tfm); 4588c2ecf20Sopenharmony_ci struct ahash_alg *alg = crypto_ahash_alg(hash); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci hash->setkey = ahash_nosetkey; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (tfm->__crt_alg->cra_type != &crypto_ahash_type) 4638c2ecf20Sopenharmony_ci return crypto_init_shash_ops_async(tfm); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci hash->init = alg->init; 4668c2ecf20Sopenharmony_ci hash->update = alg->update; 4678c2ecf20Sopenharmony_ci hash->final = alg->final; 4688c2ecf20Sopenharmony_ci hash->finup = alg->finup ?: ahash_def_finup; 4698c2ecf20Sopenharmony_ci hash->digest = alg->digest; 4708c2ecf20Sopenharmony_ci hash->export = alg->export; 4718c2ecf20Sopenharmony_ci hash->import = alg->import; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (alg->setkey) { 4748c2ecf20Sopenharmony_ci hash->setkey = alg->setkey; 4758c2ecf20Sopenharmony_ci ahash_set_needkey(hash); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (alg->exit_tfm) 4798c2ecf20Sopenharmony_ci tfm->exit = crypto_ahash_exit_tfm; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci return alg->init_tfm ? alg->init_tfm(hash) : 0; 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic unsigned int crypto_ahash_extsize(struct crypto_alg *alg) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci if (alg->cra_type != &crypto_ahash_type) 4878c2ecf20Sopenharmony_ci return sizeof(struct crypto_shash *); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return crypto_alg_extsize(alg); 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic void crypto_ahash_free_instance(struct crypto_instance *inst) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct ahash_instance *ahash = ahash_instance(inst); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ahash->free(ahash); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci#ifdef CONFIG_NET 5008c2ecf20Sopenharmony_cistatic int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct crypto_report_hash rhash; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci memset(&rhash, 0, sizeof(rhash)); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci strscpy(rhash.type, "ahash", sizeof(rhash.type)); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci rhash.blocksize = alg->cra_blocksize; 5098c2ecf20Sopenharmony_ci rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci#else 5148c2ecf20Sopenharmony_cistatic int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci return -ENOSYS; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci#endif 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) 5218c2ecf20Sopenharmony_ci __maybe_unused; 5228c2ecf20Sopenharmony_cistatic void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci seq_printf(m, "type : ahash\n"); 5258c2ecf20Sopenharmony_ci seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? 5268c2ecf20Sopenharmony_ci "yes" : "no"); 5278c2ecf20Sopenharmony_ci seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); 5288c2ecf20Sopenharmony_ci seq_printf(m, "digestsize : %u\n", 5298c2ecf20Sopenharmony_ci __crypto_hash_alg_common(alg)->digestsize); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic const struct crypto_type crypto_ahash_type = { 5338c2ecf20Sopenharmony_ci .extsize = crypto_ahash_extsize, 5348c2ecf20Sopenharmony_ci .init_tfm = crypto_ahash_init_tfm, 5358c2ecf20Sopenharmony_ci .free = crypto_ahash_free_instance, 5368c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 5378c2ecf20Sopenharmony_ci .show = crypto_ahash_show, 5388c2ecf20Sopenharmony_ci#endif 5398c2ecf20Sopenharmony_ci .report = crypto_ahash_report, 5408c2ecf20Sopenharmony_ci .maskclear = ~CRYPTO_ALG_TYPE_MASK, 5418c2ecf20Sopenharmony_ci .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, 5428c2ecf20Sopenharmony_ci .type = CRYPTO_ALG_TYPE_AHASH, 5438c2ecf20Sopenharmony_ci .tfmsize = offsetof(struct crypto_ahash, base), 5448c2ecf20Sopenharmony_ci}; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ciint crypto_grab_ahash(struct crypto_ahash_spawn *spawn, 5478c2ecf20Sopenharmony_ci struct crypto_instance *inst, 5488c2ecf20Sopenharmony_ci const char *name, u32 type, u32 mask) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci spawn->base.frontend = &crypto_ahash_type; 5518c2ecf20Sopenharmony_ci return crypto_grab_spawn(&spawn->base, inst, name, type, mask); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_grab_ahash); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistruct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, 5568c2ecf20Sopenharmony_ci u32 mask) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask); 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_alloc_ahash); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ciint crypto_has_ahash(const char *alg_name, u32 type, u32 mask) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_has_ahash); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int ahash_prepare_alg(struct ahash_alg *alg) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci struct crypto_alg *base = &alg->halg.base; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (alg->halg.digestsize > HASH_MAX_DIGESTSIZE || 5738c2ecf20Sopenharmony_ci alg->halg.statesize > HASH_MAX_STATESIZE || 5748c2ecf20Sopenharmony_ci alg->halg.statesize == 0) 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci base->cra_type = &crypto_ahash_type; 5788c2ecf20Sopenharmony_ci base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; 5798c2ecf20Sopenharmony_ci base->cra_flags |= CRYPTO_ALG_TYPE_AHASH; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci return 0; 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ciint crypto_register_ahash(struct ahash_alg *alg) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct crypto_alg *base = &alg->halg.base; 5878c2ecf20Sopenharmony_ci int err; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci err = ahash_prepare_alg(alg); 5908c2ecf20Sopenharmony_ci if (err) 5918c2ecf20Sopenharmony_ci return err; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci return crypto_register_alg(base); 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_register_ahash); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_civoid crypto_unregister_ahash(struct ahash_alg *alg) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci crypto_unregister_alg(&alg->halg.base); 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_unregister_ahash); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ciint crypto_register_ahashes(struct ahash_alg *algs, int count) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci int i, ret; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 6088c2ecf20Sopenharmony_ci ret = crypto_register_ahash(&algs[i]); 6098c2ecf20Sopenharmony_ci if (ret) 6108c2ecf20Sopenharmony_ci goto err; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cierr: 6168c2ecf20Sopenharmony_ci for (--i; i >= 0; --i) 6178c2ecf20Sopenharmony_ci crypto_unregister_ahash(&algs[i]); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return ret; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_register_ahashes); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_civoid crypto_unregister_ahashes(struct ahash_alg *algs, int count) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci int i; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci for (i = count - 1; i >= 0; --i) 6288c2ecf20Sopenharmony_ci crypto_unregister_ahash(&algs[i]); 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_unregister_ahashes); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ciint ahash_register_instance(struct crypto_template *tmpl, 6338c2ecf20Sopenharmony_ci struct ahash_instance *inst) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci int err; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (WARN_ON(!inst->free)) 6388c2ecf20Sopenharmony_ci return -EINVAL; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci err = ahash_prepare_alg(&inst->alg); 6418c2ecf20Sopenharmony_ci if (err) 6428c2ecf20Sopenharmony_ci return err; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return crypto_register_instance(tmpl, ahash_crypto_instance(inst)); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ahash_register_instance); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cibool crypto_hash_alg_has_setkey(struct hash_alg_common *halg) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct crypto_alg *alg = &halg->base; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (alg->cra_type != &crypto_ahash_type) 6538c2ecf20Sopenharmony_ci return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg)); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return __crypto_ahash_alg(alg)->setkey != NULL; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Asynchronous cryptographic hash type"); 661