162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/kernel.h> 362306a36Sopenharmony_ci#include <linux/printk.h> 462306a36Sopenharmony_ci#include <linux/crypto.h> 562306a36Sopenharmony_ci#include <linux/rtnetlink.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <crypto/aead.h> 862306a36Sopenharmony_ci#include <crypto/authenc.h> 962306a36Sopenharmony_ci#include <crypto/des.h> 1062306a36Sopenharmony_ci#include <crypto/internal/aead.h> 1162306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1262306a36Sopenharmony_ci#include <crypto/gcm.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "nitrox_dev.h" 1562306a36Sopenharmony_ci#include "nitrox_common.h" 1662306a36Sopenharmony_ci#include "nitrox_req.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define GCM_AES_SALT_SIZE 4 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciunion gph_p3 { 2162306a36Sopenharmony_ci struct { 2262306a36Sopenharmony_ci#ifdef __BIG_ENDIAN_BITFIELD 2362306a36Sopenharmony_ci u16 iv_offset : 8; 2462306a36Sopenharmony_ci u16 auth_offset : 8; 2562306a36Sopenharmony_ci#else 2662306a36Sopenharmony_ci u16 auth_offset : 8; 2762306a36Sopenharmony_ci u16 iv_offset : 8; 2862306a36Sopenharmony_ci#endif 2962306a36Sopenharmony_ci }; 3062306a36Sopenharmony_ci u16 param; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int nitrox_aes_gcm_setkey(struct crypto_aead *aead, const u8 *key, 3462306a36Sopenharmony_ci unsigned int keylen) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci int aes_keylen; 3762306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead); 3862306a36Sopenharmony_ci struct flexi_crypto_context *fctx; 3962306a36Sopenharmony_ci union fc_ctx_flags flags; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci aes_keylen = flexi_aes_keylen(keylen); 4262306a36Sopenharmony_ci if (aes_keylen < 0) 4362306a36Sopenharmony_ci return -EINVAL; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* fill crypto context */ 4662306a36Sopenharmony_ci fctx = nctx->u.fctx; 4762306a36Sopenharmony_ci flags.fu = be64_to_cpu(fctx->flags.f); 4862306a36Sopenharmony_ci flags.w0.aes_keylen = aes_keylen; 4962306a36Sopenharmony_ci fctx->flags.f = cpu_to_be64(flags.fu); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* copy enc key to context */ 5262306a36Sopenharmony_ci memset(&fctx->crypto, 0, sizeof(fctx->crypto)); 5362306a36Sopenharmony_ci memcpy(fctx->crypto.u.key, key, keylen); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return 0; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int nitrox_aead_setauthsize(struct crypto_aead *aead, 5962306a36Sopenharmony_ci unsigned int authsize) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead); 6262306a36Sopenharmony_ci struct flexi_crypto_context *fctx = nctx->u.fctx; 6362306a36Sopenharmony_ci union fc_ctx_flags flags; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci flags.fu = be64_to_cpu(fctx->flags.f); 6662306a36Sopenharmony_ci flags.w0.mac_len = authsize; 6762306a36Sopenharmony_ci fctx->flags.f = cpu_to_be64(flags.fu); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci aead->authsize = authsize; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int nitrox_aes_gcm_setauthsize(struct crypto_aead *aead, 7562306a36Sopenharmony_ci unsigned int authsize) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci switch (authsize) { 7862306a36Sopenharmony_ci case 4: 7962306a36Sopenharmony_ci case 8: 8062306a36Sopenharmony_ci case 12: 8162306a36Sopenharmony_ci case 13: 8262306a36Sopenharmony_ci case 14: 8362306a36Sopenharmony_ci case 15: 8462306a36Sopenharmony_ci case 16: 8562306a36Sopenharmony_ci break; 8662306a36Sopenharmony_ci default: 8762306a36Sopenharmony_ci return -EINVAL; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return nitrox_aead_setauthsize(aead, authsize); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int alloc_src_sglist(struct nitrox_kcrypt_request *nkreq, 9462306a36Sopenharmony_ci struct scatterlist *src, char *iv, int ivsize, 9562306a36Sopenharmony_ci int buflen) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci int nents = sg_nents_for_len(src, buflen); 9862306a36Sopenharmony_ci int ret; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (nents < 0) 10162306a36Sopenharmony_ci return nents; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* IV entry */ 10462306a36Sopenharmony_ci nents += 1; 10562306a36Sopenharmony_ci /* Allocate buffer to hold IV and input scatterlist array */ 10662306a36Sopenharmony_ci ret = alloc_src_req_buf(nkreq, nents, ivsize); 10762306a36Sopenharmony_ci if (ret) 10862306a36Sopenharmony_ci return ret; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci nitrox_creq_copy_iv(nkreq->src, iv, ivsize); 11162306a36Sopenharmony_ci nitrox_creq_set_src_sg(nkreq, nents, ivsize, src, buflen); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int alloc_dst_sglist(struct nitrox_kcrypt_request *nkreq, 11762306a36Sopenharmony_ci struct scatterlist *dst, int ivsize, int buflen) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci int nents = sg_nents_for_len(dst, buflen); 12062306a36Sopenharmony_ci int ret; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (nents < 0) 12362306a36Sopenharmony_ci return nents; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* IV, ORH, COMPLETION entries */ 12662306a36Sopenharmony_ci nents += 3; 12762306a36Sopenharmony_ci /* Allocate buffer to hold ORH, COMPLETION and output scatterlist 12862306a36Sopenharmony_ci * array 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci ret = alloc_dst_req_buf(nkreq, nents); 13162306a36Sopenharmony_ci if (ret) 13262306a36Sopenharmony_ci return ret; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci nitrox_creq_set_orh(nkreq); 13562306a36Sopenharmony_ci nitrox_creq_set_comp(nkreq); 13662306a36Sopenharmony_ci nitrox_creq_set_dst_sg(nkreq, nents, ivsize, dst, buflen); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic void free_src_sglist(struct nitrox_kcrypt_request *nkreq) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci kfree(nkreq->src); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void free_dst_sglist(struct nitrox_kcrypt_request *nkreq) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci kfree(nkreq->dst); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic int nitrox_set_creq(struct nitrox_aead_rctx *rctx) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct se_crypto_request *creq = &rctx->nkreq.creq; 15462306a36Sopenharmony_ci union gph_p3 param3; 15562306a36Sopenharmony_ci int ret; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci creq->flags = rctx->flags; 15862306a36Sopenharmony_ci creq->gfp = (rctx->flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : 15962306a36Sopenharmony_ci GFP_ATOMIC; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci creq->ctrl.value = 0; 16262306a36Sopenharmony_ci creq->opcode = FLEXI_CRYPTO_ENCRYPT_HMAC; 16362306a36Sopenharmony_ci creq->ctrl.s.arg = rctx->ctrl_arg; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci creq->gph.param0 = cpu_to_be16(rctx->cryptlen); 16662306a36Sopenharmony_ci creq->gph.param1 = cpu_to_be16(rctx->cryptlen + rctx->assoclen); 16762306a36Sopenharmony_ci creq->gph.param2 = cpu_to_be16(rctx->ivsize + rctx->assoclen); 16862306a36Sopenharmony_ci param3.iv_offset = 0; 16962306a36Sopenharmony_ci param3.auth_offset = rctx->ivsize; 17062306a36Sopenharmony_ci creq->gph.param3 = cpu_to_be16(param3.param); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci creq->ctx_handle = rctx->ctx_handle; 17362306a36Sopenharmony_ci creq->ctrl.s.ctxl = sizeof(struct flexi_crypto_context); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci ret = alloc_src_sglist(&rctx->nkreq, rctx->src, rctx->iv, rctx->ivsize, 17662306a36Sopenharmony_ci rctx->srclen); 17762306a36Sopenharmony_ci if (ret) 17862306a36Sopenharmony_ci return ret; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ret = alloc_dst_sglist(&rctx->nkreq, rctx->dst, rctx->ivsize, 18162306a36Sopenharmony_ci rctx->dstlen); 18262306a36Sopenharmony_ci if (ret) { 18362306a36Sopenharmony_ci free_src_sglist(&rctx->nkreq); 18462306a36Sopenharmony_ci return ret; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic void nitrox_aead_callback(void *arg, int err) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct aead_request *areq = arg; 19362306a36Sopenharmony_ci struct nitrox_aead_rctx *rctx = aead_request_ctx(areq); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci free_src_sglist(&rctx->nkreq); 19662306a36Sopenharmony_ci free_dst_sglist(&rctx->nkreq); 19762306a36Sopenharmony_ci if (err) { 19862306a36Sopenharmony_ci pr_err_ratelimited("request failed status 0x%0x\n", err); 19962306a36Sopenharmony_ci err = -EINVAL; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci aead_request_complete(areq, err); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic inline bool nitrox_aes_gcm_assoclen_supported(unsigned int assoclen) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci if (assoclen <= 512) 20862306a36Sopenharmony_ci return true; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci return false; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int nitrox_aes_gcm_enc(struct aead_request *areq) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(areq); 21662306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead); 21762306a36Sopenharmony_ci struct nitrox_aead_rctx *rctx = aead_request_ctx(areq); 21862306a36Sopenharmony_ci struct se_crypto_request *creq = &rctx->nkreq.creq; 21962306a36Sopenharmony_ci struct flexi_crypto_context *fctx = nctx->u.fctx; 22062306a36Sopenharmony_ci int ret; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (!nitrox_aes_gcm_assoclen_supported(areq->assoclen)) 22362306a36Sopenharmony_ci return -EINVAL; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci memcpy(fctx->crypto.iv, areq->iv, GCM_AES_SALT_SIZE); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci rctx->cryptlen = areq->cryptlen; 22862306a36Sopenharmony_ci rctx->assoclen = areq->assoclen; 22962306a36Sopenharmony_ci rctx->srclen = areq->assoclen + areq->cryptlen; 23062306a36Sopenharmony_ci rctx->dstlen = rctx->srclen + aead->authsize; 23162306a36Sopenharmony_ci rctx->iv = &areq->iv[GCM_AES_SALT_SIZE]; 23262306a36Sopenharmony_ci rctx->ivsize = GCM_AES_IV_SIZE - GCM_AES_SALT_SIZE; 23362306a36Sopenharmony_ci rctx->flags = areq->base.flags; 23462306a36Sopenharmony_ci rctx->ctx_handle = nctx->u.ctx_handle; 23562306a36Sopenharmony_ci rctx->src = areq->src; 23662306a36Sopenharmony_ci rctx->dst = areq->dst; 23762306a36Sopenharmony_ci rctx->ctrl_arg = ENCRYPT; 23862306a36Sopenharmony_ci ret = nitrox_set_creq(rctx); 23962306a36Sopenharmony_ci if (ret) 24062306a36Sopenharmony_ci return ret; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* send the crypto request */ 24362306a36Sopenharmony_ci return nitrox_process_se_request(nctx->ndev, creq, nitrox_aead_callback, 24462306a36Sopenharmony_ci areq); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic int nitrox_aes_gcm_dec(struct aead_request *areq) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(areq); 25062306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead); 25162306a36Sopenharmony_ci struct nitrox_aead_rctx *rctx = aead_request_ctx(areq); 25262306a36Sopenharmony_ci struct se_crypto_request *creq = &rctx->nkreq.creq; 25362306a36Sopenharmony_ci struct flexi_crypto_context *fctx = nctx->u.fctx; 25462306a36Sopenharmony_ci int ret; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (!nitrox_aes_gcm_assoclen_supported(areq->assoclen)) 25762306a36Sopenharmony_ci return -EINVAL; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci memcpy(fctx->crypto.iv, areq->iv, GCM_AES_SALT_SIZE); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci rctx->cryptlen = areq->cryptlen - aead->authsize; 26262306a36Sopenharmony_ci rctx->assoclen = areq->assoclen; 26362306a36Sopenharmony_ci rctx->srclen = areq->cryptlen + areq->assoclen; 26462306a36Sopenharmony_ci rctx->dstlen = rctx->srclen - aead->authsize; 26562306a36Sopenharmony_ci rctx->iv = &areq->iv[GCM_AES_SALT_SIZE]; 26662306a36Sopenharmony_ci rctx->ivsize = GCM_AES_IV_SIZE - GCM_AES_SALT_SIZE; 26762306a36Sopenharmony_ci rctx->flags = areq->base.flags; 26862306a36Sopenharmony_ci rctx->ctx_handle = nctx->u.ctx_handle; 26962306a36Sopenharmony_ci rctx->src = areq->src; 27062306a36Sopenharmony_ci rctx->dst = areq->dst; 27162306a36Sopenharmony_ci rctx->ctrl_arg = DECRYPT; 27262306a36Sopenharmony_ci ret = nitrox_set_creq(rctx); 27362306a36Sopenharmony_ci if (ret) 27462306a36Sopenharmony_ci return ret; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* send the crypto request */ 27762306a36Sopenharmony_ci return nitrox_process_se_request(nctx->ndev, creq, nitrox_aead_callback, 27862306a36Sopenharmony_ci areq); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic int nitrox_aead_init(struct crypto_aead *aead) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead); 28462306a36Sopenharmony_ci struct crypto_ctx_hdr *chdr; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* get the first device */ 28762306a36Sopenharmony_ci nctx->ndev = nitrox_get_first_device(); 28862306a36Sopenharmony_ci if (!nctx->ndev) 28962306a36Sopenharmony_ci return -ENODEV; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* allocate nitrox crypto context */ 29262306a36Sopenharmony_ci chdr = crypto_alloc_context(nctx->ndev); 29362306a36Sopenharmony_ci if (!chdr) { 29462306a36Sopenharmony_ci nitrox_put_device(nctx->ndev); 29562306a36Sopenharmony_ci return -ENOMEM; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci nctx->chdr = chdr; 29862306a36Sopenharmony_ci nctx->u.ctx_handle = (uintptr_t)((u8 *)chdr->vaddr + 29962306a36Sopenharmony_ci sizeof(struct ctx_hdr)); 30062306a36Sopenharmony_ci nctx->u.fctx->flags.f = 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int nitrox_gcm_common_init(struct crypto_aead *aead) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci int ret; 30862306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead); 30962306a36Sopenharmony_ci union fc_ctx_flags *flags; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci ret = nitrox_aead_init(aead); 31262306a36Sopenharmony_ci if (ret) 31362306a36Sopenharmony_ci return ret; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci flags = &nctx->u.fctx->flags; 31662306a36Sopenharmony_ci flags->w0.cipher_type = CIPHER_AES_GCM; 31762306a36Sopenharmony_ci flags->w0.hash_type = AUTH_NULL; 31862306a36Sopenharmony_ci flags->w0.iv_source = IV_FROM_DPTR; 31962306a36Sopenharmony_ci /* ask microcode to calculate ipad/opad */ 32062306a36Sopenharmony_ci flags->w0.auth_input_type = 1; 32162306a36Sopenharmony_ci flags->f = cpu_to_be64(flags->fu); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int nitrox_aes_gcm_init(struct crypto_aead *aead) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci int ret; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci ret = nitrox_gcm_common_init(aead); 33162306a36Sopenharmony_ci if (ret) 33262306a36Sopenharmony_ci return ret; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci crypto_aead_set_reqsize(aead, 33562306a36Sopenharmony_ci sizeof(struct aead_request) + 33662306a36Sopenharmony_ci sizeof(struct nitrox_aead_rctx)); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void nitrox_aead_exit(struct crypto_aead *aead) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* free the nitrox crypto context */ 34662306a36Sopenharmony_ci if (nctx->u.ctx_handle) { 34762306a36Sopenharmony_ci struct flexi_crypto_context *fctx = nctx->u.fctx; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci memzero_explicit(&fctx->crypto, sizeof(struct crypto_keys)); 35062306a36Sopenharmony_ci memzero_explicit(&fctx->auth, sizeof(struct auth_keys)); 35162306a36Sopenharmony_ci crypto_free_context((void *)nctx->chdr); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci nitrox_put_device(nctx->ndev); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci nctx->u.ctx_handle = 0; 35662306a36Sopenharmony_ci nctx->ndev = NULL; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic int nitrox_rfc4106_setkey(struct crypto_aead *aead, const u8 *key, 36062306a36Sopenharmony_ci unsigned int keylen) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead); 36362306a36Sopenharmony_ci struct flexi_crypto_context *fctx = nctx->u.fctx; 36462306a36Sopenharmony_ci int ret; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (keylen < GCM_AES_SALT_SIZE) 36762306a36Sopenharmony_ci return -EINVAL; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci keylen -= GCM_AES_SALT_SIZE; 37062306a36Sopenharmony_ci ret = nitrox_aes_gcm_setkey(aead, key, keylen); 37162306a36Sopenharmony_ci if (ret) 37262306a36Sopenharmony_ci return ret; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci memcpy(fctx->crypto.iv, key + keylen, GCM_AES_SALT_SIZE); 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic int nitrox_rfc4106_setauthsize(struct crypto_aead *aead, 37962306a36Sopenharmony_ci unsigned int authsize) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci switch (authsize) { 38262306a36Sopenharmony_ci case 8: 38362306a36Sopenharmony_ci case 12: 38462306a36Sopenharmony_ci case 16: 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci default: 38762306a36Sopenharmony_ci return -EINVAL; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return nitrox_aead_setauthsize(aead, authsize); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int nitrox_rfc4106_set_aead_rctx_sglist(struct aead_request *areq) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct nitrox_rfc4106_rctx *rctx = aead_request_ctx_dma(areq); 39662306a36Sopenharmony_ci struct nitrox_aead_rctx *aead_rctx = &rctx->base; 39762306a36Sopenharmony_ci unsigned int assoclen = areq->assoclen - GCM_RFC4106_IV_SIZE; 39862306a36Sopenharmony_ci struct scatterlist *sg; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (areq->assoclen != 16 && areq->assoclen != 20) 40162306a36Sopenharmony_ci return -EINVAL; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci scatterwalk_map_and_copy(rctx->assoc, areq->src, 0, assoclen, 0); 40462306a36Sopenharmony_ci sg_init_table(rctx->src, 3); 40562306a36Sopenharmony_ci sg_set_buf(rctx->src, rctx->assoc, assoclen); 40662306a36Sopenharmony_ci sg = scatterwalk_ffwd(rctx->src + 1, areq->src, areq->assoclen); 40762306a36Sopenharmony_ci if (sg != rctx->src + 1) 40862306a36Sopenharmony_ci sg_chain(rctx->src, 2, sg); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (areq->src != areq->dst) { 41162306a36Sopenharmony_ci sg_init_table(rctx->dst, 3); 41262306a36Sopenharmony_ci sg_set_buf(rctx->dst, rctx->assoc, assoclen); 41362306a36Sopenharmony_ci sg = scatterwalk_ffwd(rctx->dst + 1, areq->dst, areq->assoclen); 41462306a36Sopenharmony_ci if (sg != rctx->dst + 1) 41562306a36Sopenharmony_ci sg_chain(rctx->dst, 2, sg); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci aead_rctx->src = rctx->src; 41962306a36Sopenharmony_ci aead_rctx->dst = (areq->src == areq->dst) ? rctx->src : rctx->dst; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic void nitrox_rfc4106_callback(void *arg, int err) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct aead_request *areq = arg; 42762306a36Sopenharmony_ci struct nitrox_rfc4106_rctx *rctx = aead_request_ctx_dma(areq); 42862306a36Sopenharmony_ci struct nitrox_kcrypt_request *nkreq = &rctx->base.nkreq; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci free_src_sglist(nkreq); 43162306a36Sopenharmony_ci free_dst_sglist(nkreq); 43262306a36Sopenharmony_ci if (err) { 43362306a36Sopenharmony_ci pr_err_ratelimited("request failed status 0x%0x\n", err); 43462306a36Sopenharmony_ci err = -EINVAL; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci aead_request_complete(areq, err); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic int nitrox_rfc4106_enc(struct aead_request *areq) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(areq); 44362306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead); 44462306a36Sopenharmony_ci struct nitrox_rfc4106_rctx *rctx = aead_request_ctx_dma(areq); 44562306a36Sopenharmony_ci struct nitrox_aead_rctx *aead_rctx = &rctx->base; 44662306a36Sopenharmony_ci struct se_crypto_request *creq = &aead_rctx->nkreq.creq; 44762306a36Sopenharmony_ci int ret; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci aead_rctx->cryptlen = areq->cryptlen; 45062306a36Sopenharmony_ci aead_rctx->assoclen = areq->assoclen - GCM_RFC4106_IV_SIZE; 45162306a36Sopenharmony_ci aead_rctx->srclen = aead_rctx->assoclen + aead_rctx->cryptlen; 45262306a36Sopenharmony_ci aead_rctx->dstlen = aead_rctx->srclen + aead->authsize; 45362306a36Sopenharmony_ci aead_rctx->iv = areq->iv; 45462306a36Sopenharmony_ci aead_rctx->ivsize = GCM_RFC4106_IV_SIZE; 45562306a36Sopenharmony_ci aead_rctx->flags = areq->base.flags; 45662306a36Sopenharmony_ci aead_rctx->ctx_handle = nctx->u.ctx_handle; 45762306a36Sopenharmony_ci aead_rctx->ctrl_arg = ENCRYPT; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci ret = nitrox_rfc4106_set_aead_rctx_sglist(areq); 46062306a36Sopenharmony_ci if (ret) 46162306a36Sopenharmony_ci return ret; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci ret = nitrox_set_creq(aead_rctx); 46462306a36Sopenharmony_ci if (ret) 46562306a36Sopenharmony_ci return ret; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* send the crypto request */ 46862306a36Sopenharmony_ci return nitrox_process_se_request(nctx->ndev, creq, 46962306a36Sopenharmony_ci nitrox_rfc4106_callback, areq); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int nitrox_rfc4106_dec(struct aead_request *areq) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(areq); 47562306a36Sopenharmony_ci struct nitrox_crypto_ctx *nctx = crypto_aead_ctx_dma(aead); 47662306a36Sopenharmony_ci struct nitrox_rfc4106_rctx *rctx = aead_request_ctx(areq); 47762306a36Sopenharmony_ci struct nitrox_aead_rctx *aead_rctx = &rctx->base; 47862306a36Sopenharmony_ci struct se_crypto_request *creq = &aead_rctx->nkreq.creq; 47962306a36Sopenharmony_ci int ret; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci aead_rctx->cryptlen = areq->cryptlen - aead->authsize; 48262306a36Sopenharmony_ci aead_rctx->assoclen = areq->assoclen - GCM_RFC4106_IV_SIZE; 48362306a36Sopenharmony_ci aead_rctx->srclen = 48462306a36Sopenharmony_ci areq->cryptlen - GCM_RFC4106_IV_SIZE + areq->assoclen; 48562306a36Sopenharmony_ci aead_rctx->dstlen = aead_rctx->srclen - aead->authsize; 48662306a36Sopenharmony_ci aead_rctx->iv = areq->iv; 48762306a36Sopenharmony_ci aead_rctx->ivsize = GCM_RFC4106_IV_SIZE; 48862306a36Sopenharmony_ci aead_rctx->flags = areq->base.flags; 48962306a36Sopenharmony_ci aead_rctx->ctx_handle = nctx->u.ctx_handle; 49062306a36Sopenharmony_ci aead_rctx->ctrl_arg = DECRYPT; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci ret = nitrox_rfc4106_set_aead_rctx_sglist(areq); 49362306a36Sopenharmony_ci if (ret) 49462306a36Sopenharmony_ci return ret; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci ret = nitrox_set_creq(aead_rctx); 49762306a36Sopenharmony_ci if (ret) 49862306a36Sopenharmony_ci return ret; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* send the crypto request */ 50162306a36Sopenharmony_ci return nitrox_process_se_request(nctx->ndev, creq, 50262306a36Sopenharmony_ci nitrox_rfc4106_callback, areq); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic int nitrox_rfc4106_init(struct crypto_aead *aead) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci int ret; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci ret = nitrox_gcm_common_init(aead); 51062306a36Sopenharmony_ci if (ret) 51162306a36Sopenharmony_ci return ret; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci crypto_aead_set_reqsize_dma(aead, sizeof(struct aead_request) + 51462306a36Sopenharmony_ci sizeof(struct nitrox_rfc4106_rctx)); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic struct aead_alg nitrox_aeads[] = { { 52062306a36Sopenharmony_ci .base = { 52162306a36Sopenharmony_ci .cra_name = "gcm(aes)", 52262306a36Sopenharmony_ci .cra_driver_name = "n5_aes_gcm", 52362306a36Sopenharmony_ci .cra_priority = PRIO, 52462306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY, 52562306a36Sopenharmony_ci .cra_blocksize = 1, 52662306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct nitrox_crypto_ctx), 52762306a36Sopenharmony_ci .cra_alignmask = 0, 52862306a36Sopenharmony_ci .cra_module = THIS_MODULE, 52962306a36Sopenharmony_ci }, 53062306a36Sopenharmony_ci .setkey = nitrox_aes_gcm_setkey, 53162306a36Sopenharmony_ci .setauthsize = nitrox_aes_gcm_setauthsize, 53262306a36Sopenharmony_ci .encrypt = nitrox_aes_gcm_enc, 53362306a36Sopenharmony_ci .decrypt = nitrox_aes_gcm_dec, 53462306a36Sopenharmony_ci .init = nitrox_aes_gcm_init, 53562306a36Sopenharmony_ci .exit = nitrox_aead_exit, 53662306a36Sopenharmony_ci .ivsize = GCM_AES_IV_SIZE, 53762306a36Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 53862306a36Sopenharmony_ci}, { 53962306a36Sopenharmony_ci .base = { 54062306a36Sopenharmony_ci .cra_name = "rfc4106(gcm(aes))", 54162306a36Sopenharmony_ci .cra_driver_name = "n5_rfc4106", 54262306a36Sopenharmony_ci .cra_priority = PRIO, 54362306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY, 54462306a36Sopenharmony_ci .cra_blocksize = 1, 54562306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct nitrox_crypto_ctx), 54662306a36Sopenharmony_ci .cra_alignmask = 0, 54762306a36Sopenharmony_ci .cra_module = THIS_MODULE, 54862306a36Sopenharmony_ci }, 54962306a36Sopenharmony_ci .setkey = nitrox_rfc4106_setkey, 55062306a36Sopenharmony_ci .setauthsize = nitrox_rfc4106_setauthsize, 55162306a36Sopenharmony_ci .encrypt = nitrox_rfc4106_enc, 55262306a36Sopenharmony_ci .decrypt = nitrox_rfc4106_dec, 55362306a36Sopenharmony_ci .init = nitrox_rfc4106_init, 55462306a36Sopenharmony_ci .exit = nitrox_aead_exit, 55562306a36Sopenharmony_ci .ivsize = GCM_RFC4106_IV_SIZE, 55662306a36Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 55762306a36Sopenharmony_ci} }; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ciint nitrox_register_aeads(void) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci return crypto_register_aeads(nitrox_aeads, ARRAY_SIZE(nitrox_aeads)); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_civoid nitrox_unregister_aeads(void) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci crypto_unregister_aeads(nitrox_aeads, ARRAY_SIZE(nitrox_aeads)); 56762306a36Sopenharmony_ci} 568