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