18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/device.h> 78c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "common.h" 128c2ecf20Sopenharmony_ci#include "core.h" 138c2ecf20Sopenharmony_ci#include "sha.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* crypto hw padding constant for first operation */ 168c2ecf20Sopenharmony_ci#define SHA_PADDING 64 178c2ecf20Sopenharmony_ci#define SHA_PADDING_MASK (SHA_PADDING - 1) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic LIST_HEAD(ahash_algs); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic const u32 std_iv_sha1[SHA256_DIGEST_SIZE / sizeof(u32)] = { 228c2ecf20Sopenharmony_ci SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 0, 0, 0 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const u32 std_iv_sha256[SHA256_DIGEST_SIZE / sizeof(u32)] = { 268c2ecf20Sopenharmony_ci SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, 278c2ecf20Sopenharmony_ci SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic void qce_ahash_done(void *data) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct crypto_async_request *async_req = data; 338c2ecf20Sopenharmony_ci struct ahash_request *req = ahash_request_cast(async_req); 348c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 358c2ecf20Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx(req); 368c2ecf20Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm); 378c2ecf20Sopenharmony_ci struct qce_device *qce = tmpl->qce; 388c2ecf20Sopenharmony_ci struct qce_result_dump *result = qce->dma.result_buf; 398c2ecf20Sopenharmony_ci unsigned int digestsize = crypto_ahash_digestsize(ahash); 408c2ecf20Sopenharmony_ci int error; 418c2ecf20Sopenharmony_ci u32 status; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci error = qce_dma_terminate_all(&qce->dma); 448c2ecf20Sopenharmony_ci if (error) 458c2ecf20Sopenharmony_ci dev_dbg(qce->dev, "ahash dma termination error (%d)\n", error); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci dma_unmap_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE); 488c2ecf20Sopenharmony_ci dma_unmap_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci memcpy(rctx->digest, result->auth_iv, digestsize); 518c2ecf20Sopenharmony_ci if (req->result) 528c2ecf20Sopenharmony_ci memcpy(req->result, result->auth_iv, digestsize); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci rctx->byte_count[0] = cpu_to_be32(result->auth_byte_count[0]); 558c2ecf20Sopenharmony_ci rctx->byte_count[1] = cpu_to_be32(result->auth_byte_count[1]); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci error = qce_check_status(qce, &status); 588c2ecf20Sopenharmony_ci if (error < 0) 598c2ecf20Sopenharmony_ci dev_dbg(qce->dev, "ahash operation error (%x)\n", status); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci req->src = rctx->src_orig; 628c2ecf20Sopenharmony_ci req->nbytes = rctx->nbytes_orig; 638c2ecf20Sopenharmony_ci rctx->last_blk = false; 648c2ecf20Sopenharmony_ci rctx->first_blk = false; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci qce->async_req_done(tmpl->qce, error); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int qce_ahash_async_req_handle(struct crypto_async_request *async_req) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct ahash_request *req = ahash_request_cast(async_req); 728c2ecf20Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx(req); 738c2ecf20Sopenharmony_ci struct qce_sha_ctx *ctx = crypto_tfm_ctx(async_req->tfm); 748c2ecf20Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm); 758c2ecf20Sopenharmony_ci struct qce_device *qce = tmpl->qce; 768c2ecf20Sopenharmony_ci unsigned long flags = rctx->flags; 778c2ecf20Sopenharmony_ci int ret; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (IS_SHA_HMAC(flags)) { 808c2ecf20Sopenharmony_ci rctx->authkey = ctx->authkey; 818c2ecf20Sopenharmony_ci rctx->authklen = QCE_SHA_HMAC_KEY_SIZE; 828c2ecf20Sopenharmony_ci } else if (IS_CMAC(flags)) { 838c2ecf20Sopenharmony_ci rctx->authkey = ctx->authkey; 848c2ecf20Sopenharmony_ci rctx->authklen = AES_KEYSIZE_128; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci rctx->src_nents = sg_nents_for_len(req->src, req->nbytes); 888c2ecf20Sopenharmony_ci if (rctx->src_nents < 0) { 898c2ecf20Sopenharmony_ci dev_err(qce->dev, "Invalid numbers of src SG.\n"); 908c2ecf20Sopenharmony_ci return rctx->src_nents; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE); 948c2ecf20Sopenharmony_ci if (ret < 0) 958c2ecf20Sopenharmony_ci return ret; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci ret = dma_map_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE); 1008c2ecf20Sopenharmony_ci if (ret < 0) 1018c2ecf20Sopenharmony_ci goto error_unmap_src; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci ret = qce_dma_prep_sgs(&qce->dma, req->src, rctx->src_nents, 1048c2ecf20Sopenharmony_ci &rctx->result_sg, 1, qce_ahash_done, async_req); 1058c2ecf20Sopenharmony_ci if (ret) 1068c2ecf20Sopenharmony_ci goto error_unmap_dst; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci qce_dma_issue_pending(&qce->dma); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci ret = qce_start(async_req, tmpl->crypto_alg_type, 0, 0); 1118c2ecf20Sopenharmony_ci if (ret) 1128c2ecf20Sopenharmony_ci goto error_terminate; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cierror_terminate: 1178c2ecf20Sopenharmony_ci qce_dma_terminate_all(&qce->dma); 1188c2ecf20Sopenharmony_cierror_unmap_dst: 1198c2ecf20Sopenharmony_ci dma_unmap_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE); 1208c2ecf20Sopenharmony_cierror_unmap_src: 1218c2ecf20Sopenharmony_ci dma_unmap_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE); 1228c2ecf20Sopenharmony_ci return ret; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int qce_ahash_init(struct ahash_request *req) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx(req); 1288c2ecf20Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm); 1298c2ecf20Sopenharmony_ci const u32 *std_iv = tmpl->std_iv; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci memset(rctx, 0, sizeof(*rctx)); 1328c2ecf20Sopenharmony_ci rctx->first_blk = true; 1338c2ecf20Sopenharmony_ci rctx->last_blk = false; 1348c2ecf20Sopenharmony_ci rctx->flags = tmpl->alg_flags; 1358c2ecf20Sopenharmony_ci memcpy(rctx->digest, std_iv, sizeof(rctx->digest)); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic int qce_ahash_export(struct ahash_request *req, void *out) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 1438c2ecf20Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx(req); 1448c2ecf20Sopenharmony_ci unsigned long flags = rctx->flags; 1458c2ecf20Sopenharmony_ci unsigned int digestsize = crypto_ahash_digestsize(ahash); 1468c2ecf20Sopenharmony_ci unsigned int blocksize = 1478c2ecf20Sopenharmony_ci crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash)); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) { 1508c2ecf20Sopenharmony_ci struct sha1_state *out_state = out; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci out_state->count = rctx->count; 1538c2ecf20Sopenharmony_ci qce_cpu_to_be32p_array((__be32 *)out_state->state, 1548c2ecf20Sopenharmony_ci rctx->digest, digestsize); 1558c2ecf20Sopenharmony_ci memcpy(out_state->buffer, rctx->buf, blocksize); 1568c2ecf20Sopenharmony_ci } else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) { 1578c2ecf20Sopenharmony_ci struct sha256_state *out_state = out; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci out_state->count = rctx->count; 1608c2ecf20Sopenharmony_ci qce_cpu_to_be32p_array((__be32 *)out_state->state, 1618c2ecf20Sopenharmony_ci rctx->digest, digestsize); 1628c2ecf20Sopenharmony_ci memcpy(out_state->buf, rctx->buf, blocksize); 1638c2ecf20Sopenharmony_ci } else { 1648c2ecf20Sopenharmony_ci return -EINVAL; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int qce_import_common(struct ahash_request *req, u64 in_count, 1718c2ecf20Sopenharmony_ci const u32 *state, const u8 *buffer, bool hmac) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 1748c2ecf20Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx(req); 1758c2ecf20Sopenharmony_ci unsigned int digestsize = crypto_ahash_digestsize(ahash); 1768c2ecf20Sopenharmony_ci unsigned int blocksize; 1778c2ecf20Sopenharmony_ci u64 count = in_count; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash)); 1808c2ecf20Sopenharmony_ci rctx->count = in_count; 1818c2ecf20Sopenharmony_ci memcpy(rctx->buf, buffer, blocksize); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (in_count <= blocksize) { 1848c2ecf20Sopenharmony_ci rctx->first_blk = 1; 1858c2ecf20Sopenharmony_ci } else { 1868c2ecf20Sopenharmony_ci rctx->first_blk = 0; 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * For HMAC, there is a hardware padding done when first block 1898c2ecf20Sopenharmony_ci * is set. Therefore the byte_count must be incremened by 64 1908c2ecf20Sopenharmony_ci * after the first block operation. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci if (hmac) 1938c2ecf20Sopenharmony_ci count += SHA_PADDING; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci rctx->byte_count[0] = (__force __be32)(count & ~SHA_PADDING_MASK); 1978c2ecf20Sopenharmony_ci rctx->byte_count[1] = (__force __be32)(count >> 32); 1988c2ecf20Sopenharmony_ci qce_cpu_to_be32p_array((__be32 *)rctx->digest, (const u8 *)state, 1998c2ecf20Sopenharmony_ci digestsize); 2008c2ecf20Sopenharmony_ci rctx->buflen = (unsigned int)(in_count & (blocksize - 1)); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int qce_ahash_import(struct ahash_request *req, const void *in) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct qce_sha_reqctx *rctx; 2088c2ecf20Sopenharmony_ci unsigned long flags; 2098c2ecf20Sopenharmony_ci bool hmac; 2108c2ecf20Sopenharmony_ci int ret; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ret = qce_ahash_init(req); 2138c2ecf20Sopenharmony_ci if (ret) 2148c2ecf20Sopenharmony_ci return ret; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci rctx = ahash_request_ctx(req); 2178c2ecf20Sopenharmony_ci flags = rctx->flags; 2188c2ecf20Sopenharmony_ci hmac = IS_SHA_HMAC(flags); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) { 2218c2ecf20Sopenharmony_ci const struct sha1_state *state = in; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ret = qce_import_common(req, state->count, state->state, 2248c2ecf20Sopenharmony_ci state->buffer, hmac); 2258c2ecf20Sopenharmony_ci } else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) { 2268c2ecf20Sopenharmony_ci const struct sha256_state *state = in; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ret = qce_import_common(req, state->count, state->state, 2298c2ecf20Sopenharmony_ci state->buf, hmac); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int qce_ahash_update(struct ahash_request *req) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 2388c2ecf20Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx(req); 2398c2ecf20Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm); 2408c2ecf20Sopenharmony_ci struct qce_device *qce = tmpl->qce; 2418c2ecf20Sopenharmony_ci struct scatterlist *sg_last, *sg; 2428c2ecf20Sopenharmony_ci unsigned int total, len; 2438c2ecf20Sopenharmony_ci unsigned int hash_later; 2448c2ecf20Sopenharmony_ci unsigned int nbytes; 2458c2ecf20Sopenharmony_ci unsigned int blocksize; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 2488c2ecf20Sopenharmony_ci rctx->count += req->nbytes; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* check for buffer from previous updates and append it */ 2518c2ecf20Sopenharmony_ci total = req->nbytes + rctx->buflen; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (total <= blocksize) { 2548c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(rctx->buf + rctx->buflen, req->src, 2558c2ecf20Sopenharmony_ci 0, req->nbytes, 0); 2568c2ecf20Sopenharmony_ci rctx->buflen += req->nbytes; 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* save the original req structure fields */ 2618c2ecf20Sopenharmony_ci rctx->src_orig = req->src; 2628c2ecf20Sopenharmony_ci rctx->nbytes_orig = req->nbytes; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * if we have data from previous update copy them on buffer. The old 2668c2ecf20Sopenharmony_ci * data will be combined with current request bytes. 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci if (rctx->buflen) 2698c2ecf20Sopenharmony_ci memcpy(rctx->tmpbuf, rctx->buf, rctx->buflen); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* calculate how many bytes will be hashed later */ 2728c2ecf20Sopenharmony_ci hash_later = total % blocksize; 2738c2ecf20Sopenharmony_ci if (hash_later) { 2748c2ecf20Sopenharmony_ci unsigned int src_offset = req->nbytes - hash_later; 2758c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(rctx->buf, req->src, src_offset, 2768c2ecf20Sopenharmony_ci hash_later, 0); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* here nbytes is multiple of blocksize */ 2808c2ecf20Sopenharmony_ci nbytes = total - hash_later; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci len = rctx->buflen; 2838c2ecf20Sopenharmony_ci sg = sg_last = req->src; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci while (len < nbytes && sg) { 2868c2ecf20Sopenharmony_ci if (len + sg_dma_len(sg) > nbytes) 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci len += sg_dma_len(sg); 2898c2ecf20Sopenharmony_ci sg_last = sg; 2908c2ecf20Sopenharmony_ci sg = sg_next(sg); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (!sg_last) 2948c2ecf20Sopenharmony_ci return -EINVAL; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (rctx->buflen) { 2978c2ecf20Sopenharmony_ci sg_init_table(rctx->sg, 2); 2988c2ecf20Sopenharmony_ci sg_set_buf(rctx->sg, rctx->tmpbuf, rctx->buflen); 2998c2ecf20Sopenharmony_ci sg_chain(rctx->sg, 2, req->src); 3008c2ecf20Sopenharmony_ci req->src = rctx->sg; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci req->nbytes = nbytes; 3048c2ecf20Sopenharmony_ci rctx->buflen = hash_later; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return qce->async_req_enqueue(tmpl->qce, &req->base); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int qce_ahash_final(struct ahash_request *req) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx(req); 3128c2ecf20Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm); 3138c2ecf20Sopenharmony_ci struct qce_device *qce = tmpl->qce; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (!rctx->buflen) { 3168c2ecf20Sopenharmony_ci if (tmpl->hash_zero) 3178c2ecf20Sopenharmony_ci memcpy(req->result, tmpl->hash_zero, 3188c2ecf20Sopenharmony_ci tmpl->alg.ahash.halg.digestsize); 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci rctx->last_blk = true; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci rctx->src_orig = req->src; 3258c2ecf20Sopenharmony_ci rctx->nbytes_orig = req->nbytes; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci memcpy(rctx->tmpbuf, rctx->buf, rctx->buflen); 3288c2ecf20Sopenharmony_ci sg_init_one(rctx->sg, rctx->tmpbuf, rctx->buflen); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci req->src = rctx->sg; 3318c2ecf20Sopenharmony_ci req->nbytes = rctx->buflen; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return qce->async_req_enqueue(tmpl->qce, &req->base); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic int qce_ahash_digest(struct ahash_request *req) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx(req); 3398c2ecf20Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm); 3408c2ecf20Sopenharmony_ci struct qce_device *qce = tmpl->qce; 3418c2ecf20Sopenharmony_ci int ret; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ret = qce_ahash_init(req); 3448c2ecf20Sopenharmony_ci if (ret) 3458c2ecf20Sopenharmony_ci return ret; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci rctx->src_orig = req->src; 3488c2ecf20Sopenharmony_ci rctx->nbytes_orig = req->nbytes; 3498c2ecf20Sopenharmony_ci rctx->first_blk = true; 3508c2ecf20Sopenharmony_ci rctx->last_blk = true; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (!rctx->nbytes_orig) { 3538c2ecf20Sopenharmony_ci if (tmpl->hash_zero) 3548c2ecf20Sopenharmony_ci memcpy(req->result, tmpl->hash_zero, 3558c2ecf20Sopenharmony_ci tmpl->alg.ahash.halg.digestsize); 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci return qce->async_req_enqueue(tmpl->qce, &req->base); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int qce_ahash_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, 3638c2ecf20Sopenharmony_ci unsigned int keylen) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci unsigned int digestsize = crypto_ahash_digestsize(tfm); 3668c2ecf20Sopenharmony_ci struct qce_sha_ctx *ctx = crypto_tfm_ctx(&tfm->base); 3678c2ecf20Sopenharmony_ci struct crypto_wait wait; 3688c2ecf20Sopenharmony_ci struct ahash_request *req; 3698c2ecf20Sopenharmony_ci struct scatterlist sg; 3708c2ecf20Sopenharmony_ci unsigned int blocksize; 3718c2ecf20Sopenharmony_ci struct crypto_ahash *ahash_tfm; 3728c2ecf20Sopenharmony_ci u8 *buf; 3738c2ecf20Sopenharmony_ci int ret; 3748c2ecf20Sopenharmony_ci const char *alg_name; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 3778c2ecf20Sopenharmony_ci memset(ctx->authkey, 0, sizeof(ctx->authkey)); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (keylen <= blocksize) { 3808c2ecf20Sopenharmony_ci memcpy(ctx->authkey, key, keylen); 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (digestsize == SHA1_DIGEST_SIZE) 3858c2ecf20Sopenharmony_ci alg_name = "sha1-qce"; 3868c2ecf20Sopenharmony_ci else if (digestsize == SHA256_DIGEST_SIZE) 3878c2ecf20Sopenharmony_ci alg_name = "sha256-qce"; 3888c2ecf20Sopenharmony_ci else 3898c2ecf20Sopenharmony_ci return -EINVAL; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ahash_tfm = crypto_alloc_ahash(alg_name, 0, 0); 3928c2ecf20Sopenharmony_ci if (IS_ERR(ahash_tfm)) 3938c2ecf20Sopenharmony_ci return PTR_ERR(ahash_tfm); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci req = ahash_request_alloc(ahash_tfm, GFP_KERNEL); 3968c2ecf20Sopenharmony_ci if (!req) { 3978c2ecf20Sopenharmony_ci ret = -ENOMEM; 3988c2ecf20Sopenharmony_ci goto err_free_ahash; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci crypto_init_wait(&wait); 4028c2ecf20Sopenharmony_ci ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 4038c2ecf20Sopenharmony_ci crypto_req_done, &wait); 4048c2ecf20Sopenharmony_ci crypto_ahash_clear_flags(ahash_tfm, ~0); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci buf = kzalloc(keylen + QCE_MAX_ALIGN_SIZE, GFP_KERNEL); 4078c2ecf20Sopenharmony_ci if (!buf) { 4088c2ecf20Sopenharmony_ci ret = -ENOMEM; 4098c2ecf20Sopenharmony_ci goto err_free_req; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci memcpy(buf, key, keylen); 4138c2ecf20Sopenharmony_ci sg_init_one(&sg, buf, keylen); 4148c2ecf20Sopenharmony_ci ahash_request_set_crypt(req, &sg, ctx->authkey, keylen); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci ret = crypto_wait_req(crypto_ahash_digest(req), &wait); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci kfree(buf); 4198c2ecf20Sopenharmony_cierr_free_req: 4208c2ecf20Sopenharmony_ci ahash_request_free(req); 4218c2ecf20Sopenharmony_cierr_free_ahash: 4228c2ecf20Sopenharmony_ci crypto_free_ahash(ahash_tfm); 4238c2ecf20Sopenharmony_ci return ret; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int qce_ahash_cra_init(struct crypto_tfm *tfm) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 4298c2ecf20Sopenharmony_ci struct qce_sha_ctx *ctx = crypto_tfm_ctx(tfm); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci crypto_ahash_set_reqsize(ahash, sizeof(struct qce_sha_reqctx)); 4328c2ecf20Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 4338c2ecf20Sopenharmony_ci return 0; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistruct qce_ahash_def { 4378c2ecf20Sopenharmony_ci unsigned long flags; 4388c2ecf20Sopenharmony_ci const char *name; 4398c2ecf20Sopenharmony_ci const char *drv_name; 4408c2ecf20Sopenharmony_ci unsigned int digestsize; 4418c2ecf20Sopenharmony_ci unsigned int blocksize; 4428c2ecf20Sopenharmony_ci unsigned int statesize; 4438c2ecf20Sopenharmony_ci const u32 *std_iv; 4448c2ecf20Sopenharmony_ci}; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic const struct qce_ahash_def ahash_def[] = { 4478c2ecf20Sopenharmony_ci { 4488c2ecf20Sopenharmony_ci .flags = QCE_HASH_SHA1, 4498c2ecf20Sopenharmony_ci .name = "sha1", 4508c2ecf20Sopenharmony_ci .drv_name = "sha1-qce", 4518c2ecf20Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 4528c2ecf20Sopenharmony_ci .blocksize = SHA1_BLOCK_SIZE, 4538c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha1_state), 4548c2ecf20Sopenharmony_ci .std_iv = std_iv_sha1, 4558c2ecf20Sopenharmony_ci }, 4568c2ecf20Sopenharmony_ci { 4578c2ecf20Sopenharmony_ci .flags = QCE_HASH_SHA256, 4588c2ecf20Sopenharmony_ci .name = "sha256", 4598c2ecf20Sopenharmony_ci .drv_name = "sha256-qce", 4608c2ecf20Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 4618c2ecf20Sopenharmony_ci .blocksize = SHA256_BLOCK_SIZE, 4628c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha256_state), 4638c2ecf20Sopenharmony_ci .std_iv = std_iv_sha256, 4648c2ecf20Sopenharmony_ci }, 4658c2ecf20Sopenharmony_ci { 4668c2ecf20Sopenharmony_ci .flags = QCE_HASH_SHA1_HMAC, 4678c2ecf20Sopenharmony_ci .name = "hmac(sha1)", 4688c2ecf20Sopenharmony_ci .drv_name = "hmac-sha1-qce", 4698c2ecf20Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 4708c2ecf20Sopenharmony_ci .blocksize = SHA1_BLOCK_SIZE, 4718c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha1_state), 4728c2ecf20Sopenharmony_ci .std_iv = std_iv_sha1, 4738c2ecf20Sopenharmony_ci }, 4748c2ecf20Sopenharmony_ci { 4758c2ecf20Sopenharmony_ci .flags = QCE_HASH_SHA256_HMAC, 4768c2ecf20Sopenharmony_ci .name = "hmac(sha256)", 4778c2ecf20Sopenharmony_ci .drv_name = "hmac-sha256-qce", 4788c2ecf20Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 4798c2ecf20Sopenharmony_ci .blocksize = SHA256_BLOCK_SIZE, 4808c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha256_state), 4818c2ecf20Sopenharmony_ci .std_iv = std_iv_sha256, 4828c2ecf20Sopenharmony_ci }, 4838c2ecf20Sopenharmony_ci}; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic int qce_ahash_register_one(const struct qce_ahash_def *def, 4868c2ecf20Sopenharmony_ci struct qce_device *qce) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci struct qce_alg_template *tmpl; 4898c2ecf20Sopenharmony_ci struct ahash_alg *alg; 4908c2ecf20Sopenharmony_ci struct crypto_alg *base; 4918c2ecf20Sopenharmony_ci int ret; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); 4948c2ecf20Sopenharmony_ci if (!tmpl) 4958c2ecf20Sopenharmony_ci return -ENOMEM; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci tmpl->std_iv = def->std_iv; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci alg = &tmpl->alg.ahash; 5008c2ecf20Sopenharmony_ci alg->init = qce_ahash_init; 5018c2ecf20Sopenharmony_ci alg->update = qce_ahash_update; 5028c2ecf20Sopenharmony_ci alg->final = qce_ahash_final; 5038c2ecf20Sopenharmony_ci alg->digest = qce_ahash_digest; 5048c2ecf20Sopenharmony_ci alg->export = qce_ahash_export; 5058c2ecf20Sopenharmony_ci alg->import = qce_ahash_import; 5068c2ecf20Sopenharmony_ci if (IS_SHA_HMAC(def->flags)) 5078c2ecf20Sopenharmony_ci alg->setkey = qce_ahash_hmac_setkey; 5088c2ecf20Sopenharmony_ci alg->halg.digestsize = def->digestsize; 5098c2ecf20Sopenharmony_ci alg->halg.statesize = def->statesize; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (IS_SHA1(def->flags)) 5128c2ecf20Sopenharmony_ci tmpl->hash_zero = sha1_zero_message_hash; 5138c2ecf20Sopenharmony_ci else if (IS_SHA256(def->flags)) 5148c2ecf20Sopenharmony_ci tmpl->hash_zero = sha256_zero_message_hash; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci base = &alg->halg.base; 5178c2ecf20Sopenharmony_ci base->cra_blocksize = def->blocksize; 5188c2ecf20Sopenharmony_ci base->cra_priority = 300; 5198c2ecf20Sopenharmony_ci base->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY; 5208c2ecf20Sopenharmony_ci base->cra_ctxsize = sizeof(struct qce_sha_ctx); 5218c2ecf20Sopenharmony_ci base->cra_alignmask = 0; 5228c2ecf20Sopenharmony_ci base->cra_module = THIS_MODULE; 5238c2ecf20Sopenharmony_ci base->cra_init = qce_ahash_cra_init; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name); 5268c2ecf20Sopenharmony_ci snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 5278c2ecf20Sopenharmony_ci def->drv_name); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tmpl->entry); 5308c2ecf20Sopenharmony_ci tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_AHASH; 5318c2ecf20Sopenharmony_ci tmpl->alg_flags = def->flags; 5328c2ecf20Sopenharmony_ci tmpl->qce = qce; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci ret = crypto_register_ahash(alg); 5358c2ecf20Sopenharmony_ci if (ret) { 5368c2ecf20Sopenharmony_ci dev_err(qce->dev, "%s registration failed\n", base->cra_name); 5378c2ecf20Sopenharmony_ci kfree(tmpl); 5388c2ecf20Sopenharmony_ci return ret; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci list_add_tail(&tmpl->entry, &ahash_algs); 5428c2ecf20Sopenharmony_ci dev_dbg(qce->dev, "%s is registered\n", base->cra_name); 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void qce_ahash_unregister(struct qce_device *qce) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct qce_alg_template *tmpl, *n; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci list_for_each_entry_safe(tmpl, n, &ahash_algs, entry) { 5518c2ecf20Sopenharmony_ci crypto_unregister_ahash(&tmpl->alg.ahash); 5528c2ecf20Sopenharmony_ci list_del(&tmpl->entry); 5538c2ecf20Sopenharmony_ci kfree(tmpl); 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic int qce_ahash_register(struct qce_device *qce) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci int ret, i; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ahash_def); i++) { 5628c2ecf20Sopenharmony_ci ret = qce_ahash_register_one(&ahash_def[i], qce); 5638c2ecf20Sopenharmony_ci if (ret) 5648c2ecf20Sopenharmony_ci goto err; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_cierr: 5698c2ecf20Sopenharmony_ci qce_ahash_unregister(qce); 5708c2ecf20Sopenharmony_ci return ret; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ciconst struct qce_algo_ops ahash_ops = { 5748c2ecf20Sopenharmony_ci .type = CRYPTO_ALG_TYPE_AHASH, 5758c2ecf20Sopenharmony_ci .register_algs = qce_ahash_register, 5768c2ecf20Sopenharmony_ci .unregister_algs = qce_ahash_unregister, 5778c2ecf20Sopenharmony_ci .async_req_handle = qce_ahash_async_req_handle, 5788c2ecf20Sopenharmony_ci}; 579