xref: /optee_os/core/drivers/crypto/hisilicon/hpre_dh.c (revision b6a44cc5a792f1ca0c8f4fc0a9ae33f1017c1e2f)
179502744Syuzexi // SPDX-License-Identifier: BSD-2-Clause
279502744Syuzexi /*
379502744Syuzexi  * Copyright (c) 2022-2024, HiSilicon Technologies Co., Ltd.
479502744Syuzexi  * Kunpeng hardware accelerator hpre dh algorithm implementation.
579502744Syuzexi  */
679502744Syuzexi 
779502744Syuzexi #include <drvcrypt.h>
879502744Syuzexi #include <drvcrypt_acipher.h>
979502744Syuzexi #include <initcall.h>
1079502744Syuzexi #include <malloc.h>
1179502744Syuzexi #include <rng_support.h>
1279502744Syuzexi #include <stdlib_ext.h>
1379502744Syuzexi #include <string.h>
1479502744Syuzexi #include <string_ext.h>
1579502744Syuzexi #include <trace.h>
1679502744Syuzexi 
17*b6a44cc5Sleisen #include "hpre_dh.h"
18*b6a44cc5Sleisen #include "hpre_main.h"
19*b6a44cc5Sleisen 
hpre_dh_alloc_keypair(struct dh_keypair * key,size_t size_bits)2079502744Syuzexi static TEE_Result hpre_dh_alloc_keypair(struct dh_keypair *key,
2179502744Syuzexi 					size_t size_bits)
2279502744Syuzexi {
2379502744Syuzexi 	if (!key || !size_bits) {
2479502744Syuzexi 		EMSG("Invalid input parameter");
2579502744Syuzexi 		return TEE_ERROR_BAD_PARAMETERS;
2679502744Syuzexi 	}
2779502744Syuzexi 
2879502744Syuzexi 	memset(key, 0, sizeof(*key));
2979502744Syuzexi 	key->g = crypto_bignum_allocate(size_bits);
3079502744Syuzexi 	if (!key->g)
3179502744Syuzexi 		goto g_err;
3279502744Syuzexi 
3379502744Syuzexi 	key->p = crypto_bignum_allocate(size_bits);
3479502744Syuzexi 	if (!key->p)
3579502744Syuzexi 		goto p_err;
3679502744Syuzexi 
3779502744Syuzexi 	key->x = crypto_bignum_allocate(size_bits);
3879502744Syuzexi 	if (!key->x)
3979502744Syuzexi 		goto x_err;
4079502744Syuzexi 
4179502744Syuzexi 	key->y = crypto_bignum_allocate(size_bits);
4279502744Syuzexi 	if (!key->y)
4379502744Syuzexi 		goto y_err;
4479502744Syuzexi 
4579502744Syuzexi 	/* Allocate subprime even if not used */
4679502744Syuzexi 	key->q = crypto_bignum_allocate(size_bits);
4779502744Syuzexi 	if (!key->q)
4879502744Syuzexi 		goto q_err;
4979502744Syuzexi 
5079502744Syuzexi 	return TEE_SUCCESS;
5179502744Syuzexi q_err:
5279502744Syuzexi 	crypto_bignum_free(&key->y);
5379502744Syuzexi y_err:
5479502744Syuzexi 	crypto_bignum_free(&key->x);
5579502744Syuzexi x_err:
5679502744Syuzexi 	crypto_bignum_free(&key->p);
5779502744Syuzexi p_err:
5879502744Syuzexi 	crypto_bignum_free(&key->g);
5979502744Syuzexi g_err:
6079502744Syuzexi 	EMSG("HPRE dh alloc key pair fail.");
6179502744Syuzexi 
6279502744Syuzexi 	return TEE_ERROR_OUT_OF_MEMORY;
6379502744Syuzexi }
6479502744Syuzexi 
hpre_dh_fill_sqe(void * bd,void * info)6579502744Syuzexi static enum hisi_drv_status hpre_dh_fill_sqe(void *bd, void *info)
6679502744Syuzexi {
6779502744Syuzexi 	struct hpre_dh_msg *msg = info;
6879502744Syuzexi 	struct hpre_sqe *sqe = bd;
6979502744Syuzexi 
7079502744Syuzexi 	sqe->w0 = msg->alg_type | SHIFT_U32(0x1, HPRE_DONE_SHIFT);
7179502744Syuzexi 	sqe->task_len1 = TASK_LENGTH(msg->key_bytes);
7279502744Syuzexi 	sqe->key = msg->x_p_dma;
7379502744Syuzexi 	sqe->in = msg->g_dma;
7479502744Syuzexi 	sqe->out = msg->out_dma;
7579502744Syuzexi 
7679502744Syuzexi 	return HISI_QM_DRVCRYPT_NO_ERR;
7779502744Syuzexi }
7879502744Syuzexi 
hpre_dh_parse_sqe(void * bd,void * info)7979502744Syuzexi static enum hisi_drv_status hpre_dh_parse_sqe(void *bd, void *info)
8079502744Syuzexi {
8179502744Syuzexi 	struct hpre_dh_msg *msg = info;
8279502744Syuzexi 	struct hpre_sqe *sqe = bd;
8379502744Syuzexi 	uint16_t err = 0;
8479502744Syuzexi 	uint16_t done = 0;
8579502744Syuzexi 
8679502744Syuzexi 	err = HPRE_TASK_ETYPE(sqe->w0);
8779502744Syuzexi 	done = HPRE_TASK_DONE(sqe->w0);
8879502744Syuzexi 	if (done != HPRE_HW_TASK_DONE || err) {
8979502744Syuzexi 		EMSG("HPRE do dh fail! done=0x%"PRIx16", etype=0x%"PRIx16,
9079502744Syuzexi 		     done, err);
9179502744Syuzexi 		return HISI_QM_DRVCRYPT_IN_EPARA;
9279502744Syuzexi 	}
9379502744Syuzexi 
9479502744Syuzexi 	if (hpre_bin_to_crypto_bin(msg->out, msg->out, msg->key_bytes,
9579502744Syuzexi 				   msg->out_bytes)) {
9679502744Syuzexi 		EMSG("Fail to transfer dh_y from hpre_bin to crypto_bin");
9779502744Syuzexi 		return HISI_QM_DRVCRYPT_EINVAL;
9879502744Syuzexi 	}
9979502744Syuzexi 
10079502744Syuzexi 	return HISI_QM_DRVCRYPT_NO_ERR;
10179502744Syuzexi }
10279502744Syuzexi 
hpre_dh_do_task(void * msg)10379502744Syuzexi static TEE_Result hpre_dh_do_task(void *msg)
10479502744Syuzexi {
10579502744Syuzexi 	enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
10679502744Syuzexi 	TEE_Result res = TEE_SUCCESS;
10779502744Syuzexi 	struct hisi_qp *qp = NULL;
10879502744Syuzexi 
10979502744Syuzexi 	qp = hpre_create_qp(HISI_QM_CHANNEL_TYPE0);
11079502744Syuzexi 	if (!qp) {
11179502744Syuzexi 		EMSG("Fail to create dh qp");
11279502744Syuzexi 		return TEE_ERROR_BUSY;
11379502744Syuzexi 	}
11479502744Syuzexi 
11579502744Syuzexi 	qp->fill_sqe = hpre_dh_fill_sqe;
11679502744Syuzexi 	qp->parse_sqe = hpre_dh_parse_sqe;
11779502744Syuzexi 	ret = hisi_qp_send(qp, msg);
11879502744Syuzexi 	if (ret) {
11979502744Syuzexi 		EMSG("Fail to send task, ret=%d", ret);
12079502744Syuzexi 		res = TEE_ERROR_BAD_STATE;
12179502744Syuzexi 		goto done_proc;
12279502744Syuzexi 	}
12379502744Syuzexi 
12479502744Syuzexi 	ret = hisi_qp_recv_sync(qp, msg);
12579502744Syuzexi 	if (ret) {
12679502744Syuzexi 		EMSG("Recv task error, ret=%d", ret);
12779502744Syuzexi 		res = TEE_ERROR_BAD_STATE;
12879502744Syuzexi 		goto done_proc;
12979502744Syuzexi 	}
13079502744Syuzexi 
13179502744Syuzexi done_proc:
13279502744Syuzexi 	hisi_qm_release_qp(qp);
13379502744Syuzexi 
13479502744Syuzexi 	return res;
13579502744Syuzexi }
13679502744Syuzexi 
round_key_size_to_hw_size(size_t key_bytes)13779502744Syuzexi static size_t round_key_size_to_hw_size(size_t key_bytes)
13879502744Syuzexi {
13979502744Syuzexi 	size_t size = 0;
14079502744Syuzexi 
14179502744Syuzexi 	if (key_bytes <= 96)
14279502744Syuzexi 		size = 96;
14379502744Syuzexi 	else if (key_bytes <= 128)
14479502744Syuzexi 		size = 128;
14579502744Syuzexi 	else if (key_bytes <= 192)
14679502744Syuzexi 		size = 192;
14779502744Syuzexi 	else if (key_bytes <= 256)
14879502744Syuzexi 		size = 256;
14979502744Syuzexi 	else if (key_bytes <= 384)
15079502744Syuzexi 		size = 384;
15179502744Syuzexi 	else if (key_bytes <= 512)
15279502744Syuzexi 		size = 512;
15379502744Syuzexi 	else
15479502744Syuzexi 		EMSG("Invalid key_bytes[%zu]", key_bytes);
15579502744Syuzexi 
15679502744Syuzexi 	return size;
15779502744Syuzexi }
15879502744Syuzexi 
hpre_dh_gen_privkey(struct bignum * x,size_t key_bits)15979502744Syuzexi static TEE_Result hpre_dh_gen_privkey(struct bignum *x, size_t key_bits)
16079502744Syuzexi {
16179502744Syuzexi 	size_t key_bytes = BITS_TO_BYTES(key_bits);
16279502744Syuzexi 	uint8_t buf[HPRE_DH_MAX_KEY_BYTES] = { };
16379502744Syuzexi 	TEE_Result ret = TEE_SUCCESS;
16479502744Syuzexi 
16579502744Syuzexi 	if (hw_get_random_bytes(buf, key_bytes)) {
16679502744Syuzexi 		EMSG("Fail to fill privkey");
16779502744Syuzexi 		return TEE_ERROR_NO_DATA;
16879502744Syuzexi 	}
16979502744Syuzexi 
17079502744Syuzexi 	ret = crypto_bignum_bin2bn(buf, key_bytes, x);
17179502744Syuzexi 	memzero_explicit(buf, key_bytes);
17279502744Syuzexi 
17379502744Syuzexi 	return ret;
17479502744Syuzexi }
17579502744Syuzexi 
hpre_dh_params_alloc(struct hpre_dh_msg * msg)17679502744Syuzexi static enum hisi_drv_status hpre_dh_params_alloc(struct hpre_dh_msg *msg)
17779502744Syuzexi {
17879502744Syuzexi 	uint32_t size = HPRE_DH_TOTAL_BUF_SIZE(msg->key_bytes);
17979502744Syuzexi 	uint8_t *data = NULL;
18079502744Syuzexi 
18179502744Syuzexi 	data = calloc(1, size);
18279502744Syuzexi 	if (!data) {
18379502744Syuzexi 		EMSG("Fail to alloc dh total buf");
18479502744Syuzexi 		return HISI_QM_DRVCRYPT_ENOMEM;
18579502744Syuzexi 	}
18679502744Syuzexi 
18779502744Syuzexi 	msg->x_p = data;
18879502744Syuzexi 	msg->x_p_dma = virt_to_phys(msg->x_p);
18979502744Syuzexi 
19079502744Syuzexi 	msg->g = msg->x_p + (msg->key_bytes << 1);
19179502744Syuzexi 	msg->g_dma = msg->x_p_dma + (msg->key_bytes << 1);
19279502744Syuzexi 	msg->out = msg->g + msg->key_bytes;
19379502744Syuzexi 	msg->out_dma = msg->g_dma + msg->key_bytes;
19479502744Syuzexi 
19579502744Syuzexi 	return HISI_QM_DRVCRYPT_NO_ERR;
19679502744Syuzexi }
19779502744Syuzexi 
hpre_dh_params_free(struct hpre_dh_msg * msg)19879502744Syuzexi static void hpre_dh_params_free(struct hpre_dh_msg *msg)
19979502744Syuzexi {
20079502744Syuzexi 	if (msg->x_p) {
20179502744Syuzexi 		free_wipe(msg->x_p);
20279502744Syuzexi 		msg->x_p = NULL;
20379502744Syuzexi 	}
20479502744Syuzexi }
20579502744Syuzexi 
hpre_dh_params_bn2bin(struct hpre_dh_msg * msg,struct dh_keypair * key,struct bignum * pubkey)20679502744Syuzexi static enum hisi_drv_status hpre_dh_params_bn2bin(struct hpre_dh_msg *msg,
20779502744Syuzexi 						  struct dh_keypair *key,
20879502744Syuzexi 						  struct bignum *pubkey)
20979502744Syuzexi {
21079502744Syuzexi 	uint8_t *p = msg->x_p + msg->key_bytes;
21179502744Syuzexi 	uint8_t *x = msg->x_p;
21279502744Syuzexi 	enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
21379502744Syuzexi 
21479502744Syuzexi 	msg->xbytes = BITS_TO_BYTES(key->xbits);
21579502744Syuzexi 	msg->out_bytes = msg->pbytes;
21679502744Syuzexi 	crypto_bignum_bn2bin(key->x, x);
21779502744Syuzexi 	crypto_bignum_bn2bin(key->p, p);
21879502744Syuzexi 
21979502744Syuzexi 	if (!pubkey) {
22079502744Syuzexi 		msg->gbytes = crypto_bignum_num_bytes(key->g);
22179502744Syuzexi 		crypto_bignum_bn2bin(key->g, msg->g);
22279502744Syuzexi 	} else {
22379502744Syuzexi 		msg->gbytes = crypto_bignum_num_bytes(pubkey);
22479502744Syuzexi 		if (msg->gbytes != msg->pbytes)
22579502744Syuzexi 			return HISI_QM_DRVCRYPT_EINVAL;
22679502744Syuzexi 		crypto_bignum_bn2bin(pubkey, msg->g);
22779502744Syuzexi 	}
22879502744Syuzexi 
22979502744Syuzexi 	ret = hpre_bin_from_crypto_bin(x, x, msg->key_bytes, msg->xbytes);
23079502744Syuzexi 	if (ret) {
23179502744Syuzexi 		EMSG("Fail to transfer dh_x from crypto_bin to hpre_bin");
23279502744Syuzexi 		return ret;
23379502744Syuzexi 	}
23479502744Syuzexi 
23579502744Syuzexi 	ret = hpre_bin_from_crypto_bin(p, p, msg->key_bytes, msg->pbytes);
23679502744Syuzexi 	if (ret) {
23779502744Syuzexi 		EMSG("Fail to transfer dh_p from crypto_bin to hpre_bin");
23879502744Syuzexi 		return ret;
23979502744Syuzexi 	}
24079502744Syuzexi 
24179502744Syuzexi 	ret = hpre_bin_from_crypto_bin(msg->g, msg->g, msg->key_bytes,
24279502744Syuzexi 				       msg->gbytes);
24379502744Syuzexi 	if (ret)
24479502744Syuzexi 		EMSG("Fail to transfer dh_g from crypto_bin to hpre_bin");
24579502744Syuzexi 
24679502744Syuzexi 	return ret;
24779502744Syuzexi }
24879502744Syuzexi 
hpre_dh_request_init(struct hpre_dh_msg * msg,struct dh_keypair * key,struct bignum * pubkey)24979502744Syuzexi static TEE_Result hpre_dh_request_init(struct hpre_dh_msg *msg,
25079502744Syuzexi 				       struct dh_keypair *key,
25179502744Syuzexi 				       struct bignum *pubkey)
25279502744Syuzexi {
25379502744Syuzexi 	enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
25479502744Syuzexi 
25579502744Syuzexi 	msg->alg_type = HPRE_ALG_DH;
25679502744Syuzexi 	msg->key_bytes = round_key_size_to_hw_size(msg->pbytes);
25779502744Syuzexi 	if (!msg->key_bytes)
25879502744Syuzexi 		return TEE_ERROR_BAD_PARAMETERS;
25979502744Syuzexi 
26079502744Syuzexi 	ret = hpre_dh_params_alloc(msg);
26179502744Syuzexi 	if (ret)
26279502744Syuzexi 		return TEE_ERROR_OUT_OF_MEMORY;
26379502744Syuzexi 
26479502744Syuzexi 	ret = hpre_dh_params_bn2bin(msg, key, pubkey);
26579502744Syuzexi 	if (ret) {
26679502744Syuzexi 		hpre_dh_params_free(msg);
26779502744Syuzexi 		return TEE_ERROR_BAD_STATE;
26879502744Syuzexi 	}
26979502744Syuzexi 
27079502744Syuzexi 	return TEE_SUCCESS;
27179502744Syuzexi }
27279502744Syuzexi 
hpre_dh_request_deinit(struct hpre_dh_msg * msg)27379502744Syuzexi static void hpre_dh_request_deinit(struct hpre_dh_msg *msg)
27479502744Syuzexi {
27579502744Syuzexi 	hpre_dh_params_free(msg);
27679502744Syuzexi }
27779502744Syuzexi 
hpre_dh_gen_keypair(struct dh_keypair * key,struct bignum * q __unused,size_t key_size)27879502744Syuzexi static TEE_Result hpre_dh_gen_keypair(struct dh_keypair *key,
27979502744Syuzexi 				      struct bignum *q __unused,
28079502744Syuzexi 				      size_t key_size)
28179502744Syuzexi {
28279502744Syuzexi 	struct hpre_dh_msg msg = { };
28379502744Syuzexi 	TEE_Result ret = TEE_SUCCESS;
28479502744Syuzexi 	size_t p_bits = 0;
28579502744Syuzexi 
28679502744Syuzexi 	if (!key || !key->g || !key->p || !key->x || !key->y) {
28779502744Syuzexi 		EMSG("Invalid dh_gen_keypair input parameters");
28879502744Syuzexi 		return TEE_ERROR_BAD_PARAMETERS;
28979502744Syuzexi 	}
29079502744Syuzexi 
29179502744Syuzexi 	p_bits = crypto_bignum_num_bits(key->p);
29279502744Syuzexi 	if (!p_bits) {
29379502744Syuzexi 		EMSG("p_bits can not be zero");
29479502744Syuzexi 		return TEE_ERROR_BAD_PARAMETERS;
29579502744Syuzexi 	}
29679502744Syuzexi 	msg.pbytes = BITS_TO_BYTES(p_bits);
29779502744Syuzexi 
29879502744Syuzexi 	if (!key_size) {
29979502744Syuzexi 		/* xbits */
30079502744Syuzexi 		key->xbits = p_bits;
30179502744Syuzexi 		ret = hpre_dh_gen_privkey(key->x, key->xbits);
30279502744Syuzexi 		if (ret) {
30379502744Syuzexi 			EMSG("Fail to gen dh privkey");
30479502744Syuzexi 			return ret;
30579502744Syuzexi 		}
30679502744Syuzexi 	} else {
30779502744Syuzexi 		key->xbits = key_size;
30879502744Syuzexi 	}
30979502744Syuzexi 
31079502744Syuzexi 	ret = hpre_dh_request_init(&msg, key, NULL);
31179502744Syuzexi 	if (ret) {
31279502744Syuzexi 		EMSG("Fail to init dh msg");
31379502744Syuzexi 		return ret;
31479502744Syuzexi 	}
31579502744Syuzexi 
31679502744Syuzexi 	ret = hpre_dh_do_task(&msg);
31779502744Syuzexi 	if (ret)
31879502744Syuzexi 		goto req_deinit;
31979502744Syuzexi 
32079502744Syuzexi 	ret = crypto_bignum_bin2bn(msg.out, msg.out_bytes, key->y);
32179502744Syuzexi 	if (ret)
32279502744Syuzexi 		EMSG("Fail to bin2bn msg out");
32379502744Syuzexi 
32479502744Syuzexi req_deinit:
32579502744Syuzexi 	hpre_dh_request_deinit(&msg);
32679502744Syuzexi 
32779502744Syuzexi 	return ret;
32879502744Syuzexi }
32979502744Syuzexi 
hpre_dh_do_shared_secret(struct drvcrypt_secret_data * sdata)33079502744Syuzexi static TEE_Result hpre_dh_do_shared_secret(struct drvcrypt_secret_data *sdata)
33179502744Syuzexi {
33279502744Syuzexi 	struct hpre_dh_msg msg = { };
33379502744Syuzexi 	struct dh_keypair *key = NULL;
33479502744Syuzexi 	TEE_Result ret = TEE_SUCCESS;
33579502744Syuzexi 
33679502744Syuzexi 	if (!sdata || !sdata->key_priv || !sdata->key_pub) {
33779502744Syuzexi 		EMSG("Invalid dh_do_shared_secret input parameters");
33879502744Syuzexi 		return TEE_ERROR_BAD_PARAMETERS;
33979502744Syuzexi 	}
34079502744Syuzexi 
34179502744Syuzexi 	key = sdata->key_priv;
34279502744Syuzexi 	key->xbits = crypto_bignum_num_bits(key->x);
34379502744Syuzexi 	if (!key->xbits) {
34479502744Syuzexi 		EMSG("xbits can not be zero");
34579502744Syuzexi 		return TEE_ERROR_BAD_PARAMETERS;
34679502744Syuzexi 	}
34779502744Syuzexi 	msg.pbytes = crypto_bignum_num_bytes(key->p);
34879502744Syuzexi 
34979502744Syuzexi 	ret = hpre_dh_request_init(&msg, key, (struct bignum *)sdata->key_pub);
35079502744Syuzexi 	if (ret) {
35179502744Syuzexi 		EMSG("Fail to init dh msg");
35279502744Syuzexi 		return ret;
35379502744Syuzexi 	}
35479502744Syuzexi 
35579502744Syuzexi 	ret = hpre_dh_do_task(&msg);
35679502744Syuzexi 	if (ret)
35779502744Syuzexi 		goto req_deinit;
35879502744Syuzexi 
35979502744Syuzexi 	sdata->secret.length = msg.out_bytes;
36079502744Syuzexi 	memcpy(sdata->secret.data, msg.out, msg.out_bytes);
36179502744Syuzexi 	memzero_explicit(msg.out, msg.out_bytes);
36279502744Syuzexi 
36379502744Syuzexi req_deinit:
36479502744Syuzexi 	hpre_dh_request_deinit(&msg);
36579502744Syuzexi 
36679502744Syuzexi 	return ret;
36779502744Syuzexi }
36879502744Syuzexi 
36979502744Syuzexi static struct drvcrypt_dh driver_dh = {
37079502744Syuzexi 	.alloc_keypair = hpre_dh_alloc_keypair,
37179502744Syuzexi 	.gen_keypair = hpre_dh_gen_keypair,
37279502744Syuzexi 	.shared_secret = hpre_dh_do_shared_secret,
37379502744Syuzexi };
37479502744Syuzexi 
hpre_dh_init(void)37579502744Syuzexi TEE_Result hpre_dh_init(void)
37679502744Syuzexi {
37779502744Syuzexi 	TEE_Result ret = drvcrypt_register_dh(&driver_dh);
37879502744Syuzexi 
37979502744Syuzexi 	if (ret != TEE_SUCCESS)
38079502744Syuzexi 		EMSG("hpre dh register to crypto fail.");
38179502744Syuzexi 
38279502744Syuzexi 	return ret;
38379502744Syuzexi }
38479502744Syuzexi 
38579502744Syuzexi driver_init(hpre_dh_init);
386