xref: /openbmc/linux/drivers/crypto/nx/nx-aes-ccm.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
164d85cc9SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
210cb823bSAditya Srivastava /*
3a00bd6e6SKent Yoder  * AES CCM routines supporting the Power 7+ Nest Accelerators driver
4a00bd6e6SKent Yoder  *
5a00bd6e6SKent Yoder  * Copyright (C) 2012 International Business Machines Inc.
6a00bd6e6SKent Yoder  *
7a00bd6e6SKent Yoder  * Author: Kent Yoder <yoder1@us.ibm.com>
8a00bd6e6SKent Yoder  */
9a00bd6e6SKent Yoder 
10a00bd6e6SKent Yoder #include <crypto/internal/aead.h>
11a00bd6e6SKent Yoder #include <crypto/aes.h>
12a00bd6e6SKent Yoder #include <crypto/algapi.h>
13a00bd6e6SKent Yoder #include <crypto/scatterwalk.h>
14a00bd6e6SKent Yoder #include <linux/module.h>
15a00bd6e6SKent Yoder #include <linux/types.h>
16a00bd6e6SKent Yoder #include <linux/crypto.h>
17a00bd6e6SKent Yoder #include <asm/vio.h>
18a00bd6e6SKent Yoder 
19a00bd6e6SKent Yoder #include "nx_csbcpb.h"
20a00bd6e6SKent Yoder #include "nx.h"
21a00bd6e6SKent Yoder 
22a00bd6e6SKent Yoder 
ccm_aes_nx_set_key(struct crypto_aead * tfm,const u8 * in_key,unsigned int key_len)23a00bd6e6SKent Yoder static int ccm_aes_nx_set_key(struct crypto_aead *tfm,
24a00bd6e6SKent Yoder 			      const u8           *in_key,
25a00bd6e6SKent Yoder 			      unsigned int        key_len)
26a00bd6e6SKent Yoder {
27a00bd6e6SKent Yoder 	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
28a00bd6e6SKent Yoder 	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
29a00bd6e6SKent Yoder 	struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
30a00bd6e6SKent Yoder 
31a00bd6e6SKent Yoder 	nx_ctx_init(nx_ctx, HCOP_FC_AES);
32a00bd6e6SKent Yoder 
33a00bd6e6SKent Yoder 	switch (key_len) {
34a00bd6e6SKent Yoder 	case AES_KEYSIZE_128:
35a00bd6e6SKent Yoder 		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
36a00bd6e6SKent Yoder 		NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
37a00bd6e6SKent Yoder 		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
38a00bd6e6SKent Yoder 		break;
39a00bd6e6SKent Yoder 	default:
40a00bd6e6SKent Yoder 		return -EINVAL;
41a00bd6e6SKent Yoder 	}
42a00bd6e6SKent Yoder 
43a00bd6e6SKent Yoder 	csbcpb->cpb.hdr.mode = NX_MODE_AES_CCM;
44a00bd6e6SKent Yoder 	memcpy(csbcpb->cpb.aes_ccm.key, in_key, key_len);
45a00bd6e6SKent Yoder 
46a00bd6e6SKent Yoder 	csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_CCA;
47a00bd6e6SKent Yoder 	memcpy(csbcpb_aead->cpb.aes_cca.key, in_key, key_len);
48a00bd6e6SKent Yoder 
49a00bd6e6SKent Yoder 	return 0;
50a00bd6e6SKent Yoder 
51a00bd6e6SKent Yoder }
52a00bd6e6SKent Yoder 
ccm4309_aes_nx_set_key(struct crypto_aead * tfm,const u8 * in_key,unsigned int key_len)53a00bd6e6SKent Yoder static int ccm4309_aes_nx_set_key(struct crypto_aead *tfm,
54a00bd6e6SKent Yoder 				  const u8           *in_key,
55a00bd6e6SKent Yoder 				  unsigned int        key_len)
56a00bd6e6SKent Yoder {
57a00bd6e6SKent Yoder 	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
58a00bd6e6SKent Yoder 
59a00bd6e6SKent Yoder 	if (key_len < 3)
60a00bd6e6SKent Yoder 		return -EINVAL;
61a00bd6e6SKent Yoder 
62a00bd6e6SKent Yoder 	key_len -= 3;
63a00bd6e6SKent Yoder 
64a00bd6e6SKent Yoder 	memcpy(nx_ctx->priv.ccm.nonce, in_key + key_len, 3);
65a00bd6e6SKent Yoder 
66a00bd6e6SKent Yoder 	return ccm_aes_nx_set_key(tfm, in_key, key_len);
67a00bd6e6SKent Yoder }
68a00bd6e6SKent Yoder 
ccm_aes_nx_setauthsize(struct crypto_aead * tfm,unsigned int authsize)69a00bd6e6SKent Yoder static int ccm_aes_nx_setauthsize(struct crypto_aead *tfm,
70a00bd6e6SKent Yoder 				  unsigned int authsize)
71a00bd6e6SKent Yoder {
72a00bd6e6SKent Yoder 	switch (authsize) {
73a00bd6e6SKent Yoder 	case 4:
74a00bd6e6SKent Yoder 	case 6:
75a00bd6e6SKent Yoder 	case 8:
76a00bd6e6SKent Yoder 	case 10:
77a00bd6e6SKent Yoder 	case 12:
78a00bd6e6SKent Yoder 	case 14:
79a00bd6e6SKent Yoder 	case 16:
80a00bd6e6SKent Yoder 		break;
81a00bd6e6SKent Yoder 	default:
82a00bd6e6SKent Yoder 		return -EINVAL;
83a00bd6e6SKent Yoder 	}
84a00bd6e6SKent Yoder 
85a00bd6e6SKent Yoder 	return 0;
86a00bd6e6SKent Yoder }
87a00bd6e6SKent Yoder 
ccm4309_aes_nx_setauthsize(struct crypto_aead * tfm,unsigned int authsize)88a00bd6e6SKent Yoder static int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm,
89a00bd6e6SKent Yoder 				      unsigned int authsize)
90a00bd6e6SKent Yoder {
91a00bd6e6SKent Yoder 	switch (authsize) {
92a00bd6e6SKent Yoder 	case 8:
93a00bd6e6SKent Yoder 	case 12:
94a00bd6e6SKent Yoder 	case 16:
95a00bd6e6SKent Yoder 		break;
96a00bd6e6SKent Yoder 	default:
97a00bd6e6SKent Yoder 		return -EINVAL;
98a00bd6e6SKent Yoder 	}
99a00bd6e6SKent Yoder 
100a00bd6e6SKent Yoder 	return 0;
101a00bd6e6SKent Yoder }
102a00bd6e6SKent Yoder 
103a00bd6e6SKent Yoder /* taken from crypto/ccm.c */
set_msg_len(u8 * block,unsigned int msglen,int csize)104a00bd6e6SKent Yoder static int set_msg_len(u8 *block, unsigned int msglen, int csize)
105a00bd6e6SKent Yoder {
106a00bd6e6SKent Yoder 	__be32 data;
107a00bd6e6SKent Yoder 
108a00bd6e6SKent Yoder 	memset(block, 0, csize);
109a00bd6e6SKent Yoder 	block += csize;
110a00bd6e6SKent Yoder 
111a00bd6e6SKent Yoder 	if (csize >= 4)
112a00bd6e6SKent Yoder 		csize = 4;
113a00bd6e6SKent Yoder 	else if (msglen > (unsigned int)(1 << (8 * csize)))
114a00bd6e6SKent Yoder 		return -EOVERFLOW;
115a00bd6e6SKent Yoder 
116a00bd6e6SKent Yoder 	data = cpu_to_be32(msglen);
117a00bd6e6SKent Yoder 	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
118a00bd6e6SKent Yoder 
119a00bd6e6SKent Yoder 	return 0;
120a00bd6e6SKent Yoder }
121a00bd6e6SKent Yoder 
122a00bd6e6SKent Yoder /* taken from crypto/ccm.c */
crypto_ccm_check_iv(const u8 * iv)123a00bd6e6SKent Yoder static inline int crypto_ccm_check_iv(const u8 *iv)
124a00bd6e6SKent Yoder {
125a00bd6e6SKent Yoder 	/* 2 <= L <= 8, so 1 <= L' <= 7. */
126a00bd6e6SKent Yoder 	if (1 > iv[0] || iv[0] > 7)
127a00bd6e6SKent Yoder 		return -EINVAL;
128a00bd6e6SKent Yoder 
129a00bd6e6SKent Yoder 	return 0;
130a00bd6e6SKent Yoder }
131a00bd6e6SKent Yoder 
132a00bd6e6SKent Yoder /* based on code from crypto/ccm.c */
generate_b0(u8 * iv,unsigned int assoclen,unsigned int authsize,unsigned int cryptlen,u8 * b0)133a00bd6e6SKent Yoder static int generate_b0(u8 *iv, unsigned int assoclen, unsigned int authsize,
134a00bd6e6SKent Yoder 		       unsigned int cryptlen, u8 *b0)
135a00bd6e6SKent Yoder {
136a00bd6e6SKent Yoder 	unsigned int l, lp, m = authsize;
137a00bd6e6SKent Yoder 
138a00bd6e6SKent Yoder 	memcpy(b0, iv, 16);
139a00bd6e6SKent Yoder 
140a00bd6e6SKent Yoder 	lp = b0[0];
141a00bd6e6SKent Yoder 	l = lp + 1;
142a00bd6e6SKent Yoder 
143a00bd6e6SKent Yoder 	/* set m, bits 3-5 */
144a00bd6e6SKent Yoder 	*b0 |= (8 * ((m - 2) / 2));
145a00bd6e6SKent Yoder 
146a00bd6e6SKent Yoder 	/* set adata, bit 6, if associated data is used */
147a00bd6e6SKent Yoder 	if (assoclen)
148a00bd6e6SKent Yoder 		*b0 |= 64;
149a00bd6e6SKent Yoder 
150*96d3e6f0Sye xingchen 	return set_msg_len(b0 + 16 - l, cryptlen, l);
151a00bd6e6SKent Yoder }
152a00bd6e6SKent Yoder 
generate_pat(u8 * iv,struct aead_request * req,struct nx_crypto_ctx * nx_ctx,unsigned int authsize,unsigned int nbytes,unsigned int assoclen,u8 * out)153a00bd6e6SKent Yoder static int generate_pat(u8                   *iv,
154a00bd6e6SKent Yoder 			struct aead_request  *req,
155a00bd6e6SKent Yoder 			struct nx_crypto_ctx *nx_ctx,
156a00bd6e6SKent Yoder 			unsigned int          authsize,
157a00bd6e6SKent Yoder 			unsigned int          nbytes,
158cc815653SHerbert Xu 			unsigned int	      assoclen,
159a00bd6e6SKent Yoder 			u8                   *out)
160a00bd6e6SKent Yoder {
161a00bd6e6SKent Yoder 	struct nx_sg *nx_insg = nx_ctx->in_sg;
162a00bd6e6SKent Yoder 	struct nx_sg *nx_outsg = nx_ctx->out_sg;
163a00bd6e6SKent Yoder 	unsigned int iauth_len = 0;
164a00bd6e6SKent Yoder 	u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL;
165a00bd6e6SKent Yoder 	int rc;
1669247f0b0SLeonidas S. Barbosa 	unsigned int max_sg_len;
167a00bd6e6SKent Yoder 
168a00bd6e6SKent Yoder 	/* zero the ctr value */
169a00bd6e6SKent Yoder 	memset(iv + 15 - iv[0], 0, iv[0] + 1);
170a00bd6e6SKent Yoder 
1712b188b3bSFionnuala Gunter 	/* page 78 of nx_wb.pdf has,
1722b188b3bSFionnuala Gunter 	 * Note: RFC3610 allows the AAD data to be up to 2^64 -1 bytes
1732b188b3bSFionnuala Gunter 	 * in length. If a full message is used, the AES CCA implementation
1742b188b3bSFionnuala Gunter 	 * restricts the maximum AAD length to 2^32 -1 bytes.
1752b188b3bSFionnuala Gunter 	 * If partial messages are used, the implementation supports
1762b188b3bSFionnuala Gunter 	 * 2^64 -1 bytes maximum AAD length.
1772b188b3bSFionnuala Gunter 	 *
1782b188b3bSFionnuala Gunter 	 * However, in the cryptoapi's aead_request structure,
1792b188b3bSFionnuala Gunter 	 * assoclen is an unsigned int, thus it cannot hold a length
1802b188b3bSFionnuala Gunter 	 * value greater than 2^32 - 1.
1812b188b3bSFionnuala Gunter 	 * Thus the AAD is further constrained by this and is never
1822b188b3bSFionnuala Gunter 	 * greater than 2^32.
1832b188b3bSFionnuala Gunter 	 */
1842b188b3bSFionnuala Gunter 
185cc815653SHerbert Xu 	if (!assoclen) {
186a00bd6e6SKent Yoder 		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
187cc815653SHerbert Xu 	} else if (assoclen <= 14) {
188a00bd6e6SKent Yoder 		/* if associated data is 14 bytes or less, we do 1 GCM
189a00bd6e6SKent Yoder 		 * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1,
190a00bd6e6SKent Yoder 		 * which is fed in through the source buffers here */
191a00bd6e6SKent Yoder 		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
192a00bd6e6SKent Yoder 		b1 = nx_ctx->priv.ccm.iauth_tag;
193cc815653SHerbert Xu 		iauth_len = assoclen;
194cc815653SHerbert Xu 	} else if (assoclen <= 65280) {
1952b188b3bSFionnuala Gunter 		/* if associated data is less than (2^16 - 2^8), we construct
1962b188b3bSFionnuala Gunter 		 * B1 differently and feed in the associated data to a CCA
1972b188b3bSFionnuala Gunter 		 * operation */
1982b188b3bSFionnuala Gunter 		b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
1992b188b3bSFionnuala Gunter 		b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
2002b188b3bSFionnuala Gunter 		iauth_len = 14;
2012b188b3bSFionnuala Gunter 	} else {
2022b188b3bSFionnuala Gunter 		b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
2032b188b3bSFionnuala Gunter 		b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
2042b188b3bSFionnuala Gunter 		iauth_len = 10;
2052b188b3bSFionnuala Gunter 	}
206a00bd6e6SKent Yoder 
2072b188b3bSFionnuala Gunter 	/* generate B0 */
208cc815653SHerbert Xu 	rc = generate_b0(iv, assoclen, authsize, nbytes, b0);
2092b188b3bSFionnuala Gunter 	if (rc)
2102b188b3bSFionnuala Gunter 		return rc;
2112b188b3bSFionnuala Gunter 
2122b188b3bSFionnuala Gunter 	/* generate B1:
2132b188b3bSFionnuala Gunter 	 * add control info for associated data
2142b188b3bSFionnuala Gunter 	 * RFC 3610 and NIST Special Publication 800-38C
2152b188b3bSFionnuala Gunter 	 */
2162b188b3bSFionnuala Gunter 	if (b1) {
2172b188b3bSFionnuala Gunter 		memset(b1, 0, 16);
218cc815653SHerbert Xu 		if (assoclen <= 65280) {
219cc815653SHerbert Xu 			*(u16 *)b1 = assoclen;
220cc815653SHerbert Xu 			scatterwalk_map_and_copy(b1 + 2, req->src, 0,
2212b188b3bSFionnuala Gunter 					 iauth_len, SCATTERWALK_FROM_SG);
2222b188b3bSFionnuala Gunter 		} else {
2232b188b3bSFionnuala Gunter 			*(u16 *)b1 = (u16)(0xfffe);
224cc815653SHerbert Xu 			*(u32 *)&b1[2] = assoclen;
225cc815653SHerbert Xu 			scatterwalk_map_and_copy(b1 + 6, req->src, 0,
2262b188b3bSFionnuala Gunter 					 iauth_len, SCATTERWALK_FROM_SG);
2272b188b3bSFionnuala Gunter 		}
2282b188b3bSFionnuala Gunter 	}
2292b188b3bSFionnuala Gunter 
2302b188b3bSFionnuala Gunter 	/* now copy any remaining AAD to scatterlist and call nx... */
231cc815653SHerbert Xu 	if (!assoclen) {
2322b188b3bSFionnuala Gunter 		return rc;
233cc815653SHerbert Xu 	} else if (assoclen <= 14) {
2349247f0b0SLeonidas S. Barbosa 		unsigned int len = 16;
2359247f0b0SLeonidas S. Barbosa 
2369247f0b0SLeonidas S. Barbosa 		nx_insg = nx_build_sg_list(nx_insg, b1, &len, nx_ctx->ap->sglen);
2379247f0b0SLeonidas S. Barbosa 
2389247f0b0SLeonidas S. Barbosa 		if (len != 16)
2399247f0b0SLeonidas S. Barbosa 			return -EINVAL;
2409247f0b0SLeonidas S. Barbosa 
2419247f0b0SLeonidas S. Barbosa 		nx_outsg = nx_build_sg_list(nx_outsg, tmp, &len,
242a00bd6e6SKent Yoder 					    nx_ctx->ap->sglen);
243a00bd6e6SKent Yoder 
2449247f0b0SLeonidas S. Barbosa 		if (len != 16)
2459247f0b0SLeonidas S. Barbosa 			return -EINVAL;
2469247f0b0SLeonidas S. Barbosa 
247a00bd6e6SKent Yoder 		/* inlen should be negative, indicating to phyp that its a
248a00bd6e6SKent Yoder 		 * pointer to an sg list */
249a00bd6e6SKent Yoder 		nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) *
250a00bd6e6SKent Yoder 					sizeof(struct nx_sg);
251a00bd6e6SKent Yoder 		nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) *
252a00bd6e6SKent Yoder 					sizeof(struct nx_sg);
253a00bd6e6SKent Yoder 
254a00bd6e6SKent Yoder 		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT;
255a00bd6e6SKent Yoder 		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE;
256a00bd6e6SKent Yoder 
257a00bd6e6SKent Yoder 		result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac;
258a00bd6e6SKent Yoder 
2592b188b3bSFionnuala Gunter 		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
260a00bd6e6SKent Yoder 				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
261a00bd6e6SKent Yoder 		if (rc)
2622b188b3bSFionnuala Gunter 			return rc;
263a00bd6e6SKent Yoder 
264a00bd6e6SKent Yoder 		atomic_inc(&(nx_ctx->stats->aes_ops));
265cc815653SHerbert Xu 		atomic64_add(assoclen, &nx_ctx->stats->aes_bytes);
266a00bd6e6SKent Yoder 
2672b188b3bSFionnuala Gunter 	} else {
2682b188b3bSFionnuala Gunter 		unsigned int processed = 0, to_process;
2692b188b3bSFionnuala Gunter 
2702b188b3bSFionnuala Gunter 		processed += iauth_len;
2712b188b3bSFionnuala Gunter 
2729247f0b0SLeonidas S. Barbosa 		/* page_limit: number of sg entries that fit on one page */
2739247f0b0SLeonidas S. Barbosa 		max_sg_len = min_t(u64, nx_ctx->ap->sglen,
2749247f0b0SLeonidas S. Barbosa 				nx_driver.of.max_sg_len/sizeof(struct nx_sg));
2759247f0b0SLeonidas S. Barbosa 		max_sg_len = min_t(u64, max_sg_len,
2769247f0b0SLeonidas S. Barbosa 				nx_ctx->ap->databytelen/NX_PAGE_SIZE);
2779247f0b0SLeonidas S. Barbosa 
2782b188b3bSFionnuala Gunter 		do {
279cc815653SHerbert Xu 			to_process = min_t(u32, assoclen - processed,
2802b188b3bSFionnuala Gunter 					   nx_ctx->ap->databytelen);
2819247f0b0SLeonidas S. Barbosa 
2829247f0b0SLeonidas S. Barbosa 			nx_insg = nx_walk_and_build(nx_ctx->in_sg,
2839247f0b0SLeonidas S. Barbosa 						    nx_ctx->ap->sglen,
284cc815653SHerbert Xu 						    req->src, processed,
2859247f0b0SLeonidas S. Barbosa 						    &to_process);
2862b188b3bSFionnuala Gunter 
287cc815653SHerbert Xu 			if ((to_process + processed) < assoclen) {
2882b188b3bSFionnuala Gunter 				NX_CPB_FDM(nx_ctx->csbcpb_aead) |=
2892b188b3bSFionnuala Gunter 					NX_FDM_INTERMEDIATE;
2902b188b3bSFionnuala Gunter 			} else {
2912b188b3bSFionnuala Gunter 				NX_CPB_FDM(nx_ctx->csbcpb_aead) &=
2922b188b3bSFionnuala Gunter 					~NX_FDM_INTERMEDIATE;
293a00bd6e6SKent Yoder 			}
2942b188b3bSFionnuala Gunter 
2952b188b3bSFionnuala Gunter 
2962b188b3bSFionnuala Gunter 			nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
2972b188b3bSFionnuala Gunter 						sizeof(struct nx_sg);
2982b188b3bSFionnuala Gunter 
2992b188b3bSFionnuala Gunter 			result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
3002b188b3bSFionnuala Gunter 
3012b188b3bSFionnuala Gunter 			rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
3022b188b3bSFionnuala Gunter 				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
3032b188b3bSFionnuala Gunter 			if (rc)
3042b188b3bSFionnuala Gunter 				return rc;
3052b188b3bSFionnuala Gunter 
3062b188b3bSFionnuala Gunter 			memcpy(nx_ctx->csbcpb_aead->cpb.aes_cca.b0,
3072b188b3bSFionnuala Gunter 				nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0,
3082b188b3bSFionnuala Gunter 				AES_BLOCK_SIZE);
3092b188b3bSFionnuala Gunter 
3102b188b3bSFionnuala Gunter 			NX_CPB_FDM(nx_ctx->csbcpb_aead) |= NX_FDM_CONTINUATION;
3112b188b3bSFionnuala Gunter 
3122b188b3bSFionnuala Gunter 			atomic_inc(&(nx_ctx->stats->aes_ops));
313cc815653SHerbert Xu 			atomic64_add(assoclen, &nx_ctx->stats->aes_bytes);
3142b188b3bSFionnuala Gunter 
3152b188b3bSFionnuala Gunter 			processed += to_process;
316cc815653SHerbert Xu 		} while (processed < assoclen);
3172b188b3bSFionnuala Gunter 
3182b188b3bSFionnuala Gunter 		result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
3192b188b3bSFionnuala Gunter 	}
3202b188b3bSFionnuala Gunter 
3212b188b3bSFionnuala Gunter 	memcpy(out, result, AES_BLOCK_SIZE);
3222b188b3bSFionnuala Gunter 
323a00bd6e6SKent Yoder 	return rc;
324a00bd6e6SKent Yoder }
325a00bd6e6SKent Yoder 
ccm_nx_decrypt(struct aead_request * req,u8 * iv,unsigned int assoclen)326a00bd6e6SKent Yoder static int ccm_nx_decrypt(struct aead_request   *req,
3277740bd51SEric Biggers 			  u8                    *iv,
328cc815653SHerbert Xu 			  unsigned int assoclen)
329a00bd6e6SKent Yoder {
330a00bd6e6SKent Yoder 	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
331a00bd6e6SKent Yoder 	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
332a00bd6e6SKent Yoder 	unsigned int nbytes = req->cryptlen;
333a00bd6e6SKent Yoder 	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
334a00bd6e6SKent Yoder 	struct nx_ccm_priv *priv = &nx_ctx->priv.ccm;
335c849163bSMarcelo Cerri 	unsigned long irq_flags;
3362b188b3bSFionnuala Gunter 	unsigned int processed = 0, to_process;
337a00bd6e6SKent Yoder 	int rc = -1;
338a00bd6e6SKent Yoder 
339c849163bSMarcelo Cerri 	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
340c849163bSMarcelo Cerri 
341a00bd6e6SKent Yoder 	nbytes -= authsize;
342a00bd6e6SKent Yoder 
343a00bd6e6SKent Yoder 	/* copy out the auth tag to compare with later */
344a00bd6e6SKent Yoder 	scatterwalk_map_and_copy(priv->oauth_tag,
345cc815653SHerbert Xu 				 req->src, nbytes + req->assoclen, authsize,
346a00bd6e6SKent Yoder 				 SCATTERWALK_FROM_SG);
347a00bd6e6SKent Yoder 
3487740bd51SEric Biggers 	rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen,
349a00bd6e6SKent Yoder 			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
350a00bd6e6SKent Yoder 	if (rc)
351a00bd6e6SKent Yoder 		goto out;
352a00bd6e6SKent Yoder 
3532b188b3bSFionnuala Gunter 	do {
3542b188b3bSFionnuala Gunter 
3552b188b3bSFionnuala Gunter 		/* to_process: the AES_BLOCK_SIZE data chunk to process in this
3562b188b3bSFionnuala Gunter 		 * update. This value is bound by sg list limits.
3572b188b3bSFionnuala Gunter 		 */
3589247f0b0SLeonidas S. Barbosa 		to_process = nbytes - processed;
3592b188b3bSFionnuala Gunter 
3602b188b3bSFionnuala Gunter 		if ((to_process + processed) < nbytes)
3612b188b3bSFionnuala Gunter 			NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
3622b188b3bSFionnuala Gunter 		else
3632b188b3bSFionnuala Gunter 			NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
3642b188b3bSFionnuala Gunter 
3652b188b3bSFionnuala Gunter 		NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
3662b188b3bSFionnuala Gunter 
3677740bd51SEric Biggers 		rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src,
368cc815653SHerbert Xu 				       &to_process, processed + req->assoclen,
369a00bd6e6SKent Yoder 				       csbcpb->cpb.aes_ccm.iv_or_ctr);
370a00bd6e6SKent Yoder 		if (rc)
371a00bd6e6SKent Yoder 			goto out;
372a00bd6e6SKent Yoder 
373a00bd6e6SKent Yoder 		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
374a00bd6e6SKent Yoder 			   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
375a00bd6e6SKent Yoder 		if (rc)
376a00bd6e6SKent Yoder 			goto out;
377a00bd6e6SKent Yoder 
3782b188b3bSFionnuala Gunter 		/* for partial completion, copy following for next
3792b188b3bSFionnuala Gunter 		 * entry into loop...
3802b188b3bSFionnuala Gunter 		 */
3817740bd51SEric Biggers 		memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
3822b188b3bSFionnuala Gunter 		memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
3832b188b3bSFionnuala Gunter 			csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
3842b188b3bSFionnuala Gunter 		memcpy(csbcpb->cpb.aes_ccm.in_s0,
3852b188b3bSFionnuala Gunter 			csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
3862b188b3bSFionnuala Gunter 
3872b188b3bSFionnuala Gunter 		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
3882b188b3bSFionnuala Gunter 
3892b188b3bSFionnuala Gunter 		/* update stats */
390a00bd6e6SKent Yoder 		atomic_inc(&(nx_ctx->stats->aes_ops));
391b20d9a73SHerbert Xu 		atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
392a00bd6e6SKent Yoder 			     &(nx_ctx->stats->aes_bytes));
393a00bd6e6SKent Yoder 
3942b188b3bSFionnuala Gunter 		processed += to_process;
3952b188b3bSFionnuala Gunter 	} while (processed < nbytes);
3962b188b3bSFionnuala Gunter 
397cb8affb5SDavid Gstir 	rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
398a00bd6e6SKent Yoder 		    authsize) ? -EBADMSG : 0;
399a00bd6e6SKent Yoder out:
400c849163bSMarcelo Cerri 	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
401a00bd6e6SKent Yoder 	return rc;
402a00bd6e6SKent Yoder }
403a00bd6e6SKent Yoder 
ccm_nx_encrypt(struct aead_request * req,u8 * iv,unsigned int assoclen)404a00bd6e6SKent Yoder static int ccm_nx_encrypt(struct aead_request   *req,
4057740bd51SEric Biggers 			  u8                    *iv,
406cc815653SHerbert Xu 			  unsigned int assoclen)
407a00bd6e6SKent Yoder {
408a00bd6e6SKent Yoder 	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
409a00bd6e6SKent Yoder 	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
410a00bd6e6SKent Yoder 	unsigned int nbytes = req->cryptlen;
411a00bd6e6SKent Yoder 	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
412c849163bSMarcelo Cerri 	unsigned long irq_flags;
4132b188b3bSFionnuala Gunter 	unsigned int processed = 0, to_process;
414a00bd6e6SKent Yoder 	int rc = -1;
415a00bd6e6SKent Yoder 
416c849163bSMarcelo Cerri 	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
417c849163bSMarcelo Cerri 
4187740bd51SEric Biggers 	rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen,
419a00bd6e6SKent Yoder 			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
420a00bd6e6SKent Yoder 	if (rc)
421a00bd6e6SKent Yoder 		goto out;
422a00bd6e6SKent Yoder 
4232b188b3bSFionnuala Gunter 	do {
4242b188b3bSFionnuala Gunter 		/* to process: the AES_BLOCK_SIZE data chunk to process in this
4252b188b3bSFionnuala Gunter 		 * update. This value is bound by sg list limits.
4262b188b3bSFionnuala Gunter 		 */
4279247f0b0SLeonidas S. Barbosa 		to_process = nbytes - processed;
4282b188b3bSFionnuala Gunter 
4292b188b3bSFionnuala Gunter 		if ((to_process + processed) < nbytes)
4302b188b3bSFionnuala Gunter 			NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
4312b188b3bSFionnuala Gunter 		else
4322b188b3bSFionnuala Gunter 			NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
4332b188b3bSFionnuala Gunter 
4342b188b3bSFionnuala Gunter 		NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
4352b188b3bSFionnuala Gunter 
4367740bd51SEric Biggers 		rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src,
437cc815653SHerbert Xu 				       &to_process, processed + req->assoclen,
438a00bd6e6SKent Yoder 				       csbcpb->cpb.aes_ccm.iv_or_ctr);
439a00bd6e6SKent Yoder 		if (rc)
440a00bd6e6SKent Yoder 			goto out;
441a00bd6e6SKent Yoder 
442a00bd6e6SKent Yoder 		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
443a00bd6e6SKent Yoder 				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
444a00bd6e6SKent Yoder 		if (rc)
445a00bd6e6SKent Yoder 			goto out;
446a00bd6e6SKent Yoder 
4472b188b3bSFionnuala Gunter 		/* for partial completion, copy following for next
4482b188b3bSFionnuala Gunter 		 * entry into loop...
4492b188b3bSFionnuala Gunter 		 */
4507740bd51SEric Biggers 		memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
4512b188b3bSFionnuala Gunter 		memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
4522b188b3bSFionnuala Gunter 			csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
4532b188b3bSFionnuala Gunter 		memcpy(csbcpb->cpb.aes_ccm.in_s0,
4542b188b3bSFionnuala Gunter 			csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
4552b188b3bSFionnuala Gunter 
4562b188b3bSFionnuala Gunter 		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
4572b188b3bSFionnuala Gunter 
4582b188b3bSFionnuala Gunter 		/* update stats */
459a00bd6e6SKent Yoder 		atomic_inc(&(nx_ctx->stats->aes_ops));
460b20d9a73SHerbert Xu 		atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
461a00bd6e6SKent Yoder 			     &(nx_ctx->stats->aes_bytes));
462a00bd6e6SKent Yoder 
4632b188b3bSFionnuala Gunter 		processed += to_process;
4642b188b3bSFionnuala Gunter 
4652b188b3bSFionnuala Gunter 	} while (processed < nbytes);
4662b188b3bSFionnuala Gunter 
467a00bd6e6SKent Yoder 	/* copy out the auth tag */
468a00bd6e6SKent Yoder 	scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac,
469cc815653SHerbert Xu 				 req->dst, nbytes + req->assoclen, authsize,
470a00bd6e6SKent Yoder 				 SCATTERWALK_TO_SG);
4712b188b3bSFionnuala Gunter 
472a00bd6e6SKent Yoder out:
473c849163bSMarcelo Cerri 	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
474a00bd6e6SKent Yoder 	return rc;
475a00bd6e6SKent Yoder }
476a00bd6e6SKent Yoder 
ccm4309_aes_nx_encrypt(struct aead_request * req)477a00bd6e6SKent Yoder static int ccm4309_aes_nx_encrypt(struct aead_request *req)
478a00bd6e6SKent Yoder {
479a00bd6e6SKent Yoder 	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
480030f4e96SHerbert Xu 	struct nx_gcm_rctx *rctx = aead_request_ctx(req);
481030f4e96SHerbert Xu 	u8 *iv = rctx->iv;
482a00bd6e6SKent Yoder 
483a00bd6e6SKent Yoder 	iv[0] = 3;
484a00bd6e6SKent Yoder 	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
485a00bd6e6SKent Yoder 	memcpy(iv + 4, req->iv, 8);
486a00bd6e6SKent Yoder 
4877740bd51SEric Biggers 	return ccm_nx_encrypt(req, iv, req->assoclen - 8);
488a00bd6e6SKent Yoder }
489a00bd6e6SKent Yoder 
ccm_aes_nx_encrypt(struct aead_request * req)490a00bd6e6SKent Yoder static int ccm_aes_nx_encrypt(struct aead_request *req)
491a00bd6e6SKent Yoder {
492a00bd6e6SKent Yoder 	int rc;
493a00bd6e6SKent Yoder 
4947740bd51SEric Biggers 	rc = crypto_ccm_check_iv(req->iv);
495a00bd6e6SKent Yoder 	if (rc)
496a00bd6e6SKent Yoder 		return rc;
497a00bd6e6SKent Yoder 
4987740bd51SEric Biggers 	return ccm_nx_encrypt(req, req->iv, req->assoclen);
499a00bd6e6SKent Yoder }
500a00bd6e6SKent Yoder 
ccm4309_aes_nx_decrypt(struct aead_request * req)501a00bd6e6SKent Yoder static int ccm4309_aes_nx_decrypt(struct aead_request *req)
502a00bd6e6SKent Yoder {
503a00bd6e6SKent Yoder 	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
504030f4e96SHerbert Xu 	struct nx_gcm_rctx *rctx = aead_request_ctx(req);
505030f4e96SHerbert Xu 	u8 *iv = rctx->iv;
506a00bd6e6SKent Yoder 
507a00bd6e6SKent Yoder 	iv[0] = 3;
508a00bd6e6SKent Yoder 	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
509a00bd6e6SKent Yoder 	memcpy(iv + 4, req->iv, 8);
510a00bd6e6SKent Yoder 
5117740bd51SEric Biggers 	return ccm_nx_decrypt(req, iv, req->assoclen - 8);
512a00bd6e6SKent Yoder }
513a00bd6e6SKent Yoder 
ccm_aes_nx_decrypt(struct aead_request * req)514a00bd6e6SKent Yoder static int ccm_aes_nx_decrypt(struct aead_request *req)
515a00bd6e6SKent Yoder {
516a00bd6e6SKent Yoder 	int rc;
517a00bd6e6SKent Yoder 
5187740bd51SEric Biggers 	rc = crypto_ccm_check_iv(req->iv);
519a00bd6e6SKent Yoder 	if (rc)
520a00bd6e6SKent Yoder 		return rc;
521a00bd6e6SKent Yoder 
5227740bd51SEric Biggers 	return ccm_nx_decrypt(req, req->iv, req->assoclen);
523a00bd6e6SKent Yoder }
524a00bd6e6SKent Yoder 
525cc815653SHerbert Xu struct aead_alg nx_ccm_aes_alg = {
526cc815653SHerbert Xu 	.base = {
527a00bd6e6SKent Yoder 		.cra_name        = "ccm(aes)",
528a00bd6e6SKent Yoder 		.cra_driver_name = "ccm-aes-nx",
529a00bd6e6SKent Yoder 		.cra_priority    = 300,
5305e4b8c1fSHerbert Xu 		.cra_flags       = CRYPTO_ALG_NEED_FALLBACK,
531a00bd6e6SKent Yoder 		.cra_blocksize   = 1,
532a00bd6e6SKent Yoder 		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
533a00bd6e6SKent Yoder 		.cra_module      = THIS_MODULE,
534cc815653SHerbert Xu 	},
535cc815653SHerbert Xu 	.init        = nx_crypto_ctx_aes_ccm_init,
536cc815653SHerbert Xu 	.exit        = nx_crypto_ctx_aead_exit,
537a00bd6e6SKent Yoder 	.ivsize      = AES_BLOCK_SIZE,
538a00bd6e6SKent Yoder 	.maxauthsize = AES_BLOCK_SIZE,
539a00bd6e6SKent Yoder 	.setkey      = ccm_aes_nx_set_key,
540a00bd6e6SKent Yoder 	.setauthsize = ccm_aes_nx_setauthsize,
541a00bd6e6SKent Yoder 	.encrypt     = ccm_aes_nx_encrypt,
542a00bd6e6SKent Yoder 	.decrypt     = ccm_aes_nx_decrypt,
543a00bd6e6SKent Yoder };
544a00bd6e6SKent Yoder 
545cc815653SHerbert Xu struct aead_alg nx_ccm4309_aes_alg = {
546cc815653SHerbert Xu 	.base = {
547a00bd6e6SKent Yoder 		.cra_name        = "rfc4309(ccm(aes))",
548a00bd6e6SKent Yoder 		.cra_driver_name = "rfc4309-ccm-aes-nx",
549a00bd6e6SKent Yoder 		.cra_priority    = 300,
5505e4b8c1fSHerbert Xu 		.cra_flags       = CRYPTO_ALG_NEED_FALLBACK,
551a00bd6e6SKent Yoder 		.cra_blocksize   = 1,
552a00bd6e6SKent Yoder 		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
553a00bd6e6SKent Yoder 		.cra_module      = THIS_MODULE,
554cc815653SHerbert Xu 	},
555cc815653SHerbert Xu 	.init        = nx_crypto_ctx_aes_ccm_init,
556cc815653SHerbert Xu 	.exit        = nx_crypto_ctx_aead_exit,
557a00bd6e6SKent Yoder 	.ivsize      = 8,
558a00bd6e6SKent Yoder 	.maxauthsize = AES_BLOCK_SIZE,
559a00bd6e6SKent Yoder 	.setkey      = ccm4309_aes_nx_set_key,
560a00bd6e6SKent Yoder 	.setauthsize = ccm4309_aes_nx_setauthsize,
561a00bd6e6SKent Yoder 	.encrypt     = ccm4309_aes_nx_encrypt,
562a00bd6e6SKent Yoder 	.decrypt     = ccm4309_aes_nx_decrypt,
563a00bd6e6SKent Yoder };
564