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