xref: /optee_os/core/drivers/crypto/hisilicon/hpre_dh.c (revision 1868eb206733e931b6c6c2d85d55e646bc8a2496)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022-2024, HiSilicon Technologies Co., Ltd.
4  * Kunpeng hardware accelerator hpre dh algorithm implementation.
5  */
6 
7 #include <drvcrypt.h>
8 #include <drvcrypt_acipher.h>
9 #include <initcall.h>
10 #include <malloc.h>
11 #include <rng_support.h>
12 #include <stdlib_ext.h>
13 #include <string.h>
14 #include <string_ext.h>
15 #include <trace.h>
16 
17 #include "hpre_dh.h"
18 #include "hpre_main.h"
19 
20 static TEE_Result hpre_dh_alloc_keypair(struct dh_keypair *key,
21 					size_t size_bits)
22 {
23 	if (!key || !size_bits) {
24 		EMSG("Invalid input parameter");
25 		return TEE_ERROR_BAD_PARAMETERS;
26 	}
27 
28 	memset(key, 0, sizeof(*key));
29 	key->g = crypto_bignum_allocate(size_bits);
30 	if (!key->g)
31 		goto g_err;
32 
33 	key->p = crypto_bignum_allocate(size_bits);
34 	if (!key->p)
35 		goto p_err;
36 
37 	key->x = crypto_bignum_allocate(size_bits);
38 	if (!key->x)
39 		goto x_err;
40 
41 	key->y = crypto_bignum_allocate(size_bits);
42 	if (!key->y)
43 		goto y_err;
44 
45 	/* Allocate subprime even if not used */
46 	key->q = crypto_bignum_allocate(size_bits);
47 	if (!key->q)
48 		goto q_err;
49 
50 	return TEE_SUCCESS;
51 q_err:
52 	crypto_bignum_free(&key->y);
53 y_err:
54 	crypto_bignum_free(&key->x);
55 x_err:
56 	crypto_bignum_free(&key->p);
57 p_err:
58 	crypto_bignum_free(&key->g);
59 g_err:
60 	EMSG("HPRE dh alloc key pair fail.");
61 
62 	return TEE_ERROR_OUT_OF_MEMORY;
63 }
64 
65 static enum hisi_drv_status hpre_dh_fill_sqe(void *bd, void *info)
66 {
67 	struct hpre_dh_msg *msg = info;
68 	struct hpre_sqe *sqe = bd;
69 
70 	sqe->w0 = msg->alg_type | SHIFT_U32(0x1, HPRE_DONE_SHIFT);
71 	sqe->task_len1 = TASK_LENGTH(msg->key_bytes);
72 	sqe->key = msg->x_p_dma;
73 	sqe->in = msg->g_dma;
74 	sqe->out = msg->out_dma;
75 
76 	return HISI_QM_DRVCRYPT_NO_ERR;
77 }
78 
79 static enum hisi_drv_status hpre_dh_parse_sqe(void *bd, void *info)
80 {
81 	struct hpre_dh_msg *msg = info;
82 	struct hpre_sqe *sqe = bd;
83 	uint16_t err = 0;
84 	uint16_t done = 0;
85 
86 	err = HPRE_TASK_ETYPE(sqe->w0);
87 	done = HPRE_TASK_DONE(sqe->w0);
88 	if (done != HPRE_HW_TASK_DONE || err) {
89 		EMSG("HPRE do dh fail! done=0x%"PRIx16", etype=0x%"PRIx16,
90 		     done, err);
91 		return HISI_QM_DRVCRYPT_IN_EPARA;
92 	}
93 
94 	if (hpre_bin_to_crypto_bin(msg->out, msg->out, msg->key_bytes,
95 				   msg->out_bytes)) {
96 		EMSG("Fail to transfer dh_y from hpre_bin to crypto_bin");
97 		return HISI_QM_DRVCRYPT_EINVAL;
98 	}
99 
100 	return HISI_QM_DRVCRYPT_NO_ERR;
101 }
102 
103 static TEE_Result hpre_dh_do_task(void *msg)
104 {
105 	enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
106 	TEE_Result res = TEE_SUCCESS;
107 	struct hisi_qp *qp = NULL;
108 
109 	qp = hpre_create_qp(HISI_QM_CHANNEL_TYPE0);
110 	if (!qp) {
111 		EMSG("Fail to create dh qp");
112 		return TEE_ERROR_BUSY;
113 	}
114 
115 	qp->fill_sqe = hpre_dh_fill_sqe;
116 	qp->parse_sqe = hpre_dh_parse_sqe;
117 	ret = hisi_qp_send(qp, msg);
118 	if (ret) {
119 		EMSG("Fail to send task, ret=%d", ret);
120 		res = TEE_ERROR_BAD_STATE;
121 		goto done_proc;
122 	}
123 
124 	ret = hisi_qp_recv_sync(qp, msg);
125 	if (ret) {
126 		EMSG("Recv task error, ret=%d", ret);
127 		res = TEE_ERROR_BAD_STATE;
128 		goto done_proc;
129 	}
130 
131 done_proc:
132 	hisi_qm_release_qp(qp);
133 
134 	return res;
135 }
136 
137 static size_t round_key_size_to_hw_size(size_t key_bytes)
138 {
139 	size_t size = 0;
140 
141 	if (key_bytes <= 96)
142 		size = 96;
143 	else if (key_bytes <= 128)
144 		size = 128;
145 	else if (key_bytes <= 192)
146 		size = 192;
147 	else if (key_bytes <= 256)
148 		size = 256;
149 	else if (key_bytes <= 384)
150 		size = 384;
151 	else if (key_bytes <= 512)
152 		size = 512;
153 	else
154 		EMSG("Invalid key_bytes[%zu]", key_bytes);
155 
156 	return size;
157 }
158 
159 static TEE_Result hpre_dh_gen_privkey(struct bignum *x, size_t key_bits)
160 {
161 	size_t key_bytes = BITS_TO_BYTES(key_bits);
162 	uint8_t buf[HPRE_DH_MAX_KEY_BYTES] = { };
163 	TEE_Result ret = TEE_SUCCESS;
164 
165 	if (hw_get_random_bytes(buf, key_bytes)) {
166 		EMSG("Fail to fill privkey");
167 		return TEE_ERROR_NO_DATA;
168 	}
169 
170 	ret = crypto_bignum_bin2bn(buf, key_bytes, x);
171 	memzero_explicit(buf, key_bytes);
172 
173 	return ret;
174 }
175 
176 static enum hisi_drv_status hpre_dh_params_alloc(struct hpre_dh_msg *msg)
177 {
178 	uint32_t size = HPRE_DH_TOTAL_BUF_SIZE(msg->key_bytes);
179 	uint8_t *data = NULL;
180 
181 	data = calloc(1, size);
182 	if (!data) {
183 		EMSG("Fail to alloc dh total buf");
184 		return HISI_QM_DRVCRYPT_ENOMEM;
185 	}
186 
187 	msg->x_p = data;
188 	msg->x_p_dma = virt_to_phys(msg->x_p);
189 
190 	msg->g = msg->x_p + (msg->key_bytes << 1);
191 	msg->g_dma = msg->x_p_dma + (msg->key_bytes << 1);
192 	msg->out = msg->g + msg->key_bytes;
193 	msg->out_dma = msg->g_dma + msg->key_bytes;
194 
195 	return HISI_QM_DRVCRYPT_NO_ERR;
196 }
197 
198 static void hpre_dh_params_free(struct hpre_dh_msg *msg)
199 {
200 	if (msg->x_p) {
201 		free_wipe(msg->x_p);
202 		msg->x_p = NULL;
203 	}
204 }
205 
206 static enum hisi_drv_status hpre_dh_params_bn2bin(struct hpre_dh_msg *msg,
207 						  struct dh_keypair *key,
208 						  struct bignum *pubkey)
209 {
210 	uint8_t *p = msg->x_p + msg->key_bytes;
211 	uint8_t *x = msg->x_p;
212 	enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
213 
214 	msg->xbytes = BITS_TO_BYTES(key->xbits);
215 	msg->out_bytes = msg->pbytes;
216 	crypto_bignum_bn2bin(key->x, x);
217 	crypto_bignum_bn2bin(key->p, p);
218 
219 	if (!pubkey) {
220 		msg->gbytes = crypto_bignum_num_bytes(key->g);
221 		crypto_bignum_bn2bin(key->g, msg->g);
222 	} else {
223 		msg->gbytes = crypto_bignum_num_bytes(pubkey);
224 		if (msg->gbytes != msg->pbytes)
225 			return HISI_QM_DRVCRYPT_EINVAL;
226 		crypto_bignum_bn2bin(pubkey, msg->g);
227 	}
228 
229 	ret = hpre_bin_from_crypto_bin(x, x, msg->key_bytes, msg->xbytes);
230 	if (ret) {
231 		EMSG("Fail to transfer dh_x from crypto_bin to hpre_bin");
232 		return ret;
233 	}
234 
235 	ret = hpre_bin_from_crypto_bin(p, p, msg->key_bytes, msg->pbytes);
236 	if (ret) {
237 		EMSG("Fail to transfer dh_p from crypto_bin to hpre_bin");
238 		return ret;
239 	}
240 
241 	ret = hpre_bin_from_crypto_bin(msg->g, msg->g, msg->key_bytes,
242 				       msg->gbytes);
243 	if (ret)
244 		EMSG("Fail to transfer dh_g from crypto_bin to hpre_bin");
245 
246 	return ret;
247 }
248 
249 static TEE_Result hpre_dh_request_init(struct hpre_dh_msg *msg,
250 				       struct dh_keypair *key,
251 				       struct bignum *pubkey)
252 {
253 	enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
254 
255 	msg->alg_type = HPRE_ALG_DH;
256 	msg->key_bytes = round_key_size_to_hw_size(msg->pbytes);
257 	if (!msg->key_bytes)
258 		return TEE_ERROR_BAD_PARAMETERS;
259 
260 	ret = hpre_dh_params_alloc(msg);
261 	if (ret)
262 		return TEE_ERROR_OUT_OF_MEMORY;
263 
264 	ret = hpre_dh_params_bn2bin(msg, key, pubkey);
265 	if (ret) {
266 		hpre_dh_params_free(msg);
267 		return TEE_ERROR_BAD_STATE;
268 	}
269 
270 	return TEE_SUCCESS;
271 }
272 
273 static void hpre_dh_request_deinit(struct hpre_dh_msg *msg)
274 {
275 	hpre_dh_params_free(msg);
276 }
277 
278 static TEE_Result hpre_dh_gen_keypair(struct dh_keypair *key,
279 				      struct bignum *q __unused,
280 				      size_t key_size)
281 {
282 	struct hpre_dh_msg msg = { };
283 	TEE_Result ret = TEE_SUCCESS;
284 	size_t p_bits = 0;
285 
286 	if (!key || !key->g || !key->p || !key->x || !key->y) {
287 		EMSG("Invalid dh_gen_keypair input parameters");
288 		return TEE_ERROR_BAD_PARAMETERS;
289 	}
290 
291 	p_bits = crypto_bignum_num_bits(key->p);
292 	if (!p_bits) {
293 		EMSG("p_bits can not be zero");
294 		return TEE_ERROR_BAD_PARAMETERS;
295 	}
296 	msg.pbytes = BITS_TO_BYTES(p_bits);
297 
298 	if (!key_size) {
299 		/* xbits */
300 		key->xbits = p_bits;
301 		ret = hpre_dh_gen_privkey(key->x, key->xbits);
302 		if (ret) {
303 			EMSG("Fail to gen dh privkey");
304 			return ret;
305 		}
306 	} else {
307 		key->xbits = key_size;
308 	}
309 
310 	ret = hpre_dh_request_init(&msg, key, NULL);
311 	if (ret) {
312 		EMSG("Fail to init dh msg");
313 		return ret;
314 	}
315 
316 	ret = hpre_dh_do_task(&msg);
317 	if (ret)
318 		goto req_deinit;
319 
320 	ret = crypto_bignum_bin2bn(msg.out, msg.out_bytes, key->y);
321 	if (ret)
322 		EMSG("Fail to bin2bn msg out");
323 
324 req_deinit:
325 	hpre_dh_request_deinit(&msg);
326 
327 	return ret;
328 }
329 
330 static TEE_Result hpre_dh_do_shared_secret(struct drvcrypt_secret_data *sdata)
331 {
332 	struct hpre_dh_msg msg = { };
333 	struct dh_keypair *key = NULL;
334 	TEE_Result ret = TEE_SUCCESS;
335 
336 	if (!sdata || !sdata->key_priv || !sdata->key_pub) {
337 		EMSG("Invalid dh_do_shared_secret input parameters");
338 		return TEE_ERROR_BAD_PARAMETERS;
339 	}
340 
341 	key = sdata->key_priv;
342 	key->xbits = crypto_bignum_num_bits(key->x);
343 	if (!key->xbits) {
344 		EMSG("xbits can not be zero");
345 		return TEE_ERROR_BAD_PARAMETERS;
346 	}
347 	msg.pbytes = crypto_bignum_num_bytes(key->p);
348 
349 	ret = hpre_dh_request_init(&msg, key, (struct bignum *)sdata->key_pub);
350 	if (ret) {
351 		EMSG("Fail to init dh msg");
352 		return ret;
353 	}
354 
355 	ret = hpre_dh_do_task(&msg);
356 	if (ret)
357 		goto req_deinit;
358 
359 	sdata->secret.length = msg.out_bytes;
360 	memcpy(sdata->secret.data, msg.out, msg.out_bytes);
361 	memzero_explicit(msg.out, msg.out_bytes);
362 
363 req_deinit:
364 	hpre_dh_request_deinit(&msg);
365 
366 	return ret;
367 }
368 
369 static struct drvcrypt_dh driver_dh = {
370 	.alloc_keypair = hpre_dh_alloc_keypair,
371 	.gen_keypair = hpre_dh_gen_keypair,
372 	.shared_secret = hpre_dh_do_shared_secret,
373 };
374 
375 TEE_Result hpre_dh_init(void)
376 {
377 	TEE_Result ret = drvcrypt_register_dh(&driver_dh);
378 
379 	if (ret != TEE_SUCCESS)
380 		EMSG("hpre dh register to crypto fail.");
381 
382 	return ret;
383 }
384 
385 driver_init(hpre_dh_init);
386