162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AMD Cryptographic Coprocessor (CCP) SHA crypto API support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013,2018 Advanced Micro Devices, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Tom Lendacky <thomas.lendacky@amd.com> 862306a36Sopenharmony_ci * Author: Gary R Hook <gary.hook@amd.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/sched.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/scatterlist.h> 1562306a36Sopenharmony_ci#include <linux/crypto.h> 1662306a36Sopenharmony_ci#include <crypto/algapi.h> 1762306a36Sopenharmony_ci#include <crypto/hash.h> 1862306a36Sopenharmony_ci#include <crypto/hmac.h> 1962306a36Sopenharmony_ci#include <crypto/internal/hash.h> 2062306a36Sopenharmony_ci#include <crypto/sha1.h> 2162306a36Sopenharmony_ci#include <crypto/sha2.h> 2262306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 2362306a36Sopenharmony_ci#include <linux/string.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "ccp-crypto.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int ccp_sha_complete(struct crypto_async_request *async_req, int ret) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct ahash_request *req = ahash_request_cast(async_req); 3062306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 3162306a36Sopenharmony_ci struct ccp_sha_req_ctx *rctx = ahash_request_ctx_dma(req); 3262306a36Sopenharmony_ci unsigned int digest_size = crypto_ahash_digestsize(tfm); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (ret) 3562306a36Sopenharmony_ci goto e_free; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (rctx->hash_rem) { 3862306a36Sopenharmony_ci /* Save remaining data to buffer */ 3962306a36Sopenharmony_ci unsigned int offset = rctx->nbytes - rctx->hash_rem; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci scatterwalk_map_and_copy(rctx->buf, rctx->src, 4262306a36Sopenharmony_ci offset, rctx->hash_rem, 0); 4362306a36Sopenharmony_ci rctx->buf_count = rctx->hash_rem; 4462306a36Sopenharmony_ci } else { 4562306a36Sopenharmony_ci rctx->buf_count = 0; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Update result area if supplied */ 4962306a36Sopenharmony_ci if (req->result && rctx->final) 5062306a36Sopenharmony_ci memcpy(req->result, rctx->ctx, digest_size); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cie_free: 5362306a36Sopenharmony_ci sg_free_table(&rctx->data_sg); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return ret; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int ccp_do_sha_update(struct ahash_request *req, unsigned int nbytes, 5962306a36Sopenharmony_ci unsigned int final) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 6262306a36Sopenharmony_ci struct ccp_ctx *ctx = crypto_ahash_ctx_dma(tfm); 6362306a36Sopenharmony_ci struct ccp_sha_req_ctx *rctx = ahash_request_ctx_dma(req); 6462306a36Sopenharmony_ci struct scatterlist *sg; 6562306a36Sopenharmony_ci unsigned int block_size = 6662306a36Sopenharmony_ci crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 6762306a36Sopenharmony_ci unsigned int sg_count; 6862306a36Sopenharmony_ci gfp_t gfp; 6962306a36Sopenharmony_ci u64 len; 7062306a36Sopenharmony_ci int ret; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci len = (u64)rctx->buf_count + (u64)nbytes; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!final && (len <= block_size)) { 7562306a36Sopenharmony_ci scatterwalk_map_and_copy(rctx->buf + rctx->buf_count, req->src, 7662306a36Sopenharmony_ci 0, nbytes, 0); 7762306a36Sopenharmony_ci rctx->buf_count += nbytes; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci rctx->src = req->src; 8362306a36Sopenharmony_ci rctx->nbytes = nbytes; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci rctx->final = final; 8662306a36Sopenharmony_ci rctx->hash_rem = final ? 0 : len & (block_size - 1); 8762306a36Sopenharmony_ci rctx->hash_cnt = len - rctx->hash_rem; 8862306a36Sopenharmony_ci if (!final && !rctx->hash_rem) { 8962306a36Sopenharmony_ci /* CCP can't do zero length final, so keep some data around */ 9062306a36Sopenharmony_ci rctx->hash_cnt -= block_size; 9162306a36Sopenharmony_ci rctx->hash_rem = block_size; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* Initialize the context scatterlist */ 9562306a36Sopenharmony_ci sg_init_one(&rctx->ctx_sg, rctx->ctx, sizeof(rctx->ctx)); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci sg = NULL; 9862306a36Sopenharmony_ci if (rctx->buf_count && nbytes) { 9962306a36Sopenharmony_ci /* Build the data scatterlist table - allocate enough entries 10062306a36Sopenharmony_ci * for both data pieces (buffer and input data) 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? 10362306a36Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 10462306a36Sopenharmony_ci sg_count = sg_nents(req->src) + 1; 10562306a36Sopenharmony_ci ret = sg_alloc_table(&rctx->data_sg, sg_count, gfp); 10662306a36Sopenharmony_ci if (ret) 10762306a36Sopenharmony_ci return ret; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci sg_init_one(&rctx->buf_sg, rctx->buf, rctx->buf_count); 11062306a36Sopenharmony_ci sg = ccp_crypto_sg_table_add(&rctx->data_sg, &rctx->buf_sg); 11162306a36Sopenharmony_ci if (!sg) { 11262306a36Sopenharmony_ci ret = -EINVAL; 11362306a36Sopenharmony_ci goto e_free; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci sg = ccp_crypto_sg_table_add(&rctx->data_sg, req->src); 11662306a36Sopenharmony_ci if (!sg) { 11762306a36Sopenharmony_ci ret = -EINVAL; 11862306a36Sopenharmony_ci goto e_free; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci sg_mark_end(sg); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci sg = rctx->data_sg.sgl; 12362306a36Sopenharmony_ci } else if (rctx->buf_count) { 12462306a36Sopenharmony_ci sg_init_one(&rctx->buf_sg, rctx->buf, rctx->buf_count); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci sg = &rctx->buf_sg; 12762306a36Sopenharmony_ci } else if (nbytes) { 12862306a36Sopenharmony_ci sg = req->src; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci rctx->msg_bits += (rctx->hash_cnt << 3); /* Total in bits */ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci memset(&rctx->cmd, 0, sizeof(rctx->cmd)); 13462306a36Sopenharmony_ci INIT_LIST_HEAD(&rctx->cmd.entry); 13562306a36Sopenharmony_ci rctx->cmd.engine = CCP_ENGINE_SHA; 13662306a36Sopenharmony_ci rctx->cmd.u.sha.type = rctx->type; 13762306a36Sopenharmony_ci rctx->cmd.u.sha.ctx = &rctx->ctx_sg; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci switch (rctx->type) { 14062306a36Sopenharmony_ci case CCP_SHA_TYPE_1: 14162306a36Sopenharmony_ci rctx->cmd.u.sha.ctx_len = SHA1_DIGEST_SIZE; 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci case CCP_SHA_TYPE_224: 14462306a36Sopenharmony_ci rctx->cmd.u.sha.ctx_len = SHA224_DIGEST_SIZE; 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci case CCP_SHA_TYPE_256: 14762306a36Sopenharmony_ci rctx->cmd.u.sha.ctx_len = SHA256_DIGEST_SIZE; 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci case CCP_SHA_TYPE_384: 15062306a36Sopenharmony_ci rctx->cmd.u.sha.ctx_len = SHA384_DIGEST_SIZE; 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci case CCP_SHA_TYPE_512: 15362306a36Sopenharmony_ci rctx->cmd.u.sha.ctx_len = SHA512_DIGEST_SIZE; 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci default: 15662306a36Sopenharmony_ci /* Should never get here */ 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci rctx->cmd.u.sha.src = sg; 16162306a36Sopenharmony_ci rctx->cmd.u.sha.src_len = rctx->hash_cnt; 16262306a36Sopenharmony_ci rctx->cmd.u.sha.opad = ctx->u.sha.key_len ? 16362306a36Sopenharmony_ci &ctx->u.sha.opad_sg : NULL; 16462306a36Sopenharmony_ci rctx->cmd.u.sha.opad_len = ctx->u.sha.key_len ? 16562306a36Sopenharmony_ci ctx->u.sha.opad_count : 0; 16662306a36Sopenharmony_ci rctx->cmd.u.sha.first = rctx->first; 16762306a36Sopenharmony_ci rctx->cmd.u.sha.final = rctx->final; 16862306a36Sopenharmony_ci rctx->cmd.u.sha.msg_bits = rctx->msg_bits; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci rctx->first = 0; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ret = ccp_crypto_enqueue_request(&req->base, &rctx->cmd); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return ret; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cie_free: 17762306a36Sopenharmony_ci sg_free_table(&rctx->data_sg); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return ret; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int ccp_sha_init(struct ahash_request *req) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 18562306a36Sopenharmony_ci struct ccp_ctx *ctx = crypto_ahash_ctx_dma(tfm); 18662306a36Sopenharmony_ci struct ccp_sha_req_ctx *rctx = ahash_request_ctx_dma(req); 18762306a36Sopenharmony_ci struct ccp_crypto_ahash_alg *alg = 18862306a36Sopenharmony_ci ccp_crypto_ahash_alg(crypto_ahash_tfm(tfm)); 18962306a36Sopenharmony_ci unsigned int block_size = 19062306a36Sopenharmony_ci crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci memset(rctx, 0, sizeof(*rctx)); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci rctx->type = alg->type; 19562306a36Sopenharmony_ci rctx->first = 1; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (ctx->u.sha.key_len) { 19862306a36Sopenharmony_ci /* Buffer the HMAC key for first update */ 19962306a36Sopenharmony_ci memcpy(rctx->buf, ctx->u.sha.ipad, block_size); 20062306a36Sopenharmony_ci rctx->buf_count = block_size; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int ccp_sha_update(struct ahash_request *req) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci return ccp_do_sha_update(req, req->nbytes, 0); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int ccp_sha_final(struct ahash_request *req) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci return ccp_do_sha_update(req, 0, 1); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int ccp_sha_finup(struct ahash_request *req) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci return ccp_do_sha_update(req, req->nbytes, 1); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int ccp_sha_digest(struct ahash_request *req) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci int ret; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ret = ccp_sha_init(req); 22662306a36Sopenharmony_ci if (ret) 22762306a36Sopenharmony_ci return ret; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return ccp_sha_finup(req); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int ccp_sha_export(struct ahash_request *req, void *out) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct ccp_sha_req_ctx *rctx = ahash_request_ctx_dma(req); 23562306a36Sopenharmony_ci struct ccp_sha_exp_ctx state; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Don't let anything leak to 'out' */ 23862306a36Sopenharmony_ci memset(&state, 0, sizeof(state)); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci state.type = rctx->type; 24162306a36Sopenharmony_ci state.msg_bits = rctx->msg_bits; 24262306a36Sopenharmony_ci state.first = rctx->first; 24362306a36Sopenharmony_ci memcpy(state.ctx, rctx->ctx, sizeof(state.ctx)); 24462306a36Sopenharmony_ci state.buf_count = rctx->buf_count; 24562306a36Sopenharmony_ci memcpy(state.buf, rctx->buf, sizeof(state.buf)); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* 'out' may not be aligned so memcpy from local variable */ 24862306a36Sopenharmony_ci memcpy(out, &state, sizeof(state)); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int ccp_sha_import(struct ahash_request *req, const void *in) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct ccp_sha_req_ctx *rctx = ahash_request_ctx_dma(req); 25662306a36Sopenharmony_ci struct ccp_sha_exp_ctx state; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* 'in' may not be aligned so memcpy to local variable */ 25962306a36Sopenharmony_ci memcpy(&state, in, sizeof(state)); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci memset(rctx, 0, sizeof(*rctx)); 26262306a36Sopenharmony_ci rctx->type = state.type; 26362306a36Sopenharmony_ci rctx->msg_bits = state.msg_bits; 26462306a36Sopenharmony_ci rctx->first = state.first; 26562306a36Sopenharmony_ci memcpy(rctx->ctx, state.ctx, sizeof(rctx->ctx)); 26662306a36Sopenharmony_ci rctx->buf_count = state.buf_count; 26762306a36Sopenharmony_ci memcpy(rctx->buf, state.buf, sizeof(rctx->buf)); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key, 27362306a36Sopenharmony_ci unsigned int key_len) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct ccp_ctx *ctx = crypto_ahash_ctx_dma(tfm); 27662306a36Sopenharmony_ci struct crypto_shash *shash = ctx->u.sha.hmac_tfm; 27762306a36Sopenharmony_ci unsigned int block_size = crypto_shash_blocksize(shash); 27862306a36Sopenharmony_ci unsigned int digest_size = crypto_shash_digestsize(shash); 27962306a36Sopenharmony_ci int i, ret; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Set to zero until complete */ 28262306a36Sopenharmony_ci ctx->u.sha.key_len = 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Clear key area to provide zero padding for keys smaller 28562306a36Sopenharmony_ci * than the block size 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci memset(ctx->u.sha.key, 0, sizeof(ctx->u.sha.key)); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (key_len > block_size) { 29062306a36Sopenharmony_ci /* Must hash the input key */ 29162306a36Sopenharmony_ci ret = crypto_shash_tfm_digest(shash, key, key_len, 29262306a36Sopenharmony_ci ctx->u.sha.key); 29362306a36Sopenharmony_ci if (ret) 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci key_len = digest_size; 29762306a36Sopenharmony_ci } else { 29862306a36Sopenharmony_ci memcpy(ctx->u.sha.key, key, key_len); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci for (i = 0; i < block_size; i++) { 30262306a36Sopenharmony_ci ctx->u.sha.ipad[i] = ctx->u.sha.key[i] ^ HMAC_IPAD_VALUE; 30362306a36Sopenharmony_ci ctx->u.sha.opad[i] = ctx->u.sha.key[i] ^ HMAC_OPAD_VALUE; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci sg_init_one(&ctx->u.sha.opad_sg, ctx->u.sha.opad, block_size); 30762306a36Sopenharmony_ci ctx->u.sha.opad_count = block_size; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci ctx->u.sha.key_len = key_len; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int ccp_sha_cra_init(struct crypto_tfm *tfm) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 31762306a36Sopenharmony_ci struct ccp_ctx *ctx = crypto_ahash_ctx_dma(ahash); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci ctx->complete = ccp_sha_complete; 32062306a36Sopenharmony_ci ctx->u.sha.key_len = 0; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci crypto_ahash_set_reqsize_dma(ahash, sizeof(struct ccp_sha_req_ctx)); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void ccp_sha_cra_exit(struct crypto_tfm *tfm) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int ccp_hmac_sha_cra_init(struct crypto_tfm *tfm) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct ccp_ctx *ctx = crypto_tfm_ctx_dma(tfm); 33462306a36Sopenharmony_ci struct ccp_crypto_ahash_alg *alg = ccp_crypto_ahash_alg(tfm); 33562306a36Sopenharmony_ci struct crypto_shash *hmac_tfm; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci hmac_tfm = crypto_alloc_shash(alg->child_alg, 0, 0); 33862306a36Sopenharmony_ci if (IS_ERR(hmac_tfm)) { 33962306a36Sopenharmony_ci pr_warn("could not load driver %s need for HMAC support\n", 34062306a36Sopenharmony_ci alg->child_alg); 34162306a36Sopenharmony_ci return PTR_ERR(hmac_tfm); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ctx->u.sha.hmac_tfm = hmac_tfm; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return ccp_sha_cra_init(tfm); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic void ccp_hmac_sha_cra_exit(struct crypto_tfm *tfm) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct ccp_ctx *ctx = crypto_tfm_ctx_dma(tfm); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (ctx->u.sha.hmac_tfm) 35462306a36Sopenharmony_ci crypto_free_shash(ctx->u.sha.hmac_tfm); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci ccp_sha_cra_exit(tfm); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistruct ccp_sha_def { 36062306a36Sopenharmony_ci unsigned int version; 36162306a36Sopenharmony_ci const char *name; 36262306a36Sopenharmony_ci const char *drv_name; 36362306a36Sopenharmony_ci enum ccp_sha_type type; 36462306a36Sopenharmony_ci u32 digest_size; 36562306a36Sopenharmony_ci u32 block_size; 36662306a36Sopenharmony_ci}; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic struct ccp_sha_def sha_algs[] = { 36962306a36Sopenharmony_ci { 37062306a36Sopenharmony_ci .version = CCP_VERSION(3, 0), 37162306a36Sopenharmony_ci .name = "sha1", 37262306a36Sopenharmony_ci .drv_name = "sha1-ccp", 37362306a36Sopenharmony_ci .type = CCP_SHA_TYPE_1, 37462306a36Sopenharmony_ci .digest_size = SHA1_DIGEST_SIZE, 37562306a36Sopenharmony_ci .block_size = SHA1_BLOCK_SIZE, 37662306a36Sopenharmony_ci }, 37762306a36Sopenharmony_ci { 37862306a36Sopenharmony_ci .version = CCP_VERSION(3, 0), 37962306a36Sopenharmony_ci .name = "sha224", 38062306a36Sopenharmony_ci .drv_name = "sha224-ccp", 38162306a36Sopenharmony_ci .type = CCP_SHA_TYPE_224, 38262306a36Sopenharmony_ci .digest_size = SHA224_DIGEST_SIZE, 38362306a36Sopenharmony_ci .block_size = SHA224_BLOCK_SIZE, 38462306a36Sopenharmony_ci }, 38562306a36Sopenharmony_ci { 38662306a36Sopenharmony_ci .version = CCP_VERSION(3, 0), 38762306a36Sopenharmony_ci .name = "sha256", 38862306a36Sopenharmony_ci .drv_name = "sha256-ccp", 38962306a36Sopenharmony_ci .type = CCP_SHA_TYPE_256, 39062306a36Sopenharmony_ci .digest_size = SHA256_DIGEST_SIZE, 39162306a36Sopenharmony_ci .block_size = SHA256_BLOCK_SIZE, 39262306a36Sopenharmony_ci }, 39362306a36Sopenharmony_ci { 39462306a36Sopenharmony_ci .version = CCP_VERSION(5, 0), 39562306a36Sopenharmony_ci .name = "sha384", 39662306a36Sopenharmony_ci .drv_name = "sha384-ccp", 39762306a36Sopenharmony_ci .type = CCP_SHA_TYPE_384, 39862306a36Sopenharmony_ci .digest_size = SHA384_DIGEST_SIZE, 39962306a36Sopenharmony_ci .block_size = SHA384_BLOCK_SIZE, 40062306a36Sopenharmony_ci }, 40162306a36Sopenharmony_ci { 40262306a36Sopenharmony_ci .version = CCP_VERSION(5, 0), 40362306a36Sopenharmony_ci .name = "sha512", 40462306a36Sopenharmony_ci .drv_name = "sha512-ccp", 40562306a36Sopenharmony_ci .type = CCP_SHA_TYPE_512, 40662306a36Sopenharmony_ci .digest_size = SHA512_DIGEST_SIZE, 40762306a36Sopenharmony_ci .block_size = SHA512_BLOCK_SIZE, 40862306a36Sopenharmony_ci }, 40962306a36Sopenharmony_ci}; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int ccp_register_hmac_alg(struct list_head *head, 41262306a36Sopenharmony_ci const struct ccp_sha_def *def, 41362306a36Sopenharmony_ci const struct ccp_crypto_ahash_alg *base_alg) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct ccp_crypto_ahash_alg *ccp_alg; 41662306a36Sopenharmony_ci struct ahash_alg *alg; 41762306a36Sopenharmony_ci struct hash_alg_common *halg; 41862306a36Sopenharmony_ci struct crypto_alg *base; 41962306a36Sopenharmony_ci int ret; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci ccp_alg = kzalloc(sizeof(*ccp_alg), GFP_KERNEL); 42262306a36Sopenharmony_ci if (!ccp_alg) 42362306a36Sopenharmony_ci return -ENOMEM; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Copy the base algorithm and only change what's necessary */ 42662306a36Sopenharmony_ci *ccp_alg = *base_alg; 42762306a36Sopenharmony_ci INIT_LIST_HEAD(&ccp_alg->entry); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci strscpy(ccp_alg->child_alg, def->name, CRYPTO_MAX_ALG_NAME); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci alg = &ccp_alg->alg; 43262306a36Sopenharmony_ci alg->setkey = ccp_sha_setkey; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci halg = &alg->halg; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci base = &halg->base; 43762306a36Sopenharmony_ci snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", def->name); 43862306a36Sopenharmony_ci snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s", 43962306a36Sopenharmony_ci def->drv_name); 44062306a36Sopenharmony_ci base->cra_init = ccp_hmac_sha_cra_init; 44162306a36Sopenharmony_ci base->cra_exit = ccp_hmac_sha_cra_exit; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci ret = crypto_register_ahash(alg); 44462306a36Sopenharmony_ci if (ret) { 44562306a36Sopenharmony_ci pr_err("%s ahash algorithm registration error (%d)\n", 44662306a36Sopenharmony_ci base->cra_name, ret); 44762306a36Sopenharmony_ci kfree(ccp_alg); 44862306a36Sopenharmony_ci return ret; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci list_add(&ccp_alg->entry, head); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int ccp_register_sha_alg(struct list_head *head, 45762306a36Sopenharmony_ci const struct ccp_sha_def *def) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct ccp_crypto_ahash_alg *ccp_alg; 46062306a36Sopenharmony_ci struct ahash_alg *alg; 46162306a36Sopenharmony_ci struct hash_alg_common *halg; 46262306a36Sopenharmony_ci struct crypto_alg *base; 46362306a36Sopenharmony_ci int ret; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci ccp_alg = kzalloc(sizeof(*ccp_alg), GFP_KERNEL); 46662306a36Sopenharmony_ci if (!ccp_alg) 46762306a36Sopenharmony_ci return -ENOMEM; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci INIT_LIST_HEAD(&ccp_alg->entry); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci ccp_alg->type = def->type; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci alg = &ccp_alg->alg; 47462306a36Sopenharmony_ci alg->init = ccp_sha_init; 47562306a36Sopenharmony_ci alg->update = ccp_sha_update; 47662306a36Sopenharmony_ci alg->final = ccp_sha_final; 47762306a36Sopenharmony_ci alg->finup = ccp_sha_finup; 47862306a36Sopenharmony_ci alg->digest = ccp_sha_digest; 47962306a36Sopenharmony_ci alg->export = ccp_sha_export; 48062306a36Sopenharmony_ci alg->import = ccp_sha_import; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci halg = &alg->halg; 48362306a36Sopenharmony_ci halg->digestsize = def->digest_size; 48462306a36Sopenharmony_ci halg->statesize = sizeof(struct ccp_sha_exp_ctx); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci base = &halg->base; 48762306a36Sopenharmony_ci snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name); 48862306a36Sopenharmony_ci snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 48962306a36Sopenharmony_ci def->drv_name); 49062306a36Sopenharmony_ci base->cra_flags = CRYPTO_ALG_ASYNC | 49162306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 49262306a36Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY | 49362306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK; 49462306a36Sopenharmony_ci base->cra_blocksize = def->block_size; 49562306a36Sopenharmony_ci base->cra_ctxsize = sizeof(struct ccp_ctx) + crypto_dma_padding(); 49662306a36Sopenharmony_ci base->cra_priority = CCP_CRA_PRIORITY; 49762306a36Sopenharmony_ci base->cra_init = ccp_sha_cra_init; 49862306a36Sopenharmony_ci base->cra_exit = ccp_sha_cra_exit; 49962306a36Sopenharmony_ci base->cra_module = THIS_MODULE; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci ret = crypto_register_ahash(alg); 50262306a36Sopenharmony_ci if (ret) { 50362306a36Sopenharmony_ci pr_err("%s ahash algorithm registration error (%d)\n", 50462306a36Sopenharmony_ci base->cra_name, ret); 50562306a36Sopenharmony_ci kfree(ccp_alg); 50662306a36Sopenharmony_ci return ret; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci list_add(&ccp_alg->entry, head); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci ret = ccp_register_hmac_alg(head, def, ccp_alg); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return ret; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ciint ccp_register_sha_algs(struct list_head *head) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci int i, ret; 51962306a36Sopenharmony_ci unsigned int ccpversion = ccp_version(); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sha_algs); i++) { 52262306a36Sopenharmony_ci if (sha_algs[i].version > ccpversion) 52362306a36Sopenharmony_ci continue; 52462306a36Sopenharmony_ci ret = ccp_register_sha_alg(head, &sha_algs[i]); 52562306a36Sopenharmony_ci if (ret) 52662306a36Sopenharmony_ci return ret; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci} 531