xref: /optee_os/core/lib/libtomcrypt/sm2-pke.c (revision f9a78287dd1217877e079f0c3cc83f6181a51dc7)
1*f9a78287SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2*f9a78287SJerome Forissier /*
3*f9a78287SJerome Forissier  * Copyright (c) 2019 Huawei Technologies Co., Ltd
4*f9a78287SJerome Forissier  */
5*f9a78287SJerome Forissier 
6*f9a78287SJerome Forissier #include <crypto/crypto.h>
7*f9a78287SJerome Forissier #include <io.h>
8*f9a78287SJerome Forissier #include <stdlib.h>
9*f9a78287SJerome Forissier #include <string.h>
10*f9a78287SJerome Forissier #include <tee_api_types.h>
11*f9a78287SJerome Forissier #include <tee/tee_cryp_utl.h>
12*f9a78287SJerome Forissier #include <trace.h>
13*f9a78287SJerome Forissier #include <util.h>
14*f9a78287SJerome Forissier #include <utee_defines.h>
15*f9a78287SJerome Forissier 
16*f9a78287SJerome Forissier #include "acipher_helpers.h"
17*f9a78287SJerome Forissier 
18*f9a78287SJerome Forissier static TEE_Result
19*f9a78287SJerome Forissier sm2_uncompressed_bytes_to_point(ecc_point *p, const ltc_ecc_dp *dp,
20*f9a78287SJerome Forissier 				const uint8_t *x1y1, size_t max_size,
21*f9a78287SJerome Forissier 				size_t *consumed)
22*f9a78287SJerome Forissier {
23*f9a78287SJerome Forissier 	uint8_t *ptr = (uint8_t *)x1y1;
24*f9a78287SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
25*f9a78287SJerome Forissier 	uint8_t one[] = { 1 };
26*f9a78287SJerome Forissier 	int ltc_res = 0;
27*f9a78287SJerome Forissier 	void *x1 = NULL;
28*f9a78287SJerome Forissier 	void *y1 = NULL;
29*f9a78287SJerome Forissier 
30*f9a78287SJerome Forissier 	if (max_size < (size_t)(2 * dp->size))
31*f9a78287SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
32*f9a78287SJerome Forissier 
33*f9a78287SJerome Forissier 	ltc_res = mp_init_multi(&x1, &y1, &p->z, NULL);
34*f9a78287SJerome Forissier 	if (ltc_res != CRYPT_OK)
35*f9a78287SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
36*f9a78287SJerome Forissier 
37*f9a78287SJerome Forissier 	ltc_res = mp_read_unsigned_bin(x1, ptr, dp->size);
38*f9a78287SJerome Forissier 	if (ltc_res != CRYPT_OK) {
39*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_PARAMETERS;
40*f9a78287SJerome Forissier 		goto err;
41*f9a78287SJerome Forissier 	}
42*f9a78287SJerome Forissier 
43*f9a78287SJerome Forissier 	ptr += dp->size;
44*f9a78287SJerome Forissier 
45*f9a78287SJerome Forissier 	ltc_res = mp_read_unsigned_bin(y1, ptr, dp->size);
46*f9a78287SJerome Forissier 	if (ltc_res != CRYPT_OK) {
47*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_PARAMETERS;
48*f9a78287SJerome Forissier 		goto err;
49*f9a78287SJerome Forissier 	}
50*f9a78287SJerome Forissier 
51*f9a78287SJerome Forissier 	ltc_res = ltc_ecc_is_point(dp, x1, y1);
52*f9a78287SJerome Forissier 	if (ltc_res != CRYPT_OK) {
53*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_PARAMETERS;
54*f9a78287SJerome Forissier 		goto err;
55*f9a78287SJerome Forissier 	}
56*f9a78287SJerome Forissier 
57*f9a78287SJerome Forissier 	p->x = x1;
58*f9a78287SJerome Forissier 	p->y = y1;
59*f9a78287SJerome Forissier 	mp_read_unsigned_bin(p->z, one, sizeof(one));
60*f9a78287SJerome Forissier 
61*f9a78287SJerome Forissier 	*consumed = 2 * dp->size + 1; /* PC */
62*f9a78287SJerome Forissier 
63*f9a78287SJerome Forissier 	return TEE_SUCCESS;
64*f9a78287SJerome Forissier err:
65*f9a78287SJerome Forissier 	mp_clear_multi(x1, y1, p->z, NULL);
66*f9a78287SJerome Forissier 	return res;
67*f9a78287SJerome Forissier }
68*f9a78287SJerome Forissier 
69*f9a78287SJerome Forissier /*
70*f9a78287SJerome Forissier  * GM/T 0003.1‒2012 Part 1 Section 4.2.9
71*f9a78287SJerome Forissier  * Conversion of a byte string @buf to a point @p. Makes sure @p is on the curve
72*f9a78287SJerome Forissier  * defined by domain parameters @dp.
73*f9a78287SJerome Forissier  * Note: only the uncompressed form is supported. Uncompressed and hybrid forms
74*f9a78287SJerome Forissier  * are TBD.
75*f9a78287SJerome Forissier  */
76*f9a78287SJerome Forissier static TEE_Result sm2_bytes_to_point(ecc_point *p, const ltc_ecc_dp *dp,
77*f9a78287SJerome Forissier 				     const uint8_t *buf, size_t max_size,
78*f9a78287SJerome Forissier 				     size_t *consumed)
79*f9a78287SJerome Forissier {
80*f9a78287SJerome Forissier 	uint8_t PC = 0;
81*f9a78287SJerome Forissier 
82*f9a78287SJerome Forissier 	if (!max_size)
83*f9a78287SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
84*f9a78287SJerome Forissier 
85*f9a78287SJerome Forissier 	PC = buf[0];
86*f9a78287SJerome Forissier 
87*f9a78287SJerome Forissier 	switch (PC) {
88*f9a78287SJerome Forissier 	case 0x02:
89*f9a78287SJerome Forissier 	case 0x03:
90*f9a78287SJerome Forissier 		/* Compressed form */
91*f9a78287SJerome Forissier 		return TEE_ERROR_NOT_SUPPORTED;
92*f9a78287SJerome Forissier 	case 0x04:
93*f9a78287SJerome Forissier 		/* UNcompressed form */
94*f9a78287SJerome Forissier 		return sm2_uncompressed_bytes_to_point(p, dp, buf + 1,
95*f9a78287SJerome Forissier 						       max_size - 1, consumed);
96*f9a78287SJerome Forissier 	case 0x06:
97*f9a78287SJerome Forissier 	case 0x07:
98*f9a78287SJerome Forissier 		/* Hybrid form */
99*f9a78287SJerome Forissier 		return TEE_ERROR_NOT_SUPPORTED;
100*f9a78287SJerome Forissier 	default:
101*f9a78287SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
102*f9a78287SJerome Forissier 	}
103*f9a78287SJerome Forissier 
104*f9a78287SJerome Forissier 	return TEE_ERROR_GENERIC;
105*f9a78287SJerome Forissier }
106*f9a78287SJerome Forissier 
107*f9a78287SJerome Forissier /*
108*f9a78287SJerome Forissier  * GM/T 0003.1‒2012 Part 4 Sections 5.4.2 and 5.4.3
109*f9a78287SJerome Forissier  * Key derivation function based on the SM3 hash function
110*f9a78287SJerome Forissier  */
111*f9a78287SJerome Forissier static TEE_Result sm2_kdf(const uint8_t *Z, size_t Z_len, uint8_t *t,
112*f9a78287SJerome Forissier 			  size_t tlen)
113*f9a78287SJerome Forissier {
114*f9a78287SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
115*f9a78287SJerome Forissier 	size_t remain = tlen;
116*f9a78287SJerome Forissier 	uint32_t count = 1;
117*f9a78287SJerome Forissier 	uint32_t be_count = 0;
118*f9a78287SJerome Forissier 	void *ctx = NULL;
119*f9a78287SJerome Forissier 	uint8_t *out = t;
120*f9a78287SJerome Forissier 
121*f9a78287SJerome Forissier 	res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3);
122*f9a78287SJerome Forissier 	if (res)
123*f9a78287SJerome Forissier 		return res;
124*f9a78287SJerome Forissier 
125*f9a78287SJerome Forissier 	while (remain) {
126*f9a78287SJerome Forissier 		uint8_t tmp[TEE_SM3_HASH_SIZE] = { };
127*f9a78287SJerome Forissier 		uint8_t *buf = NULL;
128*f9a78287SJerome Forissier 
129*f9a78287SJerome Forissier 		if (remain >= TEE_SM3_HASH_SIZE)
130*f9a78287SJerome Forissier 			buf = out;
131*f9a78287SJerome Forissier 		else
132*f9a78287SJerome Forissier 			buf = tmp;
133*f9a78287SJerome Forissier 
134*f9a78287SJerome Forissier 		put_be32(&be_count, count);
135*f9a78287SJerome Forissier 		res = crypto_hash_init(ctx);
136*f9a78287SJerome Forissier 		if (res)
137*f9a78287SJerome Forissier 			goto out;
138*f9a78287SJerome Forissier 		res = crypto_hash_update(ctx, Z, Z_len);
139*f9a78287SJerome Forissier 		if (res)
140*f9a78287SJerome Forissier 			goto out;
141*f9a78287SJerome Forissier 		res = crypto_hash_update(ctx, (const uint8_t *)&be_count,
142*f9a78287SJerome Forissier 					 sizeof(be_count));
143*f9a78287SJerome Forissier 		if (res)
144*f9a78287SJerome Forissier 			goto out;
145*f9a78287SJerome Forissier 		res = crypto_hash_final(ctx, buf, TEE_SM3_HASH_SIZE);
146*f9a78287SJerome Forissier 		if (res)
147*f9a78287SJerome Forissier 			goto out;
148*f9a78287SJerome Forissier 
149*f9a78287SJerome Forissier 		if (remain < TEE_SM3_HASH_SIZE) {
150*f9a78287SJerome Forissier 			memcpy(out, tmp, remain);
151*f9a78287SJerome Forissier 			break;
152*f9a78287SJerome Forissier 		}
153*f9a78287SJerome Forissier 
154*f9a78287SJerome Forissier 		out += TEE_SM3_HASH_SIZE;
155*f9a78287SJerome Forissier 		remain -= TEE_SM3_HASH_SIZE;
156*f9a78287SJerome Forissier 		count++;
157*f9a78287SJerome Forissier 	}
158*f9a78287SJerome Forissier out:
159*f9a78287SJerome Forissier 	crypto_hash_free_ctx(ctx);
160*f9a78287SJerome Forissier 	return res;
161*f9a78287SJerome Forissier }
162*f9a78287SJerome Forissier 
163*f9a78287SJerome Forissier static bool is_zero(const uint8_t *buf, size_t size)
164*f9a78287SJerome Forissier {
165*f9a78287SJerome Forissier 	uint8_t v = 0;
166*f9a78287SJerome Forissier 	size_t i = 0;
167*f9a78287SJerome Forissier 
168*f9a78287SJerome Forissier 	for (i = 0; i < size; i++)
169*f9a78287SJerome Forissier 		v |= buf[i];
170*f9a78287SJerome Forissier 
171*f9a78287SJerome Forissier 	return !v;
172*f9a78287SJerome Forissier }
173*f9a78287SJerome Forissier 
174*f9a78287SJerome Forissier /*
175*f9a78287SJerome Forissier  * GM/T 0003.1‒2012 Part 4 Section 7.1
176*f9a78287SJerome Forissier  * Decryption algorithm
177*f9a78287SJerome Forissier  */
178*f9a78287SJerome Forissier TEE_Result crypto_acipher_sm2_pke_decrypt(struct ecc_keypair *key,
179*f9a78287SJerome Forissier 					  const uint8_t *src, size_t src_len,
180*f9a78287SJerome Forissier 					  uint8_t *dst, size_t *dst_len)
181*f9a78287SJerome Forissier {
182*f9a78287SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
183*f9a78287SJerome Forissier 	uint8_t x2y2[64] = { };
184*f9a78287SJerome Forissier 	ecc_key ltc_key = { };
185*f9a78287SJerome Forissier 	ecc_point *C1 = NULL;
186*f9a78287SJerome Forissier 	size_t C1_len = 0;
187*f9a78287SJerome Forissier 	ecc_point *S = NULL;
188*f9a78287SJerome Forissier 	ecc_point *x2y2p = NULL;
189*f9a78287SJerome Forissier 	void *ctx = NULL;
190*f9a78287SJerome Forissier 	int ltc_res = 0;
191*f9a78287SJerome Forissier 	void *h = NULL;
192*f9a78287SJerome Forissier 	int inf = 0;
193*f9a78287SJerome Forissier 	uint8_t *t = NULL;
194*f9a78287SJerome Forissier 	size_t C2_len = 0;
195*f9a78287SJerome Forissier 	size_t i = 0;
196*f9a78287SJerome Forissier 	size_t out_len = 0;
197*f9a78287SJerome Forissier 	uint8_t *eom = NULL;
198*f9a78287SJerome Forissier 	uint8_t u[TEE_SM3_HASH_SIZE] = { };
199*f9a78287SJerome Forissier 
200*f9a78287SJerome Forissier 	/*
201*f9a78287SJerome Forissier 	 * Input buffer src is (C1 || C2 || C3)
202*f9a78287SJerome Forissier 	 * - C1 represents a point (should be on the curve)
203*f9a78287SJerome Forissier 	 * - C2 is the encrypted message
204*f9a78287SJerome Forissier 	 * - C3 is a SM3 hash
205*f9a78287SJerome Forissier 	 */
206*f9a78287SJerome Forissier 
207*f9a78287SJerome Forissier 	res = ecc_populate_ltc_private_key(&ltc_key, key, TEE_ALG_SM2_PKE,
208*f9a78287SJerome Forissier 					   NULL);
209*f9a78287SJerome Forissier 	if (res)
210*f9a78287SJerome Forissier 		goto out;
211*f9a78287SJerome Forissier 
212*f9a78287SJerome Forissier 	/* Step B1: read and validate point C1 from encrypted message */
213*f9a78287SJerome Forissier 
214*f9a78287SJerome Forissier 	C1 = ltc_ecc_new_point();
215*f9a78287SJerome Forissier 	if (!C1) {
216*f9a78287SJerome Forissier 		res = TEE_ERROR_OUT_OF_MEMORY;
217*f9a78287SJerome Forissier 		goto out;
218*f9a78287SJerome Forissier 	}
219*f9a78287SJerome Forissier 
220*f9a78287SJerome Forissier 	res = sm2_bytes_to_point(C1, &ltc_key.dp, src, src_len, &C1_len);
221*f9a78287SJerome Forissier 	if (res)
222*f9a78287SJerome Forissier 		goto out;
223*f9a78287SJerome Forissier 
224*f9a78287SJerome Forissier 	/* Step B2: S = [h]C1 */
225*f9a78287SJerome Forissier 
226*f9a78287SJerome Forissier 	if (ltc_key.dp.cofactor != 1) {
227*f9a78287SJerome Forissier 		S = ltc_ecc_new_point();
228*f9a78287SJerome Forissier 		if (!S) {
229*f9a78287SJerome Forissier 			res = TEE_ERROR_OUT_OF_MEMORY;
230*f9a78287SJerome Forissier 			goto out;
231*f9a78287SJerome Forissier 		}
232*f9a78287SJerome Forissier 
233*f9a78287SJerome Forissier 		ltc_res = mp_init_multi(&h, NULL);
234*f9a78287SJerome Forissier 		if (ltc_res != CRYPT_OK)
235*f9a78287SJerome Forissier 			return TEE_ERROR_OUT_OF_MEMORY;
236*f9a78287SJerome Forissier 
237*f9a78287SJerome Forissier 		ltc_res = mp_set_int(h, ltc_key.dp.cofactor);
238*f9a78287SJerome Forissier 		if (ltc_res != CRYPT_OK) {
239*f9a78287SJerome Forissier 			res = TEE_ERROR_BAD_STATE;
240*f9a78287SJerome Forissier 			goto out;
241*f9a78287SJerome Forissier 		}
242*f9a78287SJerome Forissier 
243*f9a78287SJerome Forissier 		ltc_res = ltc_ecc_mulmod(h, C1, S, ltc_key.dp.A,
244*f9a78287SJerome Forissier 					 ltc_key.dp.prime, 1);
245*f9a78287SJerome Forissier 		if (ltc_res != CRYPT_OK) {
246*f9a78287SJerome Forissier 			res = TEE_ERROR_BAD_STATE;
247*f9a78287SJerome Forissier 			goto out;
248*f9a78287SJerome Forissier 		}
249*f9a78287SJerome Forissier 
250*f9a78287SJerome Forissier 		ltc_res = ltc_ecc_is_point_at_infinity(S, ltc_key.dp.prime,
251*f9a78287SJerome Forissier 						       &inf);
252*f9a78287SJerome Forissier 	} else {
253*f9a78287SJerome Forissier 		ltc_res = ltc_ecc_is_point_at_infinity(C1, ltc_key.dp.prime,
254*f9a78287SJerome Forissier 						       &inf);
255*f9a78287SJerome Forissier 	}
256*f9a78287SJerome Forissier 	if (inf) {
257*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_STATE;
258*f9a78287SJerome Forissier 		goto out;
259*f9a78287SJerome Forissier 	}
260*f9a78287SJerome Forissier 
261*f9a78287SJerome Forissier 	/* Step B3: (x2, y2) = [dB]C1 */
262*f9a78287SJerome Forissier 
263*f9a78287SJerome Forissier 	x2y2p = ltc_ecc_new_point();
264*f9a78287SJerome Forissier 	if (!x2y2p) {
265*f9a78287SJerome Forissier 		res = TEE_ERROR_OUT_OF_MEMORY;
266*f9a78287SJerome Forissier 		goto out;
267*f9a78287SJerome Forissier 	}
268*f9a78287SJerome Forissier 
269*f9a78287SJerome Forissier 	ltc_res = ltc_ecc_mulmod(ltc_key.k, C1, x2y2p, ltc_key.dp.A,
270*f9a78287SJerome Forissier 				 ltc_key.dp.prime, 1);
271*f9a78287SJerome Forissier 	if (ltc_res != CRYPT_OK) {
272*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_STATE;
273*f9a78287SJerome Forissier 		goto out;
274*f9a78287SJerome Forissier 	}
275*f9a78287SJerome Forissier 
276*f9a78287SJerome Forissier 	if (mp_unsigned_bin_size(x2y2p->x) != 32 ||
277*f9a78287SJerome Forissier 	    mp_unsigned_bin_size(x2y2p->y) != 32) {
278*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_STATE;
279*f9a78287SJerome Forissier 		goto out;
280*f9a78287SJerome Forissier 	}
281*f9a78287SJerome Forissier 
282*f9a78287SJerome Forissier 	mp_to_unsigned_bin(x2y2p->x, x2y2);
283*f9a78287SJerome Forissier 	mp_to_unsigned_bin(x2y2p->y, x2y2 + 32);
284*f9a78287SJerome Forissier 
285*f9a78287SJerome Forissier 	/* Step B4: t = KDF(x2 || y2, klen) */
286*f9a78287SJerome Forissier 
287*f9a78287SJerome Forissier 	/* C = C1 || C2 || C3 */
288*f9a78287SJerome Forissier 	if (src_len <= C1_len + TEE_SM3_HASH_SIZE) {
289*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_PARAMETERS;
290*f9a78287SJerome Forissier 		goto out;
291*f9a78287SJerome Forissier 	}
292*f9a78287SJerome Forissier 
293*f9a78287SJerome Forissier 	C2_len = src_len - C1_len - TEE_SM3_HASH_SIZE;
294*f9a78287SJerome Forissier 
295*f9a78287SJerome Forissier 	t = calloc(1, C2_len);
296*f9a78287SJerome Forissier 	if (!t) {
297*f9a78287SJerome Forissier 		res = TEE_ERROR_OUT_OF_MEMORY;
298*f9a78287SJerome Forissier 		goto out;
299*f9a78287SJerome Forissier 	}
300*f9a78287SJerome Forissier 
301*f9a78287SJerome Forissier 	res = sm2_kdf(x2y2, sizeof(x2y2), t, C2_len);
302*f9a78287SJerome Forissier 	if (res)
303*f9a78287SJerome Forissier 		goto out;
304*f9a78287SJerome Forissier 
305*f9a78287SJerome Forissier 	if (is_zero(t, C2_len)) {
306*f9a78287SJerome Forissier 		res = TEE_ERROR_CIPHERTEXT_INVALID;
307*f9a78287SJerome Forissier 		goto out;
308*f9a78287SJerome Forissier 	}
309*f9a78287SJerome Forissier 
310*f9a78287SJerome Forissier 	/* Step B5: get C2 from C and compute Mprime = C2 (+) t */
311*f9a78287SJerome Forissier 
312*f9a78287SJerome Forissier 	out_len = MIN(*dst_len, C2_len);
313*f9a78287SJerome Forissier 	for (i = 0; i < out_len; i++)
314*f9a78287SJerome Forissier 		dst[i] = src[C1_len + i] ^ t[i];
315*f9a78287SJerome Forissier 	*dst_len = out_len;
316*f9a78287SJerome Forissier 	if (out_len < C2_len) {
317*f9a78287SJerome Forissier 		eom = calloc(1, C2_len - out_len);
318*f9a78287SJerome Forissier 		if (!eom)
319*f9a78287SJerome Forissier 			goto out;
320*f9a78287SJerome Forissier 		for (i = out_len; i < C2_len; i++)
321*f9a78287SJerome Forissier 		       eom[i - out_len] = src[C1_len + i] ^ t[i];
322*f9a78287SJerome Forissier 	}
323*f9a78287SJerome Forissier 
324*f9a78287SJerome Forissier 	/* Step B6: compute u = Hash(x2 || M' || y2) and compare with C3 */
325*f9a78287SJerome Forissier 
326*f9a78287SJerome Forissier 	res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3);
327*f9a78287SJerome Forissier 	if (res)
328*f9a78287SJerome Forissier 		goto out;
329*f9a78287SJerome Forissier 	res = crypto_hash_init(ctx);
330*f9a78287SJerome Forissier 	if (res)
331*f9a78287SJerome Forissier 		goto out;
332*f9a78287SJerome Forissier 	res = crypto_hash_update(ctx, x2y2, 32);
333*f9a78287SJerome Forissier 	if (res)
334*f9a78287SJerome Forissier 		goto out;
335*f9a78287SJerome Forissier 	res = crypto_hash_update(ctx, dst, out_len);
336*f9a78287SJerome Forissier 	if (res)
337*f9a78287SJerome Forissier 		goto out;
338*f9a78287SJerome Forissier 	if (out_len < C2_len) {
339*f9a78287SJerome Forissier 		res = crypto_hash_update(ctx, eom, C2_len - out_len);
340*f9a78287SJerome Forissier 		if (res)
341*f9a78287SJerome Forissier 			goto out;
342*f9a78287SJerome Forissier 	}
343*f9a78287SJerome Forissier 	res = crypto_hash_update(ctx, x2y2 + 32, 32);
344*f9a78287SJerome Forissier 	if (res)
345*f9a78287SJerome Forissier 		goto out;
346*f9a78287SJerome Forissier 	res = crypto_hash_final(ctx, u, sizeof(u));
347*f9a78287SJerome Forissier 	if (res)
348*f9a78287SJerome Forissier 		goto out;
349*f9a78287SJerome Forissier 
350*f9a78287SJerome Forissier 	if (consttime_memcmp(u, src + C1_len + C2_len, TEE_SM3_HASH_SIZE)) {
351*f9a78287SJerome Forissier 		res = TEE_ERROR_CIPHERTEXT_INVALID;
352*f9a78287SJerome Forissier 		goto out;
353*f9a78287SJerome Forissier 	}
354*f9a78287SJerome Forissier out:
355*f9a78287SJerome Forissier 	free(eom);
356*f9a78287SJerome Forissier 	free(t);
357*f9a78287SJerome Forissier 	crypto_hash_free_ctx(ctx);
358*f9a78287SJerome Forissier 	ltc_ecc_del_point(x2y2p);
359*f9a78287SJerome Forissier 	ltc_ecc_del_point(S);
360*f9a78287SJerome Forissier 	ltc_ecc_del_point(C1);
361*f9a78287SJerome Forissier 	mp_clear_multi(h, NULL);
362*f9a78287SJerome Forissier 	return res;
363*f9a78287SJerome Forissier }
364*f9a78287SJerome Forissier 
365*f9a78287SJerome Forissier /*
366*f9a78287SJerome Forissier  * GM/T 0003.1‒2012 Part 1 Section 4.2.8
367*f9a78287SJerome Forissier  * Conversion of point @p to a byte string @buf (uncompressed form).
368*f9a78287SJerome Forissier  */
369*f9a78287SJerome Forissier static TEE_Result sm2_point_to_bytes(uint8_t *buf, size_t *size,
370*f9a78287SJerome Forissier 				     const ecc_point *p)
371*f9a78287SJerome Forissier {
372*f9a78287SJerome Forissier 	size_t xsize = mp_unsigned_bin_size(p->x);
373*f9a78287SJerome Forissier 	size_t ysize = mp_unsigned_bin_size(p->y);
374*f9a78287SJerome Forissier 
375*f9a78287SJerome Forissier 	if (*size < xsize + ysize + 1)
376*f9a78287SJerome Forissier 		return TEE_ERROR_BAD_STATE;
377*f9a78287SJerome Forissier 
378*f9a78287SJerome Forissier 	buf[0] = 0x04;  /* Uncompressed form indicator */
379*f9a78287SJerome Forissier 	mp_to_unsigned_bin(p->x, buf + 1);
380*f9a78287SJerome Forissier 	mp_to_unsigned_bin(p->y, buf + 1 + xsize);
381*f9a78287SJerome Forissier 
382*f9a78287SJerome Forissier 	*size = xsize + ysize + 1;
383*f9a78287SJerome Forissier 
384*f9a78287SJerome Forissier 	return TEE_SUCCESS;
385*f9a78287SJerome Forissier }
386*f9a78287SJerome Forissier 
387*f9a78287SJerome Forissier /*
388*f9a78287SJerome Forissier  * GM/T 0003.1‒2012 Part 4 Section 6.1
389*f9a78287SJerome Forissier  * Encryption algorithm
390*f9a78287SJerome Forissier  */
391*f9a78287SJerome Forissier TEE_Result crypto_acipher_sm2_pke_encrypt(struct ecc_public_key *key,
392*f9a78287SJerome Forissier 					  const uint8_t *src, size_t src_len,
393*f9a78287SJerome Forissier 					  uint8_t *dst, size_t *dst_len)
394*f9a78287SJerome Forissier {
395*f9a78287SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
396*f9a78287SJerome Forissier 	ecc_key ltc_key = { };
397*f9a78287SJerome Forissier 	ecc_point *x2y2p = NULL;
398*f9a78287SJerome Forissier 	ecc_point *C1 = NULL;
399*f9a78287SJerome Forissier 	ecc_point *S = NULL;
400*f9a78287SJerome Forissier 	uint8_t x2y2[64] = { };
401*f9a78287SJerome Forissier 	uint8_t *t = NULL;
402*f9a78287SJerome Forissier 	int ltc_res = 0;
403*f9a78287SJerome Forissier 	void *k = NULL;
404*f9a78287SJerome Forissier 	void *h = NULL;
405*f9a78287SJerome Forissier 	int inf = 0;
406*f9a78287SJerome Forissier 	size_t C1_len = 0;
407*f9a78287SJerome Forissier 	void *ctx = NULL;
408*f9a78287SJerome Forissier 	size_t i = 0;
409*f9a78287SJerome Forissier 
410*f9a78287SJerome Forissier 	ltc_res = mp_init_multi(&k, &h, NULL);
411*f9a78287SJerome Forissier 	if (ltc_res != CRYPT_OK)
412*f9a78287SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
413*f9a78287SJerome Forissier 
414*f9a78287SJerome Forissier 	res = ecc_populate_ltc_public_key(&ltc_key, key, TEE_ALG_SM2_PKE, NULL);
415*f9a78287SJerome Forissier 	if (res)
416*f9a78287SJerome Forissier 		goto out;
417*f9a78287SJerome Forissier 
418*f9a78287SJerome Forissier 	/* Step A1: generate random number 1 <= k < n */
419*f9a78287SJerome Forissier 
420*f9a78287SJerome Forissier 	ltc_res = rand_bn_upto(k, ltc_key.dp.order, NULL,
421*f9a78287SJerome Forissier 			       find_prng("prng_crypto"));
422*f9a78287SJerome Forissier 	if (ltc_res != CRYPT_OK) {
423*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_STATE;
424*f9a78287SJerome Forissier 		goto out;
425*f9a78287SJerome Forissier 	}
426*f9a78287SJerome Forissier 
427*f9a78287SJerome Forissier 	/* Step A2: compute C1 = [k]G */
428*f9a78287SJerome Forissier 
429*f9a78287SJerome Forissier 	C1 = ltc_ecc_new_point();
430*f9a78287SJerome Forissier 	if (!C1) {
431*f9a78287SJerome Forissier 		res = TEE_ERROR_OUT_OF_MEMORY;
432*f9a78287SJerome Forissier 		goto out;
433*f9a78287SJerome Forissier 	}
434*f9a78287SJerome Forissier 
435*f9a78287SJerome Forissier 	ltc_res = ltc_ecc_mulmod(k, &ltc_key.dp.base, C1, ltc_key.dp.A,
436*f9a78287SJerome Forissier 				 ltc_key.dp.prime, 1);
437*f9a78287SJerome Forissier 	if (ltc_res != CRYPT_OK) {
438*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_STATE;
439*f9a78287SJerome Forissier 		goto out;
440*f9a78287SJerome Forissier 	}
441*f9a78287SJerome Forissier 
442*f9a78287SJerome Forissier 	/* Step A3: compute S = [h]PB and check for infinity */
443*f9a78287SJerome Forissier 
444*f9a78287SJerome Forissier 	if (ltc_key.dp.cofactor != 1) {
445*f9a78287SJerome Forissier 		S = ltc_ecc_new_point();
446*f9a78287SJerome Forissier 		if (!S) {
447*f9a78287SJerome Forissier 			res = TEE_ERROR_OUT_OF_MEMORY;
448*f9a78287SJerome Forissier 			goto out;
449*f9a78287SJerome Forissier 		}
450*f9a78287SJerome Forissier 
451*f9a78287SJerome Forissier 		ltc_res = mp_set_int(h, ltc_key.dp.cofactor);
452*f9a78287SJerome Forissier 		if (ltc_res != CRYPT_OK) {
453*f9a78287SJerome Forissier 			res = TEE_ERROR_BAD_STATE;
454*f9a78287SJerome Forissier 			goto out;
455*f9a78287SJerome Forissier 		}
456*f9a78287SJerome Forissier 
457*f9a78287SJerome Forissier 		ltc_res = ltc_ecc_mulmod(h, &ltc_key.pubkey, S, ltc_key.dp.A,
458*f9a78287SJerome Forissier 					 ltc_key.dp.prime, 1);
459*f9a78287SJerome Forissier 		if (ltc_res != CRYPT_OK) {
460*f9a78287SJerome Forissier 			res = TEE_ERROR_BAD_STATE;
461*f9a78287SJerome Forissier 			goto out;
462*f9a78287SJerome Forissier 		}
463*f9a78287SJerome Forissier 
464*f9a78287SJerome Forissier 		ltc_res = ltc_ecc_is_point_at_infinity(S, ltc_key.dp.prime,
465*f9a78287SJerome Forissier 						       &inf);
466*f9a78287SJerome Forissier 	} else {
467*f9a78287SJerome Forissier 		ltc_res = ltc_ecc_is_point_at_infinity(&ltc_key.pubkey,
468*f9a78287SJerome Forissier 						       ltc_key.dp.prime, &inf);
469*f9a78287SJerome Forissier 	}
470*f9a78287SJerome Forissier 	if (inf) {
471*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_STATE;
472*f9a78287SJerome Forissier 		goto out;
473*f9a78287SJerome Forissier 	}
474*f9a78287SJerome Forissier 
475*f9a78287SJerome Forissier 	/* Step A4: compute (x2, y2) = [k]PB */
476*f9a78287SJerome Forissier 
477*f9a78287SJerome Forissier 	x2y2p = ltc_ecc_new_point();
478*f9a78287SJerome Forissier 	if (!x2y2p) {
479*f9a78287SJerome Forissier 		res = TEE_ERROR_OUT_OF_MEMORY;
480*f9a78287SJerome Forissier 		goto out;
481*f9a78287SJerome Forissier 	}
482*f9a78287SJerome Forissier 
483*f9a78287SJerome Forissier 	ltc_res = ltc_ecc_mulmod(k, &ltc_key.pubkey, x2y2p, ltc_key.dp.A,
484*f9a78287SJerome Forissier 				 ltc_key.dp.prime, 1);
485*f9a78287SJerome Forissier 	if (ltc_res != CRYPT_OK) {
486*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_STATE;
487*f9a78287SJerome Forissier 		goto out;
488*f9a78287SJerome Forissier 	}
489*f9a78287SJerome Forissier 
490*f9a78287SJerome Forissier 	if (mp_unsigned_bin_size(x2y2p->x) != 32 ||
491*f9a78287SJerome Forissier 	    mp_unsigned_bin_size(x2y2p->y) != 32) {
492*f9a78287SJerome Forissier 		res = TEE_ERROR_BAD_STATE;
493*f9a78287SJerome Forissier 		goto out;
494*f9a78287SJerome Forissier 	}
495*f9a78287SJerome Forissier 
496*f9a78287SJerome Forissier 	mp_to_unsigned_bin(x2y2p->x, x2y2);
497*f9a78287SJerome Forissier 	mp_to_unsigned_bin(x2y2p->y, x2y2 + 32);
498*f9a78287SJerome Forissier 
499*f9a78287SJerome Forissier 	/* Step A5: compute t = KDF(x2 || y2, klen) */
500*f9a78287SJerome Forissier 
501*f9a78287SJerome Forissier 	t = calloc(1, src_len);
502*f9a78287SJerome Forissier 	if (!t) {
503*f9a78287SJerome Forissier 		res = TEE_ERROR_OUT_OF_MEMORY;
504*f9a78287SJerome Forissier 		goto out;
505*f9a78287SJerome Forissier 	}
506*f9a78287SJerome Forissier 
507*f9a78287SJerome Forissier 	res = sm2_kdf(x2y2, sizeof(x2y2), t, src_len);
508*f9a78287SJerome Forissier 	if (res)
509*f9a78287SJerome Forissier 		goto out;
510*f9a78287SJerome Forissier 
511*f9a78287SJerome Forissier 	if (is_zero(t, src_len)) {
512*f9a78287SJerome Forissier 		res = TEE_ERROR_CIPHERTEXT_INVALID;
513*f9a78287SJerome Forissier 		goto out;
514*f9a78287SJerome Forissier 	}
515*f9a78287SJerome Forissier 
516*f9a78287SJerome Forissier 	/*
517*f9a78287SJerome Forissier 	 * Steps A6, A7, A8:
518*f9a78287SJerome Forissier 	 * Compute C2 = M (+) t
519*f9a78287SJerome Forissier 	 * Compute C3 = Hash(x2 || M || y2)
520*f9a78287SJerome Forissier 	 * Output C = C1 || C2 || C3
521*f9a78287SJerome Forissier 	 */
522*f9a78287SJerome Forissier 
523*f9a78287SJerome Forissier 	/* C1 */
524*f9a78287SJerome Forissier 	C1_len = *dst_len;
525*f9a78287SJerome Forissier 	res = sm2_point_to_bytes(dst, &C1_len, C1);
526*f9a78287SJerome Forissier 	if (res)
527*f9a78287SJerome Forissier 		goto out;
528*f9a78287SJerome Forissier 
529*f9a78287SJerome Forissier 	if (*dst_len < C1_len + src_len + TEE_SM3_HASH_SIZE) {
530*f9a78287SJerome Forissier 		*dst_len = C1_len + src_len + TEE_SM3_HASH_SIZE;
531*f9a78287SJerome Forissier 		res = TEE_ERROR_SHORT_BUFFER;
532*f9a78287SJerome Forissier 		goto out;
533*f9a78287SJerome Forissier 	}
534*f9a78287SJerome Forissier 
535*f9a78287SJerome Forissier 	/* C2 */
536*f9a78287SJerome Forissier 	for (i = 0; i < src_len; i++)
537*f9a78287SJerome Forissier 		dst[i + C1_len] = src[i] ^ t[i];
538*f9a78287SJerome Forissier 
539*f9a78287SJerome Forissier 	/* C3 */
540*f9a78287SJerome Forissier         res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3);
541*f9a78287SJerome Forissier         if (res)
542*f9a78287SJerome Forissier                 goto out;
543*f9a78287SJerome Forissier         res = crypto_hash_init(ctx);
544*f9a78287SJerome Forissier         if (res)
545*f9a78287SJerome Forissier                 goto out;
546*f9a78287SJerome Forissier         res = crypto_hash_update(ctx, x2y2, 32);
547*f9a78287SJerome Forissier         if (res)
548*f9a78287SJerome Forissier                 goto out;
549*f9a78287SJerome Forissier         res = crypto_hash_update(ctx, src, src_len);
550*f9a78287SJerome Forissier         if (res)
551*f9a78287SJerome Forissier                 goto out;
552*f9a78287SJerome Forissier         res = crypto_hash_update(ctx, x2y2 + 32, 32);
553*f9a78287SJerome Forissier         if (res)
554*f9a78287SJerome Forissier                 goto out;
555*f9a78287SJerome Forissier         res = crypto_hash_final(ctx, dst + C1_len + src_len, TEE_SM3_HASH_SIZE);
556*f9a78287SJerome Forissier         if (res)
557*f9a78287SJerome Forissier                 goto out;
558*f9a78287SJerome Forissier 
559*f9a78287SJerome Forissier 	*dst_len = C1_len + src_len + TEE_SM3_HASH_SIZE;
560*f9a78287SJerome Forissier out:
561*f9a78287SJerome Forissier 	crypto_hash_free_ctx(ctx);
562*f9a78287SJerome Forissier 	free(t);
563*f9a78287SJerome Forissier 	ltc_ecc_del_point(x2y2p);
564*f9a78287SJerome Forissier 	ltc_ecc_del_point(S);
565*f9a78287SJerome Forissier 	ltc_ecc_del_point(C1);
566*f9a78287SJerome Forissier 	mp_clear_multi(k, h, NULL);
567*f9a78287SJerome Forissier 	return res;
568*f9a78287SJerome Forissier }
569