18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * AES CCM routines supporting the Power 7+ Nest Accelerators driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2012 International Business Machines Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Kent Yoder <yoder1@us.ibm.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h>
118c2ecf20Sopenharmony_ci#include <crypto/aes.h>
128c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
138c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/types.h>
168c2ecf20Sopenharmony_ci#include <linux/crypto.h>
178c2ecf20Sopenharmony_ci#include <asm/vio.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "nx_csbcpb.h"
208c2ecf20Sopenharmony_ci#include "nx.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic int ccm_aes_nx_set_key(struct crypto_aead *tfm,
248c2ecf20Sopenharmony_ci			      const u8           *in_key,
258c2ecf20Sopenharmony_ci			      unsigned int        key_len)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
288c2ecf20Sopenharmony_ci	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
298c2ecf20Sopenharmony_ci	struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	nx_ctx_init(nx_ctx, HCOP_FC_AES);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	switch (key_len) {
348c2ecf20Sopenharmony_ci	case AES_KEYSIZE_128:
358c2ecf20Sopenharmony_ci		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
368c2ecf20Sopenharmony_ci		NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
378c2ecf20Sopenharmony_ci		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
388c2ecf20Sopenharmony_ci		break;
398c2ecf20Sopenharmony_ci	default:
408c2ecf20Sopenharmony_ci		return -EINVAL;
418c2ecf20Sopenharmony_ci	}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	csbcpb->cpb.hdr.mode = NX_MODE_AES_CCM;
448c2ecf20Sopenharmony_ci	memcpy(csbcpb->cpb.aes_ccm.key, in_key, key_len);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_CCA;
478c2ecf20Sopenharmony_ci	memcpy(csbcpb_aead->cpb.aes_cca.key, in_key, key_len);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	return 0;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic int ccm4309_aes_nx_set_key(struct crypto_aead *tfm,
548c2ecf20Sopenharmony_ci				  const u8           *in_key,
558c2ecf20Sopenharmony_ci				  unsigned int        key_len)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (key_len < 3)
608c2ecf20Sopenharmony_ci		return -EINVAL;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	key_len -= 3;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	memcpy(nx_ctx->priv.ccm.nonce, in_key + key_len, 3);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	return ccm_aes_nx_set_key(tfm, in_key, key_len);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int ccm_aes_nx_setauthsize(struct crypto_aead *tfm,
708c2ecf20Sopenharmony_ci				  unsigned int authsize)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	switch (authsize) {
738c2ecf20Sopenharmony_ci	case 4:
748c2ecf20Sopenharmony_ci	case 6:
758c2ecf20Sopenharmony_ci	case 8:
768c2ecf20Sopenharmony_ci	case 10:
778c2ecf20Sopenharmony_ci	case 12:
788c2ecf20Sopenharmony_ci	case 14:
798c2ecf20Sopenharmony_ci	case 16:
808c2ecf20Sopenharmony_ci		break;
818c2ecf20Sopenharmony_ci	default:
828c2ecf20Sopenharmony_ci		return -EINVAL;
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return 0;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm,
898c2ecf20Sopenharmony_ci				      unsigned int authsize)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	switch (authsize) {
928c2ecf20Sopenharmony_ci	case 8:
938c2ecf20Sopenharmony_ci	case 12:
948c2ecf20Sopenharmony_ci	case 16:
958c2ecf20Sopenharmony_ci		break;
968c2ecf20Sopenharmony_ci	default:
978c2ecf20Sopenharmony_ci		return -EINVAL;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/* taken from crypto/ccm.c */
1048c2ecf20Sopenharmony_cistatic int set_msg_len(u8 *block, unsigned int msglen, int csize)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	__be32 data;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	memset(block, 0, csize);
1098c2ecf20Sopenharmony_ci	block += csize;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (csize >= 4)
1128c2ecf20Sopenharmony_ci		csize = 4;
1138c2ecf20Sopenharmony_ci	else if (msglen > (unsigned int)(1 << (8 * csize)))
1148c2ecf20Sopenharmony_ci		return -EOVERFLOW;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	data = cpu_to_be32(msglen);
1178c2ecf20Sopenharmony_ci	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/* taken from crypto/ccm.c */
1238c2ecf20Sopenharmony_cistatic inline int crypto_ccm_check_iv(const u8 *iv)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	/* 2 <= L <= 8, so 1 <= L' <= 7. */
1268c2ecf20Sopenharmony_ci	if (1 > iv[0] || iv[0] > 7)
1278c2ecf20Sopenharmony_ci		return -EINVAL;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return 0;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/* based on code from crypto/ccm.c */
1338c2ecf20Sopenharmony_cistatic int generate_b0(u8 *iv, unsigned int assoclen, unsigned int authsize,
1348c2ecf20Sopenharmony_ci		       unsigned int cryptlen, u8 *b0)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	unsigned int l, lp, m = authsize;
1378c2ecf20Sopenharmony_ci	int rc;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	memcpy(b0, iv, 16);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	lp = b0[0];
1428c2ecf20Sopenharmony_ci	l = lp + 1;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* set m, bits 3-5 */
1458c2ecf20Sopenharmony_ci	*b0 |= (8 * ((m - 2) / 2));
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* set adata, bit 6, if associated data is used */
1488c2ecf20Sopenharmony_ci	if (assoclen)
1498c2ecf20Sopenharmony_ci		*b0 |= 64;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	rc = set_msg_len(b0 + 16 - l, cryptlen, l);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return rc;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic int generate_pat(u8                   *iv,
1578c2ecf20Sopenharmony_ci			struct aead_request  *req,
1588c2ecf20Sopenharmony_ci			struct nx_crypto_ctx *nx_ctx,
1598c2ecf20Sopenharmony_ci			unsigned int          authsize,
1608c2ecf20Sopenharmony_ci			unsigned int          nbytes,
1618c2ecf20Sopenharmony_ci			unsigned int	      assoclen,
1628c2ecf20Sopenharmony_ci			u8                   *out)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct nx_sg *nx_insg = nx_ctx->in_sg;
1658c2ecf20Sopenharmony_ci	struct nx_sg *nx_outsg = nx_ctx->out_sg;
1668c2ecf20Sopenharmony_ci	unsigned int iauth_len = 0;
1678c2ecf20Sopenharmony_ci	u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL;
1688c2ecf20Sopenharmony_ci	int rc;
1698c2ecf20Sopenharmony_ci	unsigned int max_sg_len;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* zero the ctr value */
1728c2ecf20Sopenharmony_ci	memset(iv + 15 - iv[0], 0, iv[0] + 1);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/* page 78 of nx_wb.pdf has,
1758c2ecf20Sopenharmony_ci	 * Note: RFC3610 allows the AAD data to be up to 2^64 -1 bytes
1768c2ecf20Sopenharmony_ci	 * in length. If a full message is used, the AES CCA implementation
1778c2ecf20Sopenharmony_ci	 * restricts the maximum AAD length to 2^32 -1 bytes.
1788c2ecf20Sopenharmony_ci	 * If partial messages are used, the implementation supports
1798c2ecf20Sopenharmony_ci	 * 2^64 -1 bytes maximum AAD length.
1808c2ecf20Sopenharmony_ci	 *
1818c2ecf20Sopenharmony_ci	 * However, in the cryptoapi's aead_request structure,
1828c2ecf20Sopenharmony_ci	 * assoclen is an unsigned int, thus it cannot hold a length
1838c2ecf20Sopenharmony_ci	 * value greater than 2^32 - 1.
1848c2ecf20Sopenharmony_ci	 * Thus the AAD is further constrained by this and is never
1858c2ecf20Sopenharmony_ci	 * greater than 2^32.
1868c2ecf20Sopenharmony_ci	 */
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (!assoclen) {
1898c2ecf20Sopenharmony_ci		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
1908c2ecf20Sopenharmony_ci	} else if (assoclen <= 14) {
1918c2ecf20Sopenharmony_ci		/* if associated data is 14 bytes or less, we do 1 GCM
1928c2ecf20Sopenharmony_ci		 * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1,
1938c2ecf20Sopenharmony_ci		 * which is fed in through the source buffers here */
1948c2ecf20Sopenharmony_ci		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
1958c2ecf20Sopenharmony_ci		b1 = nx_ctx->priv.ccm.iauth_tag;
1968c2ecf20Sopenharmony_ci		iauth_len = assoclen;
1978c2ecf20Sopenharmony_ci	} else if (assoclen <= 65280) {
1988c2ecf20Sopenharmony_ci		/* if associated data is less than (2^16 - 2^8), we construct
1998c2ecf20Sopenharmony_ci		 * B1 differently and feed in the associated data to a CCA
2008c2ecf20Sopenharmony_ci		 * operation */
2018c2ecf20Sopenharmony_ci		b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
2028c2ecf20Sopenharmony_ci		b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
2038c2ecf20Sopenharmony_ci		iauth_len = 14;
2048c2ecf20Sopenharmony_ci	} else {
2058c2ecf20Sopenharmony_ci		b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
2068c2ecf20Sopenharmony_ci		b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
2078c2ecf20Sopenharmony_ci		iauth_len = 10;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	/* generate B0 */
2118c2ecf20Sopenharmony_ci	rc = generate_b0(iv, assoclen, authsize, nbytes, b0);
2128c2ecf20Sopenharmony_ci	if (rc)
2138c2ecf20Sopenharmony_ci		return rc;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* generate B1:
2168c2ecf20Sopenharmony_ci	 * add control info for associated data
2178c2ecf20Sopenharmony_ci	 * RFC 3610 and NIST Special Publication 800-38C
2188c2ecf20Sopenharmony_ci	 */
2198c2ecf20Sopenharmony_ci	if (b1) {
2208c2ecf20Sopenharmony_ci		memset(b1, 0, 16);
2218c2ecf20Sopenharmony_ci		if (assoclen <= 65280) {
2228c2ecf20Sopenharmony_ci			*(u16 *)b1 = assoclen;
2238c2ecf20Sopenharmony_ci			scatterwalk_map_and_copy(b1 + 2, req->src, 0,
2248c2ecf20Sopenharmony_ci					 iauth_len, SCATTERWALK_FROM_SG);
2258c2ecf20Sopenharmony_ci		} else {
2268c2ecf20Sopenharmony_ci			*(u16 *)b1 = (u16)(0xfffe);
2278c2ecf20Sopenharmony_ci			*(u32 *)&b1[2] = assoclen;
2288c2ecf20Sopenharmony_ci			scatterwalk_map_and_copy(b1 + 6, req->src, 0,
2298c2ecf20Sopenharmony_ci					 iauth_len, SCATTERWALK_FROM_SG);
2308c2ecf20Sopenharmony_ci		}
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* now copy any remaining AAD to scatterlist and call nx... */
2348c2ecf20Sopenharmony_ci	if (!assoclen) {
2358c2ecf20Sopenharmony_ci		return rc;
2368c2ecf20Sopenharmony_ci	} else if (assoclen <= 14) {
2378c2ecf20Sopenharmony_ci		unsigned int len = 16;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci		nx_insg = nx_build_sg_list(nx_insg, b1, &len, nx_ctx->ap->sglen);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		if (len != 16)
2428c2ecf20Sopenharmony_ci			return -EINVAL;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		nx_outsg = nx_build_sg_list(nx_outsg, tmp, &len,
2458c2ecf20Sopenharmony_ci					    nx_ctx->ap->sglen);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		if (len != 16)
2488c2ecf20Sopenharmony_ci			return -EINVAL;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci		/* inlen should be negative, indicating to phyp that its a
2518c2ecf20Sopenharmony_ci		 * pointer to an sg list */
2528c2ecf20Sopenharmony_ci		nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) *
2538c2ecf20Sopenharmony_ci					sizeof(struct nx_sg);
2548c2ecf20Sopenharmony_ci		nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) *
2558c2ecf20Sopenharmony_ci					sizeof(struct nx_sg);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT;
2588c2ecf20Sopenharmony_ci		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci		result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
2638c2ecf20Sopenharmony_ci				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
2648c2ecf20Sopenharmony_ci		if (rc)
2658c2ecf20Sopenharmony_ci			return rc;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		atomic_inc(&(nx_ctx->stats->aes_ops));
2688c2ecf20Sopenharmony_ci		atomic64_add(assoclen, &nx_ctx->stats->aes_bytes);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	} else {
2718c2ecf20Sopenharmony_ci		unsigned int processed = 0, to_process;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		processed += iauth_len;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		/* page_limit: number of sg entries that fit on one page */
2768c2ecf20Sopenharmony_ci		max_sg_len = min_t(u64, nx_ctx->ap->sglen,
2778c2ecf20Sopenharmony_ci				nx_driver.of.max_sg_len/sizeof(struct nx_sg));
2788c2ecf20Sopenharmony_ci		max_sg_len = min_t(u64, max_sg_len,
2798c2ecf20Sopenharmony_ci				nx_ctx->ap->databytelen/NX_PAGE_SIZE);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci		do {
2828c2ecf20Sopenharmony_ci			to_process = min_t(u32, assoclen - processed,
2838c2ecf20Sopenharmony_ci					   nx_ctx->ap->databytelen);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci			nx_insg = nx_walk_and_build(nx_ctx->in_sg,
2868c2ecf20Sopenharmony_ci						    nx_ctx->ap->sglen,
2878c2ecf20Sopenharmony_ci						    req->src, processed,
2888c2ecf20Sopenharmony_ci						    &to_process);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci			if ((to_process + processed) < assoclen) {
2918c2ecf20Sopenharmony_ci				NX_CPB_FDM(nx_ctx->csbcpb_aead) |=
2928c2ecf20Sopenharmony_ci					NX_FDM_INTERMEDIATE;
2938c2ecf20Sopenharmony_ci			} else {
2948c2ecf20Sopenharmony_ci				NX_CPB_FDM(nx_ctx->csbcpb_aead) &=
2958c2ecf20Sopenharmony_ci					~NX_FDM_INTERMEDIATE;
2968c2ecf20Sopenharmony_ci			}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci			nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
3008c2ecf20Sopenharmony_ci						sizeof(struct nx_sg);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci			result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci			rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
3058c2ecf20Sopenharmony_ci				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
3068c2ecf20Sopenharmony_ci			if (rc)
3078c2ecf20Sopenharmony_ci				return rc;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci			memcpy(nx_ctx->csbcpb_aead->cpb.aes_cca.b0,
3108c2ecf20Sopenharmony_ci				nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0,
3118c2ecf20Sopenharmony_ci				AES_BLOCK_SIZE);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci			NX_CPB_FDM(nx_ctx->csbcpb_aead) |= NX_FDM_CONTINUATION;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci			atomic_inc(&(nx_ctx->stats->aes_ops));
3168c2ecf20Sopenharmony_ci			atomic64_add(assoclen, &nx_ctx->stats->aes_bytes);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci			processed += to_process;
3198c2ecf20Sopenharmony_ci		} while (processed < assoclen);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	memcpy(out, result, AES_BLOCK_SIZE);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return rc;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic int ccm_nx_decrypt(struct aead_request   *req,
3308c2ecf20Sopenharmony_ci			  u8                    *iv,
3318c2ecf20Sopenharmony_ci			  unsigned int assoclen)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
3348c2ecf20Sopenharmony_ci	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
3358c2ecf20Sopenharmony_ci	unsigned int nbytes = req->cryptlen;
3368c2ecf20Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
3378c2ecf20Sopenharmony_ci	struct nx_ccm_priv *priv = &nx_ctx->priv.ccm;
3388c2ecf20Sopenharmony_ci	unsigned long irq_flags;
3398c2ecf20Sopenharmony_ci	unsigned int processed = 0, to_process;
3408c2ecf20Sopenharmony_ci	int rc = -1;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	nbytes -= authsize;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/* copy out the auth tag to compare with later */
3478c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(priv->oauth_tag,
3488c2ecf20Sopenharmony_ci				 req->src, nbytes + req->assoclen, authsize,
3498c2ecf20Sopenharmony_ci				 SCATTERWALK_FROM_SG);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen,
3528c2ecf20Sopenharmony_ci			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
3538c2ecf20Sopenharmony_ci	if (rc)
3548c2ecf20Sopenharmony_ci		goto out;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	do {
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		/* to_process: the AES_BLOCK_SIZE data chunk to process in this
3598c2ecf20Sopenharmony_ci		 * update. This value is bound by sg list limits.
3608c2ecf20Sopenharmony_ci		 */
3618c2ecf20Sopenharmony_ci		to_process = nbytes - processed;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		if ((to_process + processed) < nbytes)
3648c2ecf20Sopenharmony_ci			NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
3658c2ecf20Sopenharmony_ci		else
3668c2ecf20Sopenharmony_ci			NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci		NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src,
3718c2ecf20Sopenharmony_ci				       &to_process, processed + req->assoclen,
3728c2ecf20Sopenharmony_ci				       csbcpb->cpb.aes_ccm.iv_or_ctr);
3738c2ecf20Sopenharmony_ci		if (rc)
3748c2ecf20Sopenharmony_ci			goto out;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
3778c2ecf20Sopenharmony_ci			   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
3788c2ecf20Sopenharmony_ci		if (rc)
3798c2ecf20Sopenharmony_ci			goto out;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci		/* for partial completion, copy following for next
3828c2ecf20Sopenharmony_ci		 * entry into loop...
3838c2ecf20Sopenharmony_ci		 */
3848c2ecf20Sopenharmony_ci		memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
3858c2ecf20Sopenharmony_ci		memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
3868c2ecf20Sopenharmony_ci			csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
3878c2ecf20Sopenharmony_ci		memcpy(csbcpb->cpb.aes_ccm.in_s0,
3888c2ecf20Sopenharmony_ci			csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci		/* update stats */
3938c2ecf20Sopenharmony_ci		atomic_inc(&(nx_ctx->stats->aes_ops));
3948c2ecf20Sopenharmony_ci		atomic64_add(csbcpb->csb.processed_byte_count,
3958c2ecf20Sopenharmony_ci			     &(nx_ctx->stats->aes_bytes));
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		processed += to_process;
3988c2ecf20Sopenharmony_ci	} while (processed < nbytes);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
4018c2ecf20Sopenharmony_ci		    authsize) ? -EBADMSG : 0;
4028c2ecf20Sopenharmony_ciout:
4038c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
4048c2ecf20Sopenharmony_ci	return rc;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic int ccm_nx_encrypt(struct aead_request   *req,
4088c2ecf20Sopenharmony_ci			  u8                    *iv,
4098c2ecf20Sopenharmony_ci			  unsigned int assoclen)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
4128c2ecf20Sopenharmony_ci	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
4138c2ecf20Sopenharmony_ci	unsigned int nbytes = req->cryptlen;
4148c2ecf20Sopenharmony_ci	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
4158c2ecf20Sopenharmony_ci	unsigned long irq_flags;
4168c2ecf20Sopenharmony_ci	unsigned int processed = 0, to_process;
4178c2ecf20Sopenharmony_ci	int rc = -1;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen,
4228c2ecf20Sopenharmony_ci			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
4238c2ecf20Sopenharmony_ci	if (rc)
4248c2ecf20Sopenharmony_ci		goto out;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	do {
4278c2ecf20Sopenharmony_ci		/* to process: the AES_BLOCK_SIZE data chunk to process in this
4288c2ecf20Sopenharmony_ci		 * update. This value is bound by sg list limits.
4298c2ecf20Sopenharmony_ci		 */
4308c2ecf20Sopenharmony_ci		to_process = nbytes - processed;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		if ((to_process + processed) < nbytes)
4338c2ecf20Sopenharmony_ci			NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
4348c2ecf20Sopenharmony_ci		else
4358c2ecf20Sopenharmony_ci			NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci		NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci		rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src,
4408c2ecf20Sopenharmony_ci				       &to_process, processed + req->assoclen,
4418c2ecf20Sopenharmony_ci				       csbcpb->cpb.aes_ccm.iv_or_ctr);
4428c2ecf20Sopenharmony_ci		if (rc)
4438c2ecf20Sopenharmony_ci			goto out;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
4468c2ecf20Sopenharmony_ci				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
4478c2ecf20Sopenharmony_ci		if (rc)
4488c2ecf20Sopenharmony_ci			goto out;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		/* for partial completion, copy following for next
4518c2ecf20Sopenharmony_ci		 * entry into loop...
4528c2ecf20Sopenharmony_ci		 */
4538c2ecf20Sopenharmony_ci		memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
4548c2ecf20Sopenharmony_ci		memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
4558c2ecf20Sopenharmony_ci			csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
4568c2ecf20Sopenharmony_ci		memcpy(csbcpb->cpb.aes_ccm.in_s0,
4578c2ecf20Sopenharmony_ci			csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		/* update stats */
4628c2ecf20Sopenharmony_ci		atomic_inc(&(nx_ctx->stats->aes_ops));
4638c2ecf20Sopenharmony_ci		atomic64_add(csbcpb->csb.processed_byte_count,
4648c2ecf20Sopenharmony_ci			     &(nx_ctx->stats->aes_bytes));
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		processed += to_process;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	} while (processed < nbytes);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	/* copy out the auth tag */
4718c2ecf20Sopenharmony_ci	scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac,
4728c2ecf20Sopenharmony_ci				 req->dst, nbytes + req->assoclen, authsize,
4738c2ecf20Sopenharmony_ci				 SCATTERWALK_TO_SG);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ciout:
4768c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
4778c2ecf20Sopenharmony_ci	return rc;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic int ccm4309_aes_nx_encrypt(struct aead_request *req)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
4838c2ecf20Sopenharmony_ci	struct nx_gcm_rctx *rctx = aead_request_ctx(req);
4848c2ecf20Sopenharmony_ci	u8 *iv = rctx->iv;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	iv[0] = 3;
4878c2ecf20Sopenharmony_ci	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
4888c2ecf20Sopenharmony_ci	memcpy(iv + 4, req->iv, 8);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	return ccm_nx_encrypt(req, iv, req->assoclen - 8);
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic int ccm_aes_nx_encrypt(struct aead_request *req)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	int rc;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	rc = crypto_ccm_check_iv(req->iv);
4988c2ecf20Sopenharmony_ci	if (rc)
4998c2ecf20Sopenharmony_ci		return rc;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	return ccm_nx_encrypt(req, req->iv, req->assoclen);
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic int ccm4309_aes_nx_decrypt(struct aead_request *req)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
5078c2ecf20Sopenharmony_ci	struct nx_gcm_rctx *rctx = aead_request_ctx(req);
5088c2ecf20Sopenharmony_ci	u8 *iv = rctx->iv;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	iv[0] = 3;
5118c2ecf20Sopenharmony_ci	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
5128c2ecf20Sopenharmony_ci	memcpy(iv + 4, req->iv, 8);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	return ccm_nx_decrypt(req, iv, req->assoclen - 8);
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistatic int ccm_aes_nx_decrypt(struct aead_request *req)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	int rc;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	rc = crypto_ccm_check_iv(req->iv);
5228c2ecf20Sopenharmony_ci	if (rc)
5238c2ecf20Sopenharmony_ci		return rc;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return ccm_nx_decrypt(req, req->iv, req->assoclen);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistruct aead_alg nx_ccm_aes_alg = {
5298c2ecf20Sopenharmony_ci	.base = {
5308c2ecf20Sopenharmony_ci		.cra_name        = "ccm(aes)",
5318c2ecf20Sopenharmony_ci		.cra_driver_name = "ccm-aes-nx",
5328c2ecf20Sopenharmony_ci		.cra_priority    = 300,
5338c2ecf20Sopenharmony_ci		.cra_flags       = CRYPTO_ALG_NEED_FALLBACK,
5348c2ecf20Sopenharmony_ci		.cra_blocksize   = 1,
5358c2ecf20Sopenharmony_ci		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
5368c2ecf20Sopenharmony_ci		.cra_module      = THIS_MODULE,
5378c2ecf20Sopenharmony_ci	},
5388c2ecf20Sopenharmony_ci	.init        = nx_crypto_ctx_aes_ccm_init,
5398c2ecf20Sopenharmony_ci	.exit        = nx_crypto_ctx_aead_exit,
5408c2ecf20Sopenharmony_ci	.ivsize      = AES_BLOCK_SIZE,
5418c2ecf20Sopenharmony_ci	.maxauthsize = AES_BLOCK_SIZE,
5428c2ecf20Sopenharmony_ci	.setkey      = ccm_aes_nx_set_key,
5438c2ecf20Sopenharmony_ci	.setauthsize = ccm_aes_nx_setauthsize,
5448c2ecf20Sopenharmony_ci	.encrypt     = ccm_aes_nx_encrypt,
5458c2ecf20Sopenharmony_ci	.decrypt     = ccm_aes_nx_decrypt,
5468c2ecf20Sopenharmony_ci};
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistruct aead_alg nx_ccm4309_aes_alg = {
5498c2ecf20Sopenharmony_ci	.base = {
5508c2ecf20Sopenharmony_ci		.cra_name        = "rfc4309(ccm(aes))",
5518c2ecf20Sopenharmony_ci		.cra_driver_name = "rfc4309-ccm-aes-nx",
5528c2ecf20Sopenharmony_ci		.cra_priority    = 300,
5538c2ecf20Sopenharmony_ci		.cra_flags       = CRYPTO_ALG_NEED_FALLBACK,
5548c2ecf20Sopenharmony_ci		.cra_blocksize   = 1,
5558c2ecf20Sopenharmony_ci		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
5568c2ecf20Sopenharmony_ci		.cra_module      = THIS_MODULE,
5578c2ecf20Sopenharmony_ci	},
5588c2ecf20Sopenharmony_ci	.init        = nx_crypto_ctx_aes_ccm_init,
5598c2ecf20Sopenharmony_ci	.exit        = nx_crypto_ctx_aead_exit,
5608c2ecf20Sopenharmony_ci	.ivsize      = 8,
5618c2ecf20Sopenharmony_ci	.maxauthsize = AES_BLOCK_SIZE,
5628c2ecf20Sopenharmony_ci	.setkey      = ccm4309_aes_nx_set_key,
5638c2ecf20Sopenharmony_ci	.setauthsize = ccm4309_aes_nx_setauthsize,
5648c2ecf20Sopenharmony_ci	.encrypt     = ccm4309_aes_nx_encrypt,
5658c2ecf20Sopenharmony_ci	.decrypt     = ccm4309_aes_nx_decrypt,
5668c2ecf20Sopenharmony_ci};
567