18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/kernel.h>
38c2ecf20Sopenharmony_ci#include <linux/printk.h>
48c2ecf20Sopenharmony_ci#include <linux/crypto.h>
58c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <crypto/aead.h>
88c2ecf20Sopenharmony_ci#include <crypto/authenc.h>
98c2ecf20Sopenharmony_ci#include <crypto/des.h>
108c2ecf20Sopenharmony_ci#include <crypto/sha.h>
118c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h>
128c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
138c2ecf20Sopenharmony_ci#include <crypto/gcm.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "nitrox_dev.h"
168c2ecf20Sopenharmony_ci#include "nitrox_common.h"
178c2ecf20Sopenharmony_ci#include "nitrox_req.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define GCM_AES_SALT_SIZE	4
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ciunion gph_p3 {
228c2ecf20Sopenharmony_ci	struct {
238c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN_BITFIELD
248c2ecf20Sopenharmony_ci		u16 iv_offset : 8;
258c2ecf20Sopenharmony_ci		u16 auth_offset	: 8;
268c2ecf20Sopenharmony_ci#else
278c2ecf20Sopenharmony_ci		u16 auth_offset	: 8;
288c2ecf20Sopenharmony_ci		u16 iv_offset : 8;
298c2ecf20Sopenharmony_ci#endif
308c2ecf20Sopenharmony_ci	};
318c2ecf20Sopenharmony_ci	u16 param;
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int nitrox_aes_gcm_setkey(struct crypto_aead *aead, const u8 *key,
358c2ecf20Sopenharmony_ci				 unsigned int keylen)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	int aes_keylen;
388c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
398c2ecf20Sopenharmony_ci	struct flexi_crypto_context *fctx;
408c2ecf20Sopenharmony_ci	union fc_ctx_flags flags;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	aes_keylen = flexi_aes_keylen(keylen);
438c2ecf20Sopenharmony_ci	if (aes_keylen < 0)
448c2ecf20Sopenharmony_ci		return -EINVAL;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	/* fill crypto context */
478c2ecf20Sopenharmony_ci	fctx = nctx->u.fctx;
488c2ecf20Sopenharmony_ci	flags.f = be64_to_cpu(fctx->flags.f);
498c2ecf20Sopenharmony_ci	flags.w0.aes_keylen = aes_keylen;
508c2ecf20Sopenharmony_ci	fctx->flags.f = cpu_to_be64(flags.f);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* copy enc key to context */
538c2ecf20Sopenharmony_ci	memset(&fctx->crypto, 0, sizeof(fctx->crypto));
548c2ecf20Sopenharmony_ci	memcpy(fctx->crypto.u.key, key, keylen);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return 0;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int nitrox_aead_setauthsize(struct crypto_aead *aead,
608c2ecf20Sopenharmony_ci				   unsigned int authsize)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
638c2ecf20Sopenharmony_ci	struct flexi_crypto_context *fctx = nctx->u.fctx;
648c2ecf20Sopenharmony_ci	union fc_ctx_flags flags;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	flags.f = be64_to_cpu(fctx->flags.f);
678c2ecf20Sopenharmony_ci	flags.w0.mac_len = authsize;
688c2ecf20Sopenharmony_ci	fctx->flags.f = cpu_to_be64(flags.f);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	aead->authsize = authsize;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic int nitrox_aes_gcm_setauthsize(struct crypto_aead *aead,
768c2ecf20Sopenharmony_ci				      unsigned int authsize)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	switch (authsize) {
798c2ecf20Sopenharmony_ci	case 4:
808c2ecf20Sopenharmony_ci	case 8:
818c2ecf20Sopenharmony_ci	case 12:
828c2ecf20Sopenharmony_ci	case 13:
838c2ecf20Sopenharmony_ci	case 14:
848c2ecf20Sopenharmony_ci	case 15:
858c2ecf20Sopenharmony_ci	case 16:
868c2ecf20Sopenharmony_ci		break;
878c2ecf20Sopenharmony_ci	default:
888c2ecf20Sopenharmony_ci		return -EINVAL;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	return nitrox_aead_setauthsize(aead, authsize);
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic int alloc_src_sglist(struct nitrox_kcrypt_request *nkreq,
958c2ecf20Sopenharmony_ci			    struct scatterlist *src, char *iv, int ivsize,
968c2ecf20Sopenharmony_ci			    int buflen)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	int nents = sg_nents_for_len(src, buflen);
998c2ecf20Sopenharmony_ci	int ret;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (nents < 0)
1028c2ecf20Sopenharmony_ci		return nents;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* IV entry */
1058c2ecf20Sopenharmony_ci	nents += 1;
1068c2ecf20Sopenharmony_ci	/* Allocate buffer to hold IV and input scatterlist array */
1078c2ecf20Sopenharmony_ci	ret = alloc_src_req_buf(nkreq, nents, ivsize);
1088c2ecf20Sopenharmony_ci	if (ret)
1098c2ecf20Sopenharmony_ci		return ret;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	nitrox_creq_copy_iv(nkreq->src, iv, ivsize);
1128c2ecf20Sopenharmony_ci	nitrox_creq_set_src_sg(nkreq, nents, ivsize, src, buflen);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int alloc_dst_sglist(struct nitrox_kcrypt_request *nkreq,
1188c2ecf20Sopenharmony_ci			    struct scatterlist *dst, int ivsize, int buflen)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	int nents = sg_nents_for_len(dst, buflen);
1218c2ecf20Sopenharmony_ci	int ret;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (nents < 0)
1248c2ecf20Sopenharmony_ci		return nents;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* IV, ORH, COMPLETION entries */
1278c2ecf20Sopenharmony_ci	nents += 3;
1288c2ecf20Sopenharmony_ci	/* Allocate buffer to hold ORH, COMPLETION and output scatterlist
1298c2ecf20Sopenharmony_ci	 * array
1308c2ecf20Sopenharmony_ci	 */
1318c2ecf20Sopenharmony_ci	ret = alloc_dst_req_buf(nkreq, nents);
1328c2ecf20Sopenharmony_ci	if (ret)
1338c2ecf20Sopenharmony_ci		return ret;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	nitrox_creq_set_orh(nkreq);
1368c2ecf20Sopenharmony_ci	nitrox_creq_set_comp(nkreq);
1378c2ecf20Sopenharmony_ci	nitrox_creq_set_dst_sg(nkreq, nents, ivsize, dst, buflen);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return 0;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic void free_src_sglist(struct nitrox_kcrypt_request *nkreq)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	kfree(nkreq->src);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic void free_dst_sglist(struct nitrox_kcrypt_request *nkreq)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	kfree(nkreq->dst);
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int nitrox_set_creq(struct nitrox_aead_rctx *rctx)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct se_crypto_request *creq = &rctx->nkreq.creq;
1558c2ecf20Sopenharmony_ci	union gph_p3 param3;
1568c2ecf20Sopenharmony_ci	int ret;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	creq->flags = rctx->flags;
1598c2ecf20Sopenharmony_ci	creq->gfp = (rctx->flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL :
1608c2ecf20Sopenharmony_ci							       GFP_ATOMIC;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	creq->ctrl.value = 0;
1638c2ecf20Sopenharmony_ci	creq->opcode = FLEXI_CRYPTO_ENCRYPT_HMAC;
1648c2ecf20Sopenharmony_ci	creq->ctrl.s.arg = rctx->ctrl_arg;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	creq->gph.param0 = cpu_to_be16(rctx->cryptlen);
1678c2ecf20Sopenharmony_ci	creq->gph.param1 = cpu_to_be16(rctx->cryptlen + rctx->assoclen);
1688c2ecf20Sopenharmony_ci	creq->gph.param2 = cpu_to_be16(rctx->ivsize + rctx->assoclen);
1698c2ecf20Sopenharmony_ci	param3.iv_offset = 0;
1708c2ecf20Sopenharmony_ci	param3.auth_offset = rctx->ivsize;
1718c2ecf20Sopenharmony_ci	creq->gph.param3 = cpu_to_be16(param3.param);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	creq->ctx_handle = rctx->ctx_handle;
1748c2ecf20Sopenharmony_ci	creq->ctrl.s.ctxl = sizeof(struct flexi_crypto_context);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	ret = alloc_src_sglist(&rctx->nkreq, rctx->src, rctx->iv, rctx->ivsize,
1778c2ecf20Sopenharmony_ci			       rctx->srclen);
1788c2ecf20Sopenharmony_ci	if (ret)
1798c2ecf20Sopenharmony_ci		return ret;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	ret = alloc_dst_sglist(&rctx->nkreq, rctx->dst, rctx->ivsize,
1828c2ecf20Sopenharmony_ci			       rctx->dstlen);
1838c2ecf20Sopenharmony_ci	if (ret) {
1848c2ecf20Sopenharmony_ci		free_src_sglist(&rctx->nkreq);
1858c2ecf20Sopenharmony_ci		return ret;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return 0;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void nitrox_aead_callback(void *arg, int err)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct aead_request *areq = arg;
1948c2ecf20Sopenharmony_ci	struct nitrox_aead_rctx *rctx = aead_request_ctx(areq);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	free_src_sglist(&rctx->nkreq);
1978c2ecf20Sopenharmony_ci	free_dst_sglist(&rctx->nkreq);
1988c2ecf20Sopenharmony_ci	if (err) {
1998c2ecf20Sopenharmony_ci		pr_err_ratelimited("request failed status 0x%0x\n", err);
2008c2ecf20Sopenharmony_ci		err = -EINVAL;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	areq->base.complete(&areq->base, err);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic inline bool nitrox_aes_gcm_assoclen_supported(unsigned int assoclen)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	if (assoclen <= 512)
2098c2ecf20Sopenharmony_ci		return true;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	return false;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int nitrox_aes_gcm_enc(struct aead_request *areq)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(areq);
2178c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
2188c2ecf20Sopenharmony_ci	struct nitrox_aead_rctx *rctx = aead_request_ctx(areq);
2198c2ecf20Sopenharmony_ci	struct se_crypto_request *creq = &rctx->nkreq.creq;
2208c2ecf20Sopenharmony_ci	struct flexi_crypto_context *fctx = nctx->u.fctx;
2218c2ecf20Sopenharmony_ci	int ret;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (!nitrox_aes_gcm_assoclen_supported(areq->assoclen))
2248c2ecf20Sopenharmony_ci		return -EINVAL;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	memcpy(fctx->crypto.iv, areq->iv, GCM_AES_SALT_SIZE);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	rctx->cryptlen = areq->cryptlen;
2298c2ecf20Sopenharmony_ci	rctx->assoclen = areq->assoclen;
2308c2ecf20Sopenharmony_ci	rctx->srclen = areq->assoclen + areq->cryptlen;
2318c2ecf20Sopenharmony_ci	rctx->dstlen = rctx->srclen + aead->authsize;
2328c2ecf20Sopenharmony_ci	rctx->iv = &areq->iv[GCM_AES_SALT_SIZE];
2338c2ecf20Sopenharmony_ci	rctx->ivsize = GCM_AES_IV_SIZE - GCM_AES_SALT_SIZE;
2348c2ecf20Sopenharmony_ci	rctx->flags = areq->base.flags;
2358c2ecf20Sopenharmony_ci	rctx->ctx_handle = nctx->u.ctx_handle;
2368c2ecf20Sopenharmony_ci	rctx->src = areq->src;
2378c2ecf20Sopenharmony_ci	rctx->dst = areq->dst;
2388c2ecf20Sopenharmony_ci	rctx->ctrl_arg = ENCRYPT;
2398c2ecf20Sopenharmony_ci	ret = nitrox_set_creq(rctx);
2408c2ecf20Sopenharmony_ci	if (ret)
2418c2ecf20Sopenharmony_ci		return ret;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/* send the crypto request */
2448c2ecf20Sopenharmony_ci	return nitrox_process_se_request(nctx->ndev, creq, nitrox_aead_callback,
2458c2ecf20Sopenharmony_ci					 areq);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic int nitrox_aes_gcm_dec(struct aead_request *areq)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(areq);
2518c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
2528c2ecf20Sopenharmony_ci	struct nitrox_aead_rctx *rctx = aead_request_ctx(areq);
2538c2ecf20Sopenharmony_ci	struct se_crypto_request *creq = &rctx->nkreq.creq;
2548c2ecf20Sopenharmony_ci	struct flexi_crypto_context *fctx = nctx->u.fctx;
2558c2ecf20Sopenharmony_ci	int ret;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (!nitrox_aes_gcm_assoclen_supported(areq->assoclen))
2588c2ecf20Sopenharmony_ci		return -EINVAL;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	memcpy(fctx->crypto.iv, areq->iv, GCM_AES_SALT_SIZE);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	rctx->cryptlen = areq->cryptlen - aead->authsize;
2638c2ecf20Sopenharmony_ci	rctx->assoclen = areq->assoclen;
2648c2ecf20Sopenharmony_ci	rctx->srclen = areq->cryptlen + areq->assoclen;
2658c2ecf20Sopenharmony_ci	rctx->dstlen = rctx->srclen - aead->authsize;
2668c2ecf20Sopenharmony_ci	rctx->iv = &areq->iv[GCM_AES_SALT_SIZE];
2678c2ecf20Sopenharmony_ci	rctx->ivsize = GCM_AES_IV_SIZE - GCM_AES_SALT_SIZE;
2688c2ecf20Sopenharmony_ci	rctx->flags = areq->base.flags;
2698c2ecf20Sopenharmony_ci	rctx->ctx_handle = nctx->u.ctx_handle;
2708c2ecf20Sopenharmony_ci	rctx->src = areq->src;
2718c2ecf20Sopenharmony_ci	rctx->dst = areq->dst;
2728c2ecf20Sopenharmony_ci	rctx->ctrl_arg = DECRYPT;
2738c2ecf20Sopenharmony_ci	ret = nitrox_set_creq(rctx);
2748c2ecf20Sopenharmony_ci	if (ret)
2758c2ecf20Sopenharmony_ci		return ret;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* send the crypto request */
2788c2ecf20Sopenharmony_ci	return nitrox_process_se_request(nctx->ndev, creq, nitrox_aead_callback,
2798c2ecf20Sopenharmony_ci					 areq);
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic int nitrox_aead_init(struct crypto_aead *aead)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
2858c2ecf20Sopenharmony_ci	struct crypto_ctx_hdr *chdr;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/* get the first device */
2888c2ecf20Sopenharmony_ci	nctx->ndev = nitrox_get_first_device();
2898c2ecf20Sopenharmony_ci	if (!nctx->ndev)
2908c2ecf20Sopenharmony_ci		return -ENODEV;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* allocate nitrox crypto context */
2938c2ecf20Sopenharmony_ci	chdr = crypto_alloc_context(nctx->ndev);
2948c2ecf20Sopenharmony_ci	if (!chdr) {
2958c2ecf20Sopenharmony_ci		nitrox_put_device(nctx->ndev);
2968c2ecf20Sopenharmony_ci		return -ENOMEM;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci	nctx->chdr = chdr;
2998c2ecf20Sopenharmony_ci	nctx->u.ctx_handle = (uintptr_t)((u8 *)chdr->vaddr +
3008c2ecf20Sopenharmony_ci					 sizeof(struct ctx_hdr));
3018c2ecf20Sopenharmony_ci	nctx->u.fctx->flags.f = 0;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return 0;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic int nitrox_gcm_common_init(struct crypto_aead *aead)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	int ret;
3098c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
3108c2ecf20Sopenharmony_ci	union fc_ctx_flags *flags;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	ret = nitrox_aead_init(aead);
3138c2ecf20Sopenharmony_ci	if (ret)
3148c2ecf20Sopenharmony_ci		return ret;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	flags = &nctx->u.fctx->flags;
3178c2ecf20Sopenharmony_ci	flags->w0.cipher_type = CIPHER_AES_GCM;
3188c2ecf20Sopenharmony_ci	flags->w0.hash_type = AUTH_NULL;
3198c2ecf20Sopenharmony_ci	flags->w0.iv_source = IV_FROM_DPTR;
3208c2ecf20Sopenharmony_ci	/* ask microcode to calculate ipad/opad */
3218c2ecf20Sopenharmony_ci	flags->w0.auth_input_type = 1;
3228c2ecf20Sopenharmony_ci	flags->f = be64_to_cpu(flags->f);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	return 0;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic int nitrox_aes_gcm_init(struct crypto_aead *aead)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	int ret;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	ret = nitrox_gcm_common_init(aead);
3328c2ecf20Sopenharmony_ci	if (ret)
3338c2ecf20Sopenharmony_ci		return ret;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	crypto_aead_set_reqsize(aead,
3368c2ecf20Sopenharmony_ci				sizeof(struct aead_request) +
3378c2ecf20Sopenharmony_ci					sizeof(struct nitrox_aead_rctx));
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return 0;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic void nitrox_aead_exit(struct crypto_aead *aead)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/* free the nitrox crypto context */
3478c2ecf20Sopenharmony_ci	if (nctx->u.ctx_handle) {
3488c2ecf20Sopenharmony_ci		struct flexi_crypto_context *fctx = nctx->u.fctx;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		memzero_explicit(&fctx->crypto, sizeof(struct crypto_keys));
3518c2ecf20Sopenharmony_ci		memzero_explicit(&fctx->auth, sizeof(struct auth_keys));
3528c2ecf20Sopenharmony_ci		crypto_free_context((void *)nctx->chdr);
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci	nitrox_put_device(nctx->ndev);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	nctx->u.ctx_handle = 0;
3578c2ecf20Sopenharmony_ci	nctx->ndev = NULL;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic int nitrox_rfc4106_setkey(struct crypto_aead *aead, const u8 *key,
3618c2ecf20Sopenharmony_ci				 unsigned int keylen)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
3648c2ecf20Sopenharmony_ci	struct flexi_crypto_context *fctx = nctx->u.fctx;
3658c2ecf20Sopenharmony_ci	int ret;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (keylen < GCM_AES_SALT_SIZE)
3688c2ecf20Sopenharmony_ci		return -EINVAL;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	keylen -= GCM_AES_SALT_SIZE;
3718c2ecf20Sopenharmony_ci	ret = nitrox_aes_gcm_setkey(aead, key, keylen);
3728c2ecf20Sopenharmony_ci	if (ret)
3738c2ecf20Sopenharmony_ci		return ret;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	memcpy(fctx->crypto.iv, key + keylen, GCM_AES_SALT_SIZE);
3768c2ecf20Sopenharmony_ci	return 0;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int nitrox_rfc4106_setauthsize(struct crypto_aead *aead,
3808c2ecf20Sopenharmony_ci				      unsigned int authsize)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	switch (authsize) {
3838c2ecf20Sopenharmony_ci	case 8:
3848c2ecf20Sopenharmony_ci	case 12:
3858c2ecf20Sopenharmony_ci	case 16:
3868c2ecf20Sopenharmony_ci		break;
3878c2ecf20Sopenharmony_ci	default:
3888c2ecf20Sopenharmony_ci		return -EINVAL;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return nitrox_aead_setauthsize(aead, authsize);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic int nitrox_rfc4106_set_aead_rctx_sglist(struct aead_request *areq)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct nitrox_rfc4106_rctx *rctx = aead_request_ctx(areq);
3978c2ecf20Sopenharmony_ci	struct nitrox_aead_rctx *aead_rctx = &rctx->base;
3988c2ecf20Sopenharmony_ci	unsigned int assoclen = areq->assoclen - GCM_RFC4106_IV_SIZE;
3998c2ecf20Sopenharmony_ci	struct scatterlist *sg;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (areq->assoclen != 16 && areq->assoclen != 20)
4028c2ecf20Sopenharmony_ci		return -EINVAL;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(rctx->assoc, areq->src, 0, assoclen, 0);
4058c2ecf20Sopenharmony_ci	sg_init_table(rctx->src, 3);
4068c2ecf20Sopenharmony_ci	sg_set_buf(rctx->src, rctx->assoc, assoclen);
4078c2ecf20Sopenharmony_ci	sg = scatterwalk_ffwd(rctx->src + 1, areq->src, areq->assoclen);
4088c2ecf20Sopenharmony_ci	if (sg != rctx->src + 1)
4098c2ecf20Sopenharmony_ci		sg_chain(rctx->src, 2, sg);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (areq->src != areq->dst) {
4128c2ecf20Sopenharmony_ci		sg_init_table(rctx->dst, 3);
4138c2ecf20Sopenharmony_ci		sg_set_buf(rctx->dst, rctx->assoc, assoclen);
4148c2ecf20Sopenharmony_ci		sg = scatterwalk_ffwd(rctx->dst + 1, areq->dst, areq->assoclen);
4158c2ecf20Sopenharmony_ci		if (sg != rctx->dst + 1)
4168c2ecf20Sopenharmony_ci			sg_chain(rctx->dst, 2, sg);
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	aead_rctx->src = rctx->src;
4208c2ecf20Sopenharmony_ci	aead_rctx->dst = (areq->src == areq->dst) ? rctx->src : rctx->dst;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic void nitrox_rfc4106_callback(void *arg, int err)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct aead_request *areq = arg;
4288c2ecf20Sopenharmony_ci	struct nitrox_rfc4106_rctx *rctx = aead_request_ctx(areq);
4298c2ecf20Sopenharmony_ci	struct nitrox_kcrypt_request *nkreq = &rctx->base.nkreq;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	free_src_sglist(nkreq);
4328c2ecf20Sopenharmony_ci	free_dst_sglist(nkreq);
4338c2ecf20Sopenharmony_ci	if (err) {
4348c2ecf20Sopenharmony_ci		pr_err_ratelimited("request failed status 0x%0x\n", err);
4358c2ecf20Sopenharmony_ci		err = -EINVAL;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	areq->base.complete(&areq->base, err);
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic int nitrox_rfc4106_enc(struct aead_request *areq)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(areq);
4448c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
4458c2ecf20Sopenharmony_ci	struct nitrox_rfc4106_rctx *rctx = aead_request_ctx(areq);
4468c2ecf20Sopenharmony_ci	struct nitrox_aead_rctx *aead_rctx = &rctx->base;
4478c2ecf20Sopenharmony_ci	struct se_crypto_request *creq = &aead_rctx->nkreq.creq;
4488c2ecf20Sopenharmony_ci	int ret;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	aead_rctx->cryptlen = areq->cryptlen;
4518c2ecf20Sopenharmony_ci	aead_rctx->assoclen = areq->assoclen - GCM_RFC4106_IV_SIZE;
4528c2ecf20Sopenharmony_ci	aead_rctx->srclen = aead_rctx->assoclen + aead_rctx->cryptlen;
4538c2ecf20Sopenharmony_ci	aead_rctx->dstlen = aead_rctx->srclen + aead->authsize;
4548c2ecf20Sopenharmony_ci	aead_rctx->iv = areq->iv;
4558c2ecf20Sopenharmony_ci	aead_rctx->ivsize = GCM_RFC4106_IV_SIZE;
4568c2ecf20Sopenharmony_ci	aead_rctx->flags = areq->base.flags;
4578c2ecf20Sopenharmony_ci	aead_rctx->ctx_handle = nctx->u.ctx_handle;
4588c2ecf20Sopenharmony_ci	aead_rctx->ctrl_arg = ENCRYPT;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	ret = nitrox_rfc4106_set_aead_rctx_sglist(areq);
4618c2ecf20Sopenharmony_ci	if (ret)
4628c2ecf20Sopenharmony_ci		return ret;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	ret = nitrox_set_creq(aead_rctx);
4658c2ecf20Sopenharmony_ci	if (ret)
4668c2ecf20Sopenharmony_ci		return ret;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	/* send the crypto request */
4698c2ecf20Sopenharmony_ci	return nitrox_process_se_request(nctx->ndev, creq,
4708c2ecf20Sopenharmony_ci					 nitrox_rfc4106_callback, areq);
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic int nitrox_rfc4106_dec(struct aead_request *areq)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(areq);
4768c2ecf20Sopenharmony_ci	struct nitrox_crypto_ctx *nctx = crypto_aead_ctx(aead);
4778c2ecf20Sopenharmony_ci	struct nitrox_rfc4106_rctx *rctx = aead_request_ctx(areq);
4788c2ecf20Sopenharmony_ci	struct nitrox_aead_rctx *aead_rctx = &rctx->base;
4798c2ecf20Sopenharmony_ci	struct se_crypto_request *creq = &aead_rctx->nkreq.creq;
4808c2ecf20Sopenharmony_ci	int ret;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	aead_rctx->cryptlen = areq->cryptlen - aead->authsize;
4838c2ecf20Sopenharmony_ci	aead_rctx->assoclen = areq->assoclen - GCM_RFC4106_IV_SIZE;
4848c2ecf20Sopenharmony_ci	aead_rctx->srclen =
4858c2ecf20Sopenharmony_ci		areq->cryptlen - GCM_RFC4106_IV_SIZE + areq->assoclen;
4868c2ecf20Sopenharmony_ci	aead_rctx->dstlen = aead_rctx->srclen - aead->authsize;
4878c2ecf20Sopenharmony_ci	aead_rctx->iv = areq->iv;
4888c2ecf20Sopenharmony_ci	aead_rctx->ivsize = GCM_RFC4106_IV_SIZE;
4898c2ecf20Sopenharmony_ci	aead_rctx->flags = areq->base.flags;
4908c2ecf20Sopenharmony_ci	aead_rctx->ctx_handle = nctx->u.ctx_handle;
4918c2ecf20Sopenharmony_ci	aead_rctx->ctrl_arg = DECRYPT;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	ret = nitrox_rfc4106_set_aead_rctx_sglist(areq);
4948c2ecf20Sopenharmony_ci	if (ret)
4958c2ecf20Sopenharmony_ci		return ret;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	ret = nitrox_set_creq(aead_rctx);
4988c2ecf20Sopenharmony_ci	if (ret)
4998c2ecf20Sopenharmony_ci		return ret;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	/* send the crypto request */
5028c2ecf20Sopenharmony_ci	return nitrox_process_se_request(nctx->ndev, creq,
5038c2ecf20Sopenharmony_ci					 nitrox_rfc4106_callback, areq);
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic int nitrox_rfc4106_init(struct crypto_aead *aead)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	int ret;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	ret = nitrox_gcm_common_init(aead);
5118c2ecf20Sopenharmony_ci	if (ret)
5128c2ecf20Sopenharmony_ci		return ret;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	crypto_aead_set_reqsize(aead, sizeof(struct aead_request) +
5158c2ecf20Sopenharmony_ci				sizeof(struct nitrox_rfc4106_rctx));
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	return 0;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic struct aead_alg nitrox_aeads[] = { {
5218c2ecf20Sopenharmony_ci	.base = {
5228c2ecf20Sopenharmony_ci		.cra_name = "gcm(aes)",
5238c2ecf20Sopenharmony_ci		.cra_driver_name = "n5_aes_gcm",
5248c2ecf20Sopenharmony_ci		.cra_priority = PRIO,
5258c2ecf20Sopenharmony_ci		.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY,
5268c2ecf20Sopenharmony_ci		.cra_blocksize = 1,
5278c2ecf20Sopenharmony_ci		.cra_ctxsize = sizeof(struct nitrox_crypto_ctx),
5288c2ecf20Sopenharmony_ci		.cra_alignmask = 0,
5298c2ecf20Sopenharmony_ci		.cra_module = THIS_MODULE,
5308c2ecf20Sopenharmony_ci	},
5318c2ecf20Sopenharmony_ci	.setkey = nitrox_aes_gcm_setkey,
5328c2ecf20Sopenharmony_ci	.setauthsize = nitrox_aes_gcm_setauthsize,
5338c2ecf20Sopenharmony_ci	.encrypt = nitrox_aes_gcm_enc,
5348c2ecf20Sopenharmony_ci	.decrypt = nitrox_aes_gcm_dec,
5358c2ecf20Sopenharmony_ci	.init = nitrox_aes_gcm_init,
5368c2ecf20Sopenharmony_ci	.exit = nitrox_aead_exit,
5378c2ecf20Sopenharmony_ci	.ivsize = GCM_AES_IV_SIZE,
5388c2ecf20Sopenharmony_ci	.maxauthsize = AES_BLOCK_SIZE,
5398c2ecf20Sopenharmony_ci}, {
5408c2ecf20Sopenharmony_ci	.base = {
5418c2ecf20Sopenharmony_ci		.cra_name = "rfc4106(gcm(aes))",
5428c2ecf20Sopenharmony_ci		.cra_driver_name = "n5_rfc4106",
5438c2ecf20Sopenharmony_ci		.cra_priority = PRIO,
5448c2ecf20Sopenharmony_ci		.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY,
5458c2ecf20Sopenharmony_ci		.cra_blocksize = 1,
5468c2ecf20Sopenharmony_ci		.cra_ctxsize = sizeof(struct nitrox_crypto_ctx),
5478c2ecf20Sopenharmony_ci		.cra_alignmask = 0,
5488c2ecf20Sopenharmony_ci		.cra_module = THIS_MODULE,
5498c2ecf20Sopenharmony_ci	},
5508c2ecf20Sopenharmony_ci	.setkey = nitrox_rfc4106_setkey,
5518c2ecf20Sopenharmony_ci	.setauthsize = nitrox_rfc4106_setauthsize,
5528c2ecf20Sopenharmony_ci	.encrypt = nitrox_rfc4106_enc,
5538c2ecf20Sopenharmony_ci	.decrypt = nitrox_rfc4106_dec,
5548c2ecf20Sopenharmony_ci	.init = nitrox_rfc4106_init,
5558c2ecf20Sopenharmony_ci	.exit = nitrox_aead_exit,
5568c2ecf20Sopenharmony_ci	.ivsize = GCM_RFC4106_IV_SIZE,
5578c2ecf20Sopenharmony_ci	.maxauthsize = AES_BLOCK_SIZE,
5588c2ecf20Sopenharmony_ci} };
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ciint nitrox_register_aeads(void)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	return crypto_register_aeads(nitrox_aeads, ARRAY_SIZE(nitrox_aeads));
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_civoid nitrox_unregister_aeads(void)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	crypto_unregister_aeads(nitrox_aeads, ARRAY_SIZE(nitrox_aeads));
5688c2ecf20Sopenharmony_ci}
569