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