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