xref: /dpdk/drivers/crypto/ipsec_mb/pmd_chacha_poly.c (revision 65c2bbf41f2258fea8e1639a86598f48d8251756)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2021 Intel Corporation
3  */
4 
5 #include "pmd_chacha_poly_priv.h"
6 
7 /** Parse crypto xform chain and set private session parameters. */
8 static int
9 chacha20_poly1305_session_configure(IMB_MGR * mb_mgr __rte_unused,
10 		void *priv_sess, const struct rte_crypto_sym_xform *xform)
11 {
12 	struct chacha20_poly1305_session *sess = priv_sess;
13 	const struct rte_crypto_sym_xform *auth_xform;
14 	const struct rte_crypto_sym_xform *cipher_xform;
15 	const struct rte_crypto_sym_xform *aead_xform;
16 
17 	uint8_t key_length;
18 	const uint8_t *key;
19 	enum ipsec_mb_operation mode;
20 	int ret = 0;
21 
22 	ret = ipsec_mb_parse_xform(xform, &mode, &auth_xform,
23 				&cipher_xform, &aead_xform);
24 	if (ret)
25 		return ret;
26 
27 	sess->op = mode;
28 
29 	switch (sess->op) {
30 	case IPSEC_MB_OP_AEAD_AUTHENTICATED_ENCRYPT:
31 	case IPSEC_MB_OP_AEAD_AUTHENTICATED_DECRYPT:
32 		if (aead_xform->aead.algo !=
33 				RTE_CRYPTO_AEAD_CHACHA20_POLY1305) {
34 			IPSEC_MB_LOG(ERR,
35 			"The only combined operation supported is CHACHA20 POLY1305");
36 			ret = -ENOTSUP;
37 			goto error_exit;
38 		}
39 		/* Set IV parameters */
40 		sess->iv.offset = aead_xform->aead.iv.offset;
41 		sess->iv.length = aead_xform->aead.iv.length;
42 		key_length = aead_xform->aead.key.length;
43 		key = aead_xform->aead.key.data;
44 		sess->aad_length = aead_xform->aead.aad_length;
45 		sess->req_digest_length = aead_xform->aead.digest_length;
46 		break;
47 	default:
48 		IPSEC_MB_LOG(
49 		    ERR, "Wrong xform type, has to be AEAD or authentication");
50 		ret = -ENOTSUP;
51 		goto error_exit;
52 	}
53 
54 	/* IV check */
55 	if (sess->iv.length != CHACHA20_POLY1305_IV_LENGTH &&
56 		sess->iv.length != 0) {
57 		IPSEC_MB_LOG(ERR, "Wrong IV length");
58 		ret = -EINVAL;
59 		goto error_exit;
60 	}
61 
62 	/* Check key length */
63 	if (key_length != CHACHA20_POLY1305_KEY_SIZE) {
64 		IPSEC_MB_LOG(ERR, "Invalid key length");
65 		ret = -EINVAL;
66 		goto error_exit;
67 	} else {
68 		memcpy(sess->key, key, CHACHA20_POLY1305_KEY_SIZE);
69 	}
70 
71 	/* Digest check */
72 	if (sess->req_digest_length !=  CHACHA20_POLY1305_DIGEST_LENGTH) {
73 		IPSEC_MB_LOG(ERR, "Invalid digest length");
74 		ret = -EINVAL;
75 		goto error_exit;
76 	} else {
77 		sess->gen_digest_length = CHACHA20_POLY1305_DIGEST_LENGTH;
78 	}
79 
80 error_exit:
81 	return ret;
82 }
83 
84 /**
85  * Process a crypto operation, calling
86  * the direct chacha poly API from the multi buffer library.
87  *
88  * @param	qp		queue pair
89  * @param	op		symmetric crypto operation
90  * @param	session		chacha poly session
91  *
92  * @return
93  * - Return 0 if success
94  */
95 static int
96 chacha20_poly1305_crypto_op(struct ipsec_mb_qp *qp, struct rte_crypto_op *op,
97 		struct chacha20_poly1305_session *session)
98 {
99 	struct chacha20_poly1305_qp_data *qp_data =
100 					ipsec_mb_get_qp_private_data(qp);
101 	uint8_t *src, *dst;
102 	uint8_t *iv_ptr;
103 	struct rte_crypto_sym_op *sym_op = op->sym;
104 	struct rte_mbuf *m_src = sym_op->m_src;
105 	uint32_t offset, data_offset, data_length;
106 	uint32_t part_len, data_len;
107 	int total_len;
108 	uint8_t *tag;
109 	unsigned int oop = 0;
110 
111 	offset = sym_op->aead.data.offset;
112 	data_offset = offset;
113 	data_length = sym_op->aead.data.length;
114 	RTE_ASSERT(m_src != NULL);
115 
116 	while (offset >= m_src->data_len && data_length != 0) {
117 		offset -= m_src->data_len;
118 		m_src = m_src->next;
119 
120 		RTE_ASSERT(m_src != NULL);
121 	}
122 
123 	src = rte_pktmbuf_mtod_offset(m_src, uint8_t *, offset);
124 
125 	data_len = m_src->data_len - offset;
126 	part_len = (data_len < data_length) ? data_len :
127 			data_length;
128 
129 	/* In-place */
130 	if (sym_op->m_dst == NULL || (sym_op->m_dst == sym_op->m_src))
131 		dst = src;
132 	/* Out-of-place */
133 	else {
134 		oop = 1;
135 		/* Segmented destination buffer is not supported
136 		 * if operation is Out-of-place
137 		 */
138 		RTE_ASSERT(rte_pktmbuf_is_contiguous(sym_op->m_dst));
139 		dst = rte_pktmbuf_mtod_offset(sym_op->m_dst, uint8_t *,
140 					data_offset);
141 	}
142 
143 	iv_ptr = rte_crypto_op_ctod_offset(op, uint8_t *,
144 				session->iv.offset);
145 
146 	IMB_CHACHA20_POLY1305_INIT(qp->mb_mgr, session->key,
147 				&qp_data->chacha20_poly1305_ctx_data,
148 				iv_ptr,	sym_op->aead.aad.data,
149 				(uint64_t)session->aad_length);
150 
151 	if (session->op == IPSEC_MB_OP_AEAD_AUTHENTICATED_ENCRYPT) {
152 		IMB_CHACHA20_POLY1305_ENC_UPDATE(qp->mb_mgr,
153 				session->key,
154 				&qp_data->chacha20_poly1305_ctx_data,
155 				dst, src, (uint64_t)part_len);
156 		total_len = data_length - part_len;
157 
158 		while (total_len) {
159 			m_src = m_src->next;
160 			RTE_ASSERT(m_src != NULL);
161 
162 			src = rte_pktmbuf_mtod(m_src, uint8_t *);
163 			if (oop)
164 				dst += part_len;
165 			else
166 				dst = src;
167 			part_len = (m_src->data_len < total_len) ?
168 					m_src->data_len : total_len;
169 
170 			if (dst == NULL || src == NULL) {
171 				IPSEC_MB_LOG(ERR, "Invalid src or dst input");
172 				return -EINVAL;
173 			}
174 			IMB_CHACHA20_POLY1305_ENC_UPDATE(qp->mb_mgr,
175 					session->key,
176 					&qp_data->chacha20_poly1305_ctx_data,
177 					dst, src, (uint64_t)part_len);
178 			total_len -= part_len;
179 			if (total_len < 0) {
180 				IPSEC_MB_LOG(ERR, "Invalid part len");
181 				return -EINVAL;
182 			}
183 		}
184 
185 		tag = sym_op->aead.digest.data;
186 		IMB_CHACHA20_POLY1305_ENC_FINALIZE(qp->mb_mgr,
187 					&qp_data->chacha20_poly1305_ctx_data,
188 					tag, session->gen_digest_length);
189 
190 	} else {
191 		IMB_CHACHA20_POLY1305_DEC_UPDATE(qp->mb_mgr,
192 					session->key,
193 					&qp_data->chacha20_poly1305_ctx_data,
194 					dst, src, (uint64_t)part_len);
195 
196 		total_len = data_length - part_len;
197 
198 		while (total_len) {
199 			m_src = m_src->next;
200 
201 			RTE_ASSERT(m_src != NULL);
202 
203 			src = rte_pktmbuf_mtod(m_src, uint8_t *);
204 			if (oop)
205 				dst += part_len;
206 			else
207 				dst = src;
208 			part_len = (m_src->data_len < total_len) ?
209 					m_src->data_len : total_len;
210 
211 			if (dst == NULL || src == NULL) {
212 				IPSEC_MB_LOG(ERR, "Invalid src or dst input");
213 				return -EINVAL;
214 			}
215 			IMB_CHACHA20_POLY1305_DEC_UPDATE(qp->mb_mgr,
216 					session->key,
217 					&qp_data->chacha20_poly1305_ctx_data,
218 					dst, src, (uint64_t)part_len);
219 			total_len -= part_len;
220 			if (total_len < 0) {
221 				IPSEC_MB_LOG(ERR, "Invalid part len");
222 				return -EINVAL;
223 			}
224 		}
225 
226 		tag = qp_data->temp_digest;
227 		IMB_CHACHA20_POLY1305_DEC_FINALIZE(qp->mb_mgr,
228 					&qp_data->chacha20_poly1305_ctx_data,
229 					tag, session->gen_digest_length);
230 	}
231 
232 	return 0;
233 }
234 
235 /**
236  * Process a completed chacha poly op
237  *
238  * @param qp		Queue Pair to process
239  * @param op		Crypto operation
240  * @param sess		Crypto session
241  *
242  * @return
243  * - void
244  */
245 static void
246 post_process_chacha20_poly1305_crypto_op(struct ipsec_mb_qp *qp,
247 		struct rte_crypto_op *op,
248 		struct chacha20_poly1305_session *session)
249 {
250 	struct chacha20_poly1305_qp_data *qp_data =
251 					ipsec_mb_get_qp_private_data(qp);
252 
253 	op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
254 	/* Verify digest if required */
255 	if (session->op == IPSEC_MB_OP_AEAD_AUTHENTICATED_DECRYPT ||
256 			session->op == IPSEC_MB_OP_HASH_VERIFY_ONLY) {
257 		uint8_t *digest = op->sym->aead.digest.data;
258 		uint8_t *tag = qp_data->temp_digest;
259 
260 #ifdef RTE_LIBRTE_PMD_CHACHA20_POLY1305_DEBUG
261 		rte_hexdump(stdout, "auth tag (orig):",
262 				digest, session->req_digest_length);
263 		rte_hexdump(stdout, "auth tag (calc):",
264 				tag, session->req_digest_length);
265 #endif
266 		if (memcmp(tag, digest,	session->req_digest_length) != 0)
267 			op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
268 
269 	}
270 
271 }
272 
273 /**
274  * Process a completed Chacha20_poly1305 request
275  *
276  * @param qp		Queue Pair to process
277  * @param op		Crypto operation
278  * @param sess		Crypto session
279  *
280  * @return
281  * - void
282  */
283 static void
284 handle_completed_chacha20_poly1305_crypto_op(struct ipsec_mb_qp *qp,
285 		struct rte_crypto_op *op,
286 		struct chacha20_poly1305_session *sess)
287 {
288 	post_process_chacha20_poly1305_crypto_op(qp, op, sess);
289 
290 	/* Free session if a session-less crypto op */
291 	if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
292 		memset(sess, 0, sizeof(struct chacha20_poly1305_session));
293 		memset(op->sym->session, 0,
294 			rte_cryptodev_sym_get_existing_header_session_size(
295 				op->sym->session));
296 		rte_mempool_put(qp->sess_mp_priv, sess);
297 		rte_mempool_put(qp->sess_mp, op->sym->session);
298 		op->sym->session = NULL;
299 	}
300 }
301 
302 static uint16_t
303 chacha20_poly1305_pmd_dequeue_burst(void *queue_pair,
304 		struct rte_crypto_op **ops, uint16_t nb_ops)
305 {
306 	struct chacha20_poly1305_session *sess;
307 	struct ipsec_mb_qp *qp = queue_pair;
308 
309 	int retval = 0;
310 	unsigned int i = 0, nb_dequeued;
311 
312 	nb_dequeued = rte_ring_dequeue_burst(qp->ingress_queue,
313 			(void **)ops, nb_ops, NULL);
314 
315 	for (i = 0; i < nb_dequeued; i++) {
316 
317 		sess = ipsec_mb_get_session_private(qp, ops[i]);
318 		if (unlikely(sess == NULL)) {
319 			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
320 			qp->stats.dequeue_err_count++;
321 			break;
322 		}
323 
324 		retval = chacha20_poly1305_crypto_op(qp, ops[i], sess);
325 		if (retval < 0) {
326 			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
327 			qp->stats.dequeue_err_count++;
328 			break;
329 		}
330 
331 		handle_completed_chacha20_poly1305_crypto_op(qp, ops[i], sess);
332 	}
333 
334 	qp->stats.dequeued_count += i;
335 
336 	return i;
337 }
338 
339 struct rte_cryptodev_ops chacha20_poly1305_pmd_ops = {
340 	.dev_configure = ipsec_mb_config,
341 	.dev_start = ipsec_mb_start,
342 	.dev_stop = ipsec_mb_stop,
343 	.dev_close = ipsec_mb_close,
344 
345 	.stats_get = ipsec_mb_stats_get,
346 	.stats_reset = ipsec_mb_stats_reset,
347 
348 	.dev_infos_get = ipsec_mb_info_get,
349 
350 	.queue_pair_setup = ipsec_mb_qp_setup,
351 	.queue_pair_release = ipsec_mb_qp_release,
352 
353 	.sym_session_get_size = ipsec_mb_sym_session_get_size,
354 	.sym_session_configure = ipsec_mb_sym_session_configure,
355 	.sym_session_clear = ipsec_mb_sym_session_clear
356 };
357 
358 struct rte_cryptodev_ops *rte_chacha20_poly1305_pmd_ops =
359 						&chacha20_poly1305_pmd_ops;
360 
361 static int
362 chacha20_poly1305_probe(struct rte_vdev_device *vdev)
363 {
364 	return ipsec_mb_create(vdev, IPSEC_MB_PMD_TYPE_CHACHA20_POLY1305);
365 }
366 
367 static struct rte_vdev_driver cryptodev_chacha20_poly1305_pmd_drv = {
368 	.probe = chacha20_poly1305_probe,
369 	.remove = ipsec_mb_remove
370 };
371 
372 static struct cryptodev_driver chacha20_poly1305_crypto_drv;
373 
374 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_CHACHA20_POLY1305_PMD,
375 					cryptodev_chacha20_poly1305_pmd_drv);
376 RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_CHACHA20_POLY1305_PMD,
377 					cryptodev_chacha20_poly1305_pmd);
378 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_CHACHA20_POLY1305_PMD,
379 			       "max_nb_queue_pairs=<int> socket_id=<int>");
380 RTE_PMD_REGISTER_CRYPTO_DRIVER(chacha20_poly1305_crypto_drv,
381 				cryptodev_chacha20_poly1305_pmd_drv.driver,
382 				pmd_driver_id_chacha20_poly1305);
383 
384 /* Constructor function to register chacha20_poly1305 PMD */
385 RTE_INIT(ipsec_mb_register_chacha20_poly1305)
386 {
387 	struct ipsec_mb_internals *chacha_poly_data
388 		= &ipsec_mb_pmds[IPSEC_MB_PMD_TYPE_CHACHA20_POLY1305];
389 
390 	chacha_poly_data->caps = chacha20_poly1305_capabilities;
391 	chacha_poly_data->dequeue_burst = chacha20_poly1305_pmd_dequeue_burst;
392 	chacha_poly_data->feature_flags =
393 		RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
394 		RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
395 		RTE_CRYPTODEV_FF_IN_PLACE_SGL |
396 		RTE_CRYPTODEV_FF_OOP_SGL_IN_LB_OUT |
397 		RTE_CRYPTODEV_FF_OOP_LB_IN_LB_OUT |
398 		RTE_CRYPTODEV_FF_SYM_CPU_CRYPTO |
399 		RTE_CRYPTODEV_FF_SYM_SESSIONLESS;
400 	chacha_poly_data->internals_priv_size = 0;
401 	chacha_poly_data->ops = &chacha20_poly1305_pmd_ops;
402 	chacha_poly_data->qp_priv_size =
403 			sizeof(struct chacha20_poly1305_qp_data);
404 	chacha_poly_data->session_configure =
405 			chacha20_poly1305_session_configure;
406 	chacha_poly_data->session_priv_size =
407 			sizeof(struct chacha20_poly1305_session);
408 }
409