162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * Copyright (C) 2021, Linaro Limited. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/dma-mapping.h> 762306a36Sopenharmony_ci#include <linux/interrupt.h> 862306a36Sopenharmony_ci#include <crypto/gcm.h> 962306a36Sopenharmony_ci#include <crypto/authenc.h> 1062306a36Sopenharmony_ci#include <crypto/internal/aead.h> 1162306a36Sopenharmony_ci#include <crypto/internal/des.h> 1262306a36Sopenharmony_ci#include <crypto/sha1.h> 1362306a36Sopenharmony_ci#include <crypto/sha2.h> 1462306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1562306a36Sopenharmony_ci#include "aead.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define CCM_NONCE_ADATA_SHIFT 6 1862306a36Sopenharmony_ci#define CCM_NONCE_AUTHSIZE_SHIFT 3 1962306a36Sopenharmony_ci#define MAX_CCM_ADATA_HEADER_LEN 6 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic LIST_HEAD(aead_algs); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void qce_aead_done(void *data) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct crypto_async_request *async_req = data; 2662306a36Sopenharmony_ci struct aead_request *req = aead_request_cast(async_req); 2762306a36Sopenharmony_ci struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); 2862306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_tfm_ctx(async_req->tfm); 2962306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req)); 3062306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 3162306a36Sopenharmony_ci struct qce_result_dump *result_buf = qce->dma.result_buf; 3262306a36Sopenharmony_ci enum dma_data_direction dir_src, dir_dst; 3362306a36Sopenharmony_ci bool diff_dst; 3462306a36Sopenharmony_ci int error; 3562306a36Sopenharmony_ci u32 status; 3662306a36Sopenharmony_ci unsigned int totallen; 3762306a36Sopenharmony_ci unsigned char tag[SHA256_DIGEST_SIZE] = {0}; 3862306a36Sopenharmony_ci int ret = 0; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci diff_dst = (req->src != req->dst) ? true : false; 4162306a36Sopenharmony_ci dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL; 4262306a36Sopenharmony_ci dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci error = qce_dma_terminate_all(&qce->dma); 4562306a36Sopenharmony_ci if (error) 4662306a36Sopenharmony_ci dev_dbg(qce->dev, "aead dma termination error (%d)\n", 4762306a36Sopenharmony_ci error); 4862306a36Sopenharmony_ci if (diff_dst) 4962306a36Sopenharmony_ci dma_unmap_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (IS_CCM(rctx->flags)) { 5462306a36Sopenharmony_ci if (req->assoclen) { 5562306a36Sopenharmony_ci sg_free_table(&rctx->src_tbl); 5662306a36Sopenharmony_ci if (diff_dst) 5762306a36Sopenharmony_ci sg_free_table(&rctx->dst_tbl); 5862306a36Sopenharmony_ci } else { 5962306a36Sopenharmony_ci if (!(IS_DECRYPT(rctx->flags) && !diff_dst)) 6062306a36Sopenharmony_ci sg_free_table(&rctx->dst_tbl); 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci } else { 6362306a36Sopenharmony_ci sg_free_table(&rctx->dst_tbl); 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci error = qce_check_status(qce, &status); 6762306a36Sopenharmony_ci if (error < 0 && (error != -EBADMSG)) 6862306a36Sopenharmony_ci dev_err(qce->dev, "aead operation error (%x)\n", status); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (IS_ENCRYPT(rctx->flags)) { 7162306a36Sopenharmony_ci totallen = req->cryptlen + req->assoclen; 7262306a36Sopenharmony_ci if (IS_CCM(rctx->flags)) 7362306a36Sopenharmony_ci scatterwalk_map_and_copy(rctx->ccmresult_buf, req->dst, 7462306a36Sopenharmony_ci totallen, ctx->authsize, 1); 7562306a36Sopenharmony_ci else 7662306a36Sopenharmony_ci scatterwalk_map_and_copy(result_buf->auth_iv, req->dst, 7762306a36Sopenharmony_ci totallen, ctx->authsize, 1); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci } else if (!IS_CCM(rctx->flags)) { 8062306a36Sopenharmony_ci totallen = req->cryptlen + req->assoclen - ctx->authsize; 8162306a36Sopenharmony_ci scatterwalk_map_and_copy(tag, req->src, totallen, ctx->authsize, 0); 8262306a36Sopenharmony_ci ret = memcmp(result_buf->auth_iv, tag, ctx->authsize); 8362306a36Sopenharmony_ci if (ret) { 8462306a36Sopenharmony_ci pr_err("Bad message error\n"); 8562306a36Sopenharmony_ci error = -EBADMSG; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci qce->async_req_done(qce, error); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic struct scatterlist * 9362306a36Sopenharmony_ciqce_aead_prepare_result_buf(struct sg_table *tbl, struct aead_request *req) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); 9662306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req)); 9762306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ); 10062306a36Sopenharmony_ci return qce_sgtable_add(tbl, &rctx->result_sg, QCE_RESULT_BUF_SZ); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic struct scatterlist * 10462306a36Sopenharmony_ciqce_aead_prepare_ccm_result_buf(struct sg_table *tbl, struct aead_request *req) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci sg_init_one(&rctx->result_sg, rctx->ccmresult_buf, QCE_BAM_BURST_SIZE); 10962306a36Sopenharmony_ci return qce_sgtable_add(tbl, &rctx->result_sg, QCE_BAM_BURST_SIZE); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic struct scatterlist * 11362306a36Sopenharmony_ciqce_aead_prepare_dst_buf(struct aead_request *req) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); 11662306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req)); 11762306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 11862306a36Sopenharmony_ci struct scatterlist *sg, *msg_sg, __sg[2]; 11962306a36Sopenharmony_ci gfp_t gfp; 12062306a36Sopenharmony_ci unsigned int assoclen = req->assoclen; 12162306a36Sopenharmony_ci unsigned int totallen; 12262306a36Sopenharmony_ci int ret; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci totallen = rctx->cryptlen + assoclen; 12562306a36Sopenharmony_ci rctx->dst_nents = sg_nents_for_len(req->dst, totallen); 12662306a36Sopenharmony_ci if (rctx->dst_nents < 0) { 12762306a36Sopenharmony_ci dev_err(qce->dev, "Invalid numbers of dst SG.\n"); 12862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci if (IS_CCM(rctx->flags)) 13162306a36Sopenharmony_ci rctx->dst_nents += 2; 13262306a36Sopenharmony_ci else 13362306a36Sopenharmony_ci rctx->dst_nents += 1; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? 13662306a36Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 13762306a36Sopenharmony_ci ret = sg_alloc_table(&rctx->dst_tbl, rctx->dst_nents, gfp); 13862306a36Sopenharmony_ci if (ret) 13962306a36Sopenharmony_ci return ERR_PTR(ret); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (IS_CCM(rctx->flags) && assoclen) { 14262306a36Sopenharmony_ci /* Get the dst buffer */ 14362306a36Sopenharmony_ci msg_sg = scatterwalk_ffwd(__sg, req->dst, assoclen); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->adata_sg, 14662306a36Sopenharmony_ci rctx->assoclen); 14762306a36Sopenharmony_ci if (IS_ERR(sg)) { 14862306a36Sopenharmony_ci ret = PTR_ERR(sg); 14962306a36Sopenharmony_ci goto dst_tbl_free; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci /* dst buffer */ 15262306a36Sopenharmony_ci sg = qce_sgtable_add(&rctx->dst_tbl, msg_sg, rctx->cryptlen); 15362306a36Sopenharmony_ci if (IS_ERR(sg)) { 15462306a36Sopenharmony_ci ret = PTR_ERR(sg); 15562306a36Sopenharmony_ci goto dst_tbl_free; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci totallen = rctx->cryptlen + rctx->assoclen; 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci if (totallen) { 16062306a36Sopenharmony_ci sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, totallen); 16162306a36Sopenharmony_ci if (IS_ERR(sg)) 16262306a36Sopenharmony_ci goto dst_tbl_free; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci if (IS_CCM(rctx->flags)) 16662306a36Sopenharmony_ci sg = qce_aead_prepare_ccm_result_buf(&rctx->dst_tbl, req); 16762306a36Sopenharmony_ci else 16862306a36Sopenharmony_ci sg = qce_aead_prepare_result_buf(&rctx->dst_tbl, req); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (IS_ERR(sg)) 17162306a36Sopenharmony_ci goto dst_tbl_free; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci sg_mark_end(sg); 17462306a36Sopenharmony_ci rctx->dst_sg = rctx->dst_tbl.sgl; 17562306a36Sopenharmony_ci rctx->dst_nents = sg_nents_for_len(rctx->dst_sg, totallen) + 1; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return sg; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cidst_tbl_free: 18062306a36Sopenharmony_ci sg_free_table(&rctx->dst_tbl); 18162306a36Sopenharmony_ci return sg; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int 18562306a36Sopenharmony_ciqce_aead_ccm_prepare_buf_assoclen(struct aead_request *req) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct scatterlist *sg, *msg_sg, __sg[2]; 18862306a36Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 18962306a36Sopenharmony_ci struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); 19062306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); 19162306a36Sopenharmony_ci unsigned int assoclen = rctx->assoclen; 19262306a36Sopenharmony_ci unsigned int adata_header_len, cryptlen, totallen; 19362306a36Sopenharmony_ci gfp_t gfp; 19462306a36Sopenharmony_ci bool diff_dst; 19562306a36Sopenharmony_ci int ret; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (IS_DECRYPT(rctx->flags)) 19862306a36Sopenharmony_ci cryptlen = rctx->cryptlen + ctx->authsize; 19962306a36Sopenharmony_ci else 20062306a36Sopenharmony_ci cryptlen = rctx->cryptlen; 20162306a36Sopenharmony_ci totallen = cryptlen + req->assoclen; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Get the msg */ 20462306a36Sopenharmony_ci msg_sg = scatterwalk_ffwd(__sg, req->src, req->assoclen); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci rctx->adata = kzalloc((ALIGN(assoclen, 16) + MAX_CCM_ADATA_HEADER_LEN) * 20762306a36Sopenharmony_ci sizeof(unsigned char), GFP_ATOMIC); 20862306a36Sopenharmony_ci if (!rctx->adata) 20962306a36Sopenharmony_ci return -ENOMEM; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* 21262306a36Sopenharmony_ci * Format associated data (RFC3610 and NIST 800-38C) 21362306a36Sopenharmony_ci * Even though specification allows for AAD to be up to 2^64 - 1 bytes, 21462306a36Sopenharmony_ci * the assoclen field in aead_request is unsigned int and thus limits 21562306a36Sopenharmony_ci * the AAD to be up to 2^32 - 1 bytes. So we handle only two scenarios 21662306a36Sopenharmony_ci * while forming the header for AAD. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci if (assoclen < 0xff00) { 21962306a36Sopenharmony_ci adata_header_len = 2; 22062306a36Sopenharmony_ci *(__be16 *)rctx->adata = cpu_to_be16(assoclen); 22162306a36Sopenharmony_ci } else { 22262306a36Sopenharmony_ci adata_header_len = 6; 22362306a36Sopenharmony_ci *(__be16 *)rctx->adata = cpu_to_be16(0xfffe); 22462306a36Sopenharmony_ci *(__be32 *)(rctx->adata + 2) = cpu_to_be32(assoclen); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Copy the associated data */ 22862306a36Sopenharmony_ci if (sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, assoclen), 22962306a36Sopenharmony_ci rctx->adata + adata_header_len, 23062306a36Sopenharmony_ci assoclen) != assoclen) 23162306a36Sopenharmony_ci return -EINVAL; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Pad associated data to block size */ 23462306a36Sopenharmony_ci rctx->assoclen = ALIGN(assoclen + adata_header_len, 16); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci diff_dst = (req->src != req->dst) ? true : false; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (diff_dst) 23962306a36Sopenharmony_ci rctx->src_nents = sg_nents_for_len(req->src, totallen) + 1; 24062306a36Sopenharmony_ci else 24162306a36Sopenharmony_ci rctx->src_nents = sg_nents_for_len(req->src, totallen) + 2; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; 24462306a36Sopenharmony_ci ret = sg_alloc_table(&rctx->src_tbl, rctx->src_nents, gfp); 24562306a36Sopenharmony_ci if (ret) 24662306a36Sopenharmony_ci return ret; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Associated Data */ 24962306a36Sopenharmony_ci sg_init_one(&rctx->adata_sg, rctx->adata, rctx->assoclen); 25062306a36Sopenharmony_ci sg = qce_sgtable_add(&rctx->src_tbl, &rctx->adata_sg, 25162306a36Sopenharmony_ci rctx->assoclen); 25262306a36Sopenharmony_ci if (IS_ERR(sg)) { 25362306a36Sopenharmony_ci ret = PTR_ERR(sg); 25462306a36Sopenharmony_ci goto err_free; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci /* src msg */ 25762306a36Sopenharmony_ci sg = qce_sgtable_add(&rctx->src_tbl, msg_sg, cryptlen); 25862306a36Sopenharmony_ci if (IS_ERR(sg)) { 25962306a36Sopenharmony_ci ret = PTR_ERR(sg); 26062306a36Sopenharmony_ci goto err_free; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci if (!diff_dst) { 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * For decrypt, when src and dst buffers are same, there is already space 26562306a36Sopenharmony_ci * in the buffer for padded 0's which is output in lieu of 26662306a36Sopenharmony_ci * the MAC that is input. So skip the below. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci if (!IS_DECRYPT(rctx->flags)) { 26962306a36Sopenharmony_ci sg = qce_aead_prepare_ccm_result_buf(&rctx->src_tbl, req); 27062306a36Sopenharmony_ci if (IS_ERR(sg)) { 27162306a36Sopenharmony_ci ret = PTR_ERR(sg); 27262306a36Sopenharmony_ci goto err_free; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci sg_mark_end(sg); 27762306a36Sopenharmony_ci rctx->src_sg = rctx->src_tbl.sgl; 27862306a36Sopenharmony_ci totallen = cryptlen + rctx->assoclen; 27962306a36Sopenharmony_ci rctx->src_nents = sg_nents_for_len(rctx->src_sg, totallen); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (diff_dst) { 28262306a36Sopenharmony_ci sg = qce_aead_prepare_dst_buf(req); 28362306a36Sopenharmony_ci if (IS_ERR(sg)) { 28462306a36Sopenharmony_ci ret = PTR_ERR(sg); 28562306a36Sopenharmony_ci goto err_free; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci } else { 28862306a36Sopenharmony_ci if (IS_ENCRYPT(rctx->flags)) 28962306a36Sopenharmony_ci rctx->dst_nents = rctx->src_nents + 1; 29062306a36Sopenharmony_ci else 29162306a36Sopenharmony_ci rctx->dst_nents = rctx->src_nents; 29262306a36Sopenharmony_ci rctx->dst_sg = rctx->src_sg; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_cierr_free: 29762306a36Sopenharmony_ci sg_free_table(&rctx->src_tbl); 29862306a36Sopenharmony_ci return ret; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic int qce_aead_prepare_buf(struct aead_request *req) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); 30462306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req)); 30562306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 30662306a36Sopenharmony_ci struct scatterlist *sg; 30762306a36Sopenharmony_ci bool diff_dst = (req->src != req->dst) ? true : false; 30862306a36Sopenharmony_ci unsigned int totallen; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci totallen = rctx->cryptlen + rctx->assoclen; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci sg = qce_aead_prepare_dst_buf(req); 31362306a36Sopenharmony_ci if (IS_ERR(sg)) 31462306a36Sopenharmony_ci return PTR_ERR(sg); 31562306a36Sopenharmony_ci if (diff_dst) { 31662306a36Sopenharmony_ci rctx->src_nents = sg_nents_for_len(req->src, totallen); 31762306a36Sopenharmony_ci if (rctx->src_nents < 0) { 31862306a36Sopenharmony_ci dev_err(qce->dev, "Invalid numbers of src SG.\n"); 31962306a36Sopenharmony_ci return -EINVAL; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci rctx->src_sg = req->src; 32262306a36Sopenharmony_ci } else { 32362306a36Sopenharmony_ci rctx->src_nents = rctx->dst_nents - 1; 32462306a36Sopenharmony_ci rctx->src_sg = rctx->dst_sg; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int qce_aead_ccm_prepare_buf(struct aead_request *req) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); 33262306a36Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 33362306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); 33462306a36Sopenharmony_ci struct scatterlist *sg; 33562306a36Sopenharmony_ci bool diff_dst = (req->src != req->dst) ? true : false; 33662306a36Sopenharmony_ci unsigned int cryptlen; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (rctx->assoclen) 33962306a36Sopenharmony_ci return qce_aead_ccm_prepare_buf_assoclen(req); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (IS_ENCRYPT(rctx->flags)) 34262306a36Sopenharmony_ci return qce_aead_prepare_buf(req); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci cryptlen = rctx->cryptlen + ctx->authsize; 34562306a36Sopenharmony_ci if (diff_dst) { 34662306a36Sopenharmony_ci rctx->src_nents = sg_nents_for_len(req->src, cryptlen); 34762306a36Sopenharmony_ci rctx->src_sg = req->src; 34862306a36Sopenharmony_ci sg = qce_aead_prepare_dst_buf(req); 34962306a36Sopenharmony_ci if (IS_ERR(sg)) 35062306a36Sopenharmony_ci return PTR_ERR(sg); 35162306a36Sopenharmony_ci } else { 35262306a36Sopenharmony_ci rctx->src_nents = sg_nents_for_len(req->src, cryptlen); 35362306a36Sopenharmony_ci rctx->src_sg = req->src; 35462306a36Sopenharmony_ci rctx->dst_nents = rctx->src_nents; 35562306a36Sopenharmony_ci rctx->dst_sg = rctx->src_sg; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int qce_aead_create_ccm_nonce(struct qce_aead_reqctx *rctx, struct qce_aead_ctx *ctx) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci unsigned int msglen_size, ivsize; 36462306a36Sopenharmony_ci u8 msg_len[4]; 36562306a36Sopenharmony_ci int i; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (!rctx || !rctx->iv) 36862306a36Sopenharmony_ci return -EINVAL; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci msglen_size = rctx->iv[0] + 1; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Verify that msg len size is valid */ 37362306a36Sopenharmony_ci if (msglen_size < 2 || msglen_size > 8) 37462306a36Sopenharmony_ci return -EINVAL; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ivsize = rctx->ivsize; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* 37962306a36Sopenharmony_ci * Clear the msglen bytes in IV. 38062306a36Sopenharmony_ci * Else the h/w engine and nonce will use any stray value pending there. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci if (!IS_CCM_RFC4309(rctx->flags)) { 38362306a36Sopenharmony_ci for (i = 0; i < msglen_size; i++) 38462306a36Sopenharmony_ci rctx->iv[ivsize - i - 1] = 0; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* 38862306a36Sopenharmony_ci * The crypto framework encodes cryptlen as unsigned int. Thus, even though 38962306a36Sopenharmony_ci * spec allows for upto 8 bytes to encode msg_len only 4 bytes are needed. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci if (msglen_size > 4) 39262306a36Sopenharmony_ci msglen_size = 4; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci memcpy(&msg_len[0], &rctx->cryptlen, 4); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci memcpy(&rctx->ccm_nonce[0], rctx->iv, rctx->ivsize); 39762306a36Sopenharmony_ci if (rctx->assoclen) 39862306a36Sopenharmony_ci rctx->ccm_nonce[0] |= 1 << CCM_NONCE_ADATA_SHIFT; 39962306a36Sopenharmony_ci rctx->ccm_nonce[0] |= ((ctx->authsize - 2) / 2) << 40062306a36Sopenharmony_ci CCM_NONCE_AUTHSIZE_SHIFT; 40162306a36Sopenharmony_ci for (i = 0; i < msglen_size; i++) 40262306a36Sopenharmony_ci rctx->ccm_nonce[QCE_MAX_NONCE - i - 1] = msg_len[i]; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic int 40862306a36Sopenharmony_ciqce_aead_async_req_handle(struct crypto_async_request *async_req) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct aead_request *req = aead_request_cast(async_req); 41162306a36Sopenharmony_ci struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); 41262306a36Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 41362306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_tfm_ctx(async_req->tfm); 41462306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req)); 41562306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 41662306a36Sopenharmony_ci enum dma_data_direction dir_src, dir_dst; 41762306a36Sopenharmony_ci bool diff_dst; 41862306a36Sopenharmony_ci int dst_nents, src_nents, ret; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (IS_CCM_RFC4309(rctx->flags)) { 42162306a36Sopenharmony_ci memset(rctx->ccm_rfc4309_iv, 0, QCE_MAX_IV_SIZE); 42262306a36Sopenharmony_ci rctx->ccm_rfc4309_iv[0] = 3; 42362306a36Sopenharmony_ci memcpy(&rctx->ccm_rfc4309_iv[1], ctx->ccm4309_salt, QCE_CCM4309_SALT_SIZE); 42462306a36Sopenharmony_ci memcpy(&rctx->ccm_rfc4309_iv[4], req->iv, 8); 42562306a36Sopenharmony_ci rctx->iv = rctx->ccm_rfc4309_iv; 42662306a36Sopenharmony_ci rctx->ivsize = AES_BLOCK_SIZE; 42762306a36Sopenharmony_ci } else { 42862306a36Sopenharmony_ci rctx->iv = req->iv; 42962306a36Sopenharmony_ci rctx->ivsize = crypto_aead_ivsize(tfm); 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci if (IS_CCM_RFC4309(rctx->flags)) 43262306a36Sopenharmony_ci rctx->assoclen = req->assoclen - 8; 43362306a36Sopenharmony_ci else 43462306a36Sopenharmony_ci rctx->assoclen = req->assoclen; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci diff_dst = (req->src != req->dst) ? true : false; 43762306a36Sopenharmony_ci dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL; 43862306a36Sopenharmony_ci dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (IS_CCM(rctx->flags)) { 44162306a36Sopenharmony_ci ret = qce_aead_create_ccm_nonce(rctx, ctx); 44262306a36Sopenharmony_ci if (ret) 44362306a36Sopenharmony_ci return ret; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci if (IS_CCM(rctx->flags)) 44662306a36Sopenharmony_ci ret = qce_aead_ccm_prepare_buf(req); 44762306a36Sopenharmony_ci else 44862306a36Sopenharmony_ci ret = qce_aead_prepare_buf(req); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (ret) 45162306a36Sopenharmony_ci return ret; 45262306a36Sopenharmony_ci dst_nents = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst); 45362306a36Sopenharmony_ci if (!dst_nents) { 45462306a36Sopenharmony_ci ret = -EIO; 45562306a36Sopenharmony_ci goto error_free; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (diff_dst) { 45962306a36Sopenharmony_ci src_nents = dma_map_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src); 46062306a36Sopenharmony_ci if (src_nents < 0) { 46162306a36Sopenharmony_ci ret = src_nents; 46262306a36Sopenharmony_ci goto error_unmap_dst; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci } else { 46562306a36Sopenharmony_ci if (IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags)) 46662306a36Sopenharmony_ci src_nents = dst_nents; 46762306a36Sopenharmony_ci else 46862306a36Sopenharmony_ci src_nents = dst_nents - 1; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, src_nents, rctx->dst_sg, dst_nents, 47262306a36Sopenharmony_ci qce_aead_done, async_req); 47362306a36Sopenharmony_ci if (ret) 47462306a36Sopenharmony_ci goto error_unmap_src; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci qce_dma_issue_pending(&qce->dma); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci ret = qce_start(async_req, tmpl->crypto_alg_type); 47962306a36Sopenharmony_ci if (ret) 48062306a36Sopenharmony_ci goto error_terminate; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cierror_terminate: 48562306a36Sopenharmony_ci qce_dma_terminate_all(&qce->dma); 48662306a36Sopenharmony_cierror_unmap_src: 48762306a36Sopenharmony_ci if (diff_dst) 48862306a36Sopenharmony_ci dma_unmap_sg(qce->dev, req->src, rctx->src_nents, dir_src); 48962306a36Sopenharmony_cierror_unmap_dst: 49062306a36Sopenharmony_ci dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst); 49162306a36Sopenharmony_cierror_free: 49262306a36Sopenharmony_ci if (IS_CCM(rctx->flags) && rctx->assoclen) { 49362306a36Sopenharmony_ci sg_free_table(&rctx->src_tbl); 49462306a36Sopenharmony_ci if (diff_dst) 49562306a36Sopenharmony_ci sg_free_table(&rctx->dst_tbl); 49662306a36Sopenharmony_ci } else { 49762306a36Sopenharmony_ci sg_free_table(&rctx->dst_tbl); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci return ret; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic int qce_aead_crypt(struct aead_request *req, int encrypt) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 50562306a36Sopenharmony_ci struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req); 50662306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); 50762306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_aead_tmpl(tfm); 50862306a36Sopenharmony_ci unsigned int blocksize = crypto_aead_blocksize(tfm); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci rctx->flags = tmpl->alg_flags; 51162306a36Sopenharmony_ci rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (encrypt) 51462306a36Sopenharmony_ci rctx->cryptlen = req->cryptlen; 51562306a36Sopenharmony_ci else 51662306a36Sopenharmony_ci rctx->cryptlen = req->cryptlen - ctx->authsize; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* CE does not handle 0 length messages */ 51962306a36Sopenharmony_ci if (!rctx->cryptlen) { 52062306a36Sopenharmony_ci if (!(IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags))) 52162306a36Sopenharmony_ci ctx->need_fallback = true; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* If fallback is needed, schedule and exit */ 52562306a36Sopenharmony_ci if (ctx->need_fallback) { 52662306a36Sopenharmony_ci /* Reset need_fallback in case the same ctx is used for another transaction */ 52762306a36Sopenharmony_ci ctx->need_fallback = false; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci aead_request_set_tfm(&rctx->fallback_req, ctx->fallback); 53062306a36Sopenharmony_ci aead_request_set_callback(&rctx->fallback_req, req->base.flags, 53162306a36Sopenharmony_ci req->base.complete, req->base.data); 53262306a36Sopenharmony_ci aead_request_set_crypt(&rctx->fallback_req, req->src, 53362306a36Sopenharmony_ci req->dst, req->cryptlen, req->iv); 53462306a36Sopenharmony_ci aead_request_set_ad(&rctx->fallback_req, req->assoclen); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return encrypt ? crypto_aead_encrypt(&rctx->fallback_req) : 53762306a36Sopenharmony_ci crypto_aead_decrypt(&rctx->fallback_req); 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* 54162306a36Sopenharmony_ci * CBC algorithms require message lengths to be 54262306a36Sopenharmony_ci * multiples of block size. 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_ci if (IS_CBC(rctx->flags) && !IS_ALIGNED(rctx->cryptlen, blocksize)) 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* RFC4309 supported AAD size 16 bytes/20 bytes */ 54862306a36Sopenharmony_ci if (IS_CCM_RFC4309(rctx->flags)) 54962306a36Sopenharmony_ci if (crypto_ipsec_check_assoclen(req->assoclen)) 55062306a36Sopenharmony_ci return -EINVAL; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return tmpl->qce->async_req_enqueue(tmpl->qce, &req->base); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int qce_aead_encrypt(struct aead_request *req) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci return qce_aead_crypt(req, 1); 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic int qce_aead_decrypt(struct aead_request *req) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci return qce_aead_crypt(req, 0); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic int qce_aead_ccm_setkey(struct crypto_aead *tfm, const u8 *key, 56662306a36Sopenharmony_ci unsigned int keylen) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); 56962306a36Sopenharmony_ci unsigned long flags = to_aead_tmpl(tfm)->alg_flags; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (IS_CCM_RFC4309(flags)) { 57262306a36Sopenharmony_ci if (keylen < QCE_CCM4309_SALT_SIZE) 57362306a36Sopenharmony_ci return -EINVAL; 57462306a36Sopenharmony_ci keylen -= QCE_CCM4309_SALT_SIZE; 57562306a36Sopenharmony_ci memcpy(ctx->ccm4309_salt, key + keylen, QCE_CCM4309_SALT_SIZE); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256 && keylen != AES_KEYSIZE_192) 57962306a36Sopenharmony_ci return -EINVAL; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci ctx->enc_keylen = keylen; 58262306a36Sopenharmony_ci ctx->auth_keylen = keylen; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci memcpy(ctx->enc_key, key, keylen); 58562306a36Sopenharmony_ci memcpy(ctx->auth_key, key, keylen); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (keylen == AES_KEYSIZE_192) 58862306a36Sopenharmony_ci ctx->need_fallback = true; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return IS_CCM_RFC4309(flags) ? 59162306a36Sopenharmony_ci crypto_aead_setkey(ctx->fallback, key, keylen + QCE_CCM4309_SALT_SIZE) : 59262306a36Sopenharmony_ci crypto_aead_setkey(ctx->fallback, key, keylen); 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic int qce_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); 59862306a36Sopenharmony_ci struct crypto_authenc_keys authenc_keys; 59962306a36Sopenharmony_ci unsigned long flags = to_aead_tmpl(tfm)->alg_flags; 60062306a36Sopenharmony_ci u32 _key[6]; 60162306a36Sopenharmony_ci int err; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci err = crypto_authenc_extractkeys(&authenc_keys, key, keylen); 60462306a36Sopenharmony_ci if (err) 60562306a36Sopenharmony_ci return err; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (authenc_keys.enckeylen > QCE_MAX_KEY_SIZE || 60862306a36Sopenharmony_ci authenc_keys.authkeylen > QCE_MAX_KEY_SIZE) 60962306a36Sopenharmony_ci return -EINVAL; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (IS_DES(flags)) { 61262306a36Sopenharmony_ci err = verify_aead_des_key(tfm, authenc_keys.enckey, authenc_keys.enckeylen); 61362306a36Sopenharmony_ci if (err) 61462306a36Sopenharmony_ci return err; 61562306a36Sopenharmony_ci } else if (IS_3DES(flags)) { 61662306a36Sopenharmony_ci err = verify_aead_des3_key(tfm, authenc_keys.enckey, authenc_keys.enckeylen); 61762306a36Sopenharmony_ci if (err) 61862306a36Sopenharmony_ci return err; 61962306a36Sopenharmony_ci /* 62062306a36Sopenharmony_ci * The crypto engine does not support any two keys 62162306a36Sopenharmony_ci * being the same for triple des algorithms. The 62262306a36Sopenharmony_ci * verify_skcipher_des3_key does not check for all the 62362306a36Sopenharmony_ci * below conditions. Schedule fallback in this case. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci memcpy(_key, authenc_keys.enckey, DES3_EDE_KEY_SIZE); 62662306a36Sopenharmony_ci if (!((_key[0] ^ _key[2]) | (_key[1] ^ _key[3])) || 62762306a36Sopenharmony_ci !((_key[2] ^ _key[4]) | (_key[3] ^ _key[5])) || 62862306a36Sopenharmony_ci !((_key[0] ^ _key[4]) | (_key[1] ^ _key[5]))) 62962306a36Sopenharmony_ci ctx->need_fallback = true; 63062306a36Sopenharmony_ci } else if (IS_AES(flags)) { 63162306a36Sopenharmony_ci /* No random key sizes */ 63262306a36Sopenharmony_ci if (authenc_keys.enckeylen != AES_KEYSIZE_128 && 63362306a36Sopenharmony_ci authenc_keys.enckeylen != AES_KEYSIZE_192 && 63462306a36Sopenharmony_ci authenc_keys.enckeylen != AES_KEYSIZE_256) 63562306a36Sopenharmony_ci return -EINVAL; 63662306a36Sopenharmony_ci if (authenc_keys.enckeylen == AES_KEYSIZE_192) 63762306a36Sopenharmony_ci ctx->need_fallback = true; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ctx->enc_keylen = authenc_keys.enckeylen; 64162306a36Sopenharmony_ci ctx->auth_keylen = authenc_keys.authkeylen; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci memcpy(ctx->enc_key, authenc_keys.enckey, authenc_keys.enckeylen); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci memset(ctx->auth_key, 0, sizeof(ctx->auth_key)); 64662306a36Sopenharmony_ci memcpy(ctx->auth_key, authenc_keys.authkey, authenc_keys.authkeylen); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return crypto_aead_setkey(ctx->fallback, key, keylen); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic int qce_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); 65462306a36Sopenharmony_ci unsigned long flags = to_aead_tmpl(tfm)->alg_flags; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (IS_CCM(flags)) { 65762306a36Sopenharmony_ci if (authsize < 4 || authsize > 16 || authsize % 2) 65862306a36Sopenharmony_ci return -EINVAL; 65962306a36Sopenharmony_ci if (IS_CCM_RFC4309(flags) && (authsize < 8 || authsize % 4)) 66062306a36Sopenharmony_ci return -EINVAL; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci ctx->authsize = authsize; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci return crypto_aead_setauthsize(ctx->fallback, authsize); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic int qce_aead_init(struct crypto_aead *tfm) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci ctx->need_fallback = false; 67262306a36Sopenharmony_ci ctx->fallback = crypto_alloc_aead(crypto_tfm_alg_name(&tfm->base), 67362306a36Sopenharmony_ci 0, CRYPTO_ALG_NEED_FALLBACK); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if (IS_ERR(ctx->fallback)) 67662306a36Sopenharmony_ci return PTR_ERR(ctx->fallback); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci crypto_aead_set_reqsize_dma(tfm, sizeof(struct qce_aead_reqctx) + 67962306a36Sopenharmony_ci crypto_aead_reqsize(ctx->fallback)); 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic void qce_aead_exit(struct crypto_aead *tfm) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci crypto_free_aead(ctx->fallback); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistruct qce_aead_def { 69162306a36Sopenharmony_ci unsigned long flags; 69262306a36Sopenharmony_ci const char *name; 69362306a36Sopenharmony_ci const char *drv_name; 69462306a36Sopenharmony_ci unsigned int blocksize; 69562306a36Sopenharmony_ci unsigned int chunksize; 69662306a36Sopenharmony_ci unsigned int ivsize; 69762306a36Sopenharmony_ci unsigned int maxauthsize; 69862306a36Sopenharmony_ci}; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic const struct qce_aead_def aead_def[] = { 70162306a36Sopenharmony_ci { 70262306a36Sopenharmony_ci .flags = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC, 70362306a36Sopenharmony_ci .name = "authenc(hmac(sha1),cbc(des))", 70462306a36Sopenharmony_ci .drv_name = "authenc-hmac-sha1-cbc-des-qce", 70562306a36Sopenharmony_ci .blocksize = DES_BLOCK_SIZE, 70662306a36Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 70762306a36Sopenharmony_ci .maxauthsize = SHA1_DIGEST_SIZE, 70862306a36Sopenharmony_ci }, 70962306a36Sopenharmony_ci { 71062306a36Sopenharmony_ci .flags = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC, 71162306a36Sopenharmony_ci .name = "authenc(hmac(sha1),cbc(des3_ede))", 71262306a36Sopenharmony_ci .drv_name = "authenc-hmac-sha1-cbc-3des-qce", 71362306a36Sopenharmony_ci .blocksize = DES3_EDE_BLOCK_SIZE, 71462306a36Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 71562306a36Sopenharmony_ci .maxauthsize = SHA1_DIGEST_SIZE, 71662306a36Sopenharmony_ci }, 71762306a36Sopenharmony_ci { 71862306a36Sopenharmony_ci .flags = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC, 71962306a36Sopenharmony_ci .name = "authenc(hmac(sha256),cbc(des))", 72062306a36Sopenharmony_ci .drv_name = "authenc-hmac-sha256-cbc-des-qce", 72162306a36Sopenharmony_ci .blocksize = DES_BLOCK_SIZE, 72262306a36Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 72362306a36Sopenharmony_ci .maxauthsize = SHA256_DIGEST_SIZE, 72462306a36Sopenharmony_ci }, 72562306a36Sopenharmony_ci { 72662306a36Sopenharmony_ci .flags = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC, 72762306a36Sopenharmony_ci .name = "authenc(hmac(sha256),cbc(des3_ede))", 72862306a36Sopenharmony_ci .drv_name = "authenc-hmac-sha256-cbc-3des-qce", 72962306a36Sopenharmony_ci .blocksize = DES3_EDE_BLOCK_SIZE, 73062306a36Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 73162306a36Sopenharmony_ci .maxauthsize = SHA256_DIGEST_SIZE, 73262306a36Sopenharmony_ci }, 73362306a36Sopenharmony_ci { 73462306a36Sopenharmony_ci .flags = QCE_ALG_AES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC, 73562306a36Sopenharmony_ci .name = "authenc(hmac(sha256),cbc(aes))", 73662306a36Sopenharmony_ci .drv_name = "authenc-hmac-sha256-cbc-aes-qce", 73762306a36Sopenharmony_ci .blocksize = AES_BLOCK_SIZE, 73862306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 73962306a36Sopenharmony_ci .maxauthsize = SHA256_DIGEST_SIZE, 74062306a36Sopenharmony_ci }, 74162306a36Sopenharmony_ci { 74262306a36Sopenharmony_ci .flags = QCE_ALG_AES | QCE_MODE_CCM, 74362306a36Sopenharmony_ci .name = "ccm(aes)", 74462306a36Sopenharmony_ci .drv_name = "ccm-aes-qce", 74562306a36Sopenharmony_ci .blocksize = 1, 74662306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 74762306a36Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 74862306a36Sopenharmony_ci }, 74962306a36Sopenharmony_ci { 75062306a36Sopenharmony_ci .flags = QCE_ALG_AES | QCE_MODE_CCM | QCE_MODE_CCM_RFC4309, 75162306a36Sopenharmony_ci .name = "rfc4309(ccm(aes))", 75262306a36Sopenharmony_ci .drv_name = "rfc4309-ccm-aes-qce", 75362306a36Sopenharmony_ci .blocksize = 1, 75462306a36Sopenharmony_ci .ivsize = 8, 75562306a36Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 75662306a36Sopenharmony_ci }, 75762306a36Sopenharmony_ci}; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic int qce_aead_register_one(const struct qce_aead_def *def, struct qce_device *qce) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct qce_alg_template *tmpl; 76262306a36Sopenharmony_ci struct aead_alg *alg; 76362306a36Sopenharmony_ci int ret; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); 76662306a36Sopenharmony_ci if (!tmpl) 76762306a36Sopenharmony_ci return -ENOMEM; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci alg = &tmpl->alg.aead; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name); 77262306a36Sopenharmony_ci snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 77362306a36Sopenharmony_ci def->drv_name); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci alg->base.cra_blocksize = def->blocksize; 77662306a36Sopenharmony_ci alg->chunksize = def->chunksize; 77762306a36Sopenharmony_ci alg->ivsize = def->ivsize; 77862306a36Sopenharmony_ci alg->maxauthsize = def->maxauthsize; 77962306a36Sopenharmony_ci if (IS_CCM(def->flags)) 78062306a36Sopenharmony_ci alg->setkey = qce_aead_ccm_setkey; 78162306a36Sopenharmony_ci else 78262306a36Sopenharmony_ci alg->setkey = qce_aead_setkey; 78362306a36Sopenharmony_ci alg->setauthsize = qce_aead_setauthsize; 78462306a36Sopenharmony_ci alg->encrypt = qce_aead_encrypt; 78562306a36Sopenharmony_ci alg->decrypt = qce_aead_decrypt; 78662306a36Sopenharmony_ci alg->init = qce_aead_init; 78762306a36Sopenharmony_ci alg->exit = qce_aead_exit; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci alg->base.cra_priority = 300; 79062306a36Sopenharmony_ci alg->base.cra_flags = CRYPTO_ALG_ASYNC | 79162306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 79262306a36Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY | 79362306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK; 79462306a36Sopenharmony_ci alg->base.cra_ctxsize = sizeof(struct qce_aead_ctx); 79562306a36Sopenharmony_ci alg->base.cra_alignmask = 0; 79662306a36Sopenharmony_ci alg->base.cra_module = THIS_MODULE; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci INIT_LIST_HEAD(&tmpl->entry); 79962306a36Sopenharmony_ci tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_AEAD; 80062306a36Sopenharmony_ci tmpl->alg_flags = def->flags; 80162306a36Sopenharmony_ci tmpl->qce = qce; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci ret = crypto_register_aead(alg); 80462306a36Sopenharmony_ci if (ret) { 80562306a36Sopenharmony_ci dev_err(qce->dev, "%s registration failed\n", alg->base.cra_name); 80662306a36Sopenharmony_ci kfree(tmpl); 80762306a36Sopenharmony_ci return ret; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci list_add_tail(&tmpl->entry, &aead_algs); 81162306a36Sopenharmony_ci dev_dbg(qce->dev, "%s is registered\n", alg->base.cra_name); 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic void qce_aead_unregister(struct qce_device *qce) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci struct qce_alg_template *tmpl, *n; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci list_for_each_entry_safe(tmpl, n, &aead_algs, entry) { 82062306a36Sopenharmony_ci crypto_unregister_aead(&tmpl->alg.aead); 82162306a36Sopenharmony_ci list_del(&tmpl->entry); 82262306a36Sopenharmony_ci kfree(tmpl); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic int qce_aead_register(struct qce_device *qce) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci int ret, i; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aead_def); i++) { 83162306a36Sopenharmony_ci ret = qce_aead_register_one(&aead_def[i], qce); 83262306a36Sopenharmony_ci if (ret) 83362306a36Sopenharmony_ci goto err; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci return 0; 83762306a36Sopenharmony_cierr: 83862306a36Sopenharmony_ci qce_aead_unregister(qce); 83962306a36Sopenharmony_ci return ret; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ciconst struct qce_algo_ops aead_ops = { 84362306a36Sopenharmony_ci .type = CRYPTO_ALG_TYPE_AEAD, 84462306a36Sopenharmony_ci .register_algs = qce_aead_register, 84562306a36Sopenharmony_ci .unregister_algs = qce_aead_unregister, 84662306a36Sopenharmony_ci .async_req_handle = qce_aead_async_req_handle, 84762306a36Sopenharmony_ci}; 848