1 /* $OpenBSD: sm2_crypt.c,v 1.3 2024/02/09 07:43:52 tb Exp $ */
2 /*
3 * Copyright (c) 2017, 2019 Ribose Inc
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #ifndef OPENSSL_NO_SM2
19
20 #include <string.h>
21
22 #include <openssl/asn1.h>
23 #include <openssl/asn1t.h>
24 #include <openssl/bn.h>
25 #include <openssl/err.h>
26 #include <openssl/evp.h>
27 #include <openssl/sm2.h>
28
29 #include "sm2_local.h"
30
31 typedef struct SM2_Ciphertext_st SM2_Ciphertext;
32
33 SM2_Ciphertext *SM2_Ciphertext_new(void);
34 void SM2_Ciphertext_free(SM2_Ciphertext *a);
35 SM2_Ciphertext *d2i_SM2_Ciphertext(SM2_Ciphertext **a, const unsigned char **in,
36 long len);
37 int i2d_SM2_Ciphertext(SM2_Ciphertext *a, unsigned char **out);
38
39 struct SM2_Ciphertext_st {
40 BIGNUM *C1x;
41 BIGNUM *C1y;
42 ASN1_OCTET_STRING *C3;
43 ASN1_OCTET_STRING *C2;
44 };
45
46 static const ASN1_TEMPLATE SM2_Ciphertext_seq_tt[] = {
47 {
48 .flags = 0,
49 .tag = 0,
50 .offset = offsetof(SM2_Ciphertext, C1x),
51 .field_name = "C1x",
52 .item = &BIGNUM_it,
53 },
54 {
55 .flags = 0,
56 .tag = 0,
57 .offset = offsetof(SM2_Ciphertext, C1y),
58 .field_name = "C1y",
59 .item = &BIGNUM_it,
60 },
61 {
62 .flags = 0,
63 .tag = 0,
64 .offset = offsetof(SM2_Ciphertext, C3),
65 .field_name = "C3",
66 .item = &ASN1_OCTET_STRING_it,
67 },
68 {
69 .flags = 0,
70 .tag = 0,
71 .offset = offsetof(SM2_Ciphertext, C2),
72 .field_name = "C2",
73 .item = &ASN1_OCTET_STRING_it,
74 },
75 };
76
77 const ASN1_ITEM SM2_Ciphertext_it = {
78 .itype = ASN1_ITYPE_SEQUENCE,
79 .utype = V_ASN1_SEQUENCE,
80 .templates = SM2_Ciphertext_seq_tt,
81 .tcount = sizeof(SM2_Ciphertext_seq_tt) / sizeof(ASN1_TEMPLATE),
82 .funcs = NULL,
83 .size = sizeof(SM2_Ciphertext),
84 .sname = "SM2_Ciphertext",
85 };
86
87 SM2_Ciphertext *
d2i_SM2_Ciphertext(SM2_Ciphertext ** a,const unsigned char ** in,long len)88 d2i_SM2_Ciphertext(SM2_Ciphertext **a, const unsigned char **in, long len)
89 {
90 return (SM2_Ciphertext *) ASN1_item_d2i((ASN1_VALUE **)a, in, len,
91 &SM2_Ciphertext_it);
92 }
93
94 int
i2d_SM2_Ciphertext(SM2_Ciphertext * a,unsigned char ** out)95 i2d_SM2_Ciphertext(SM2_Ciphertext *a, unsigned char **out)
96 {
97 return ASN1_item_i2d((ASN1_VALUE *)a, out, &SM2_Ciphertext_it);
98 }
99
100 SM2_Ciphertext *
SM2_Ciphertext_new(void)101 SM2_Ciphertext_new(void)
102 {
103 return (SM2_Ciphertext *)ASN1_item_new(&SM2_Ciphertext_it);
104 }
105
106 void
SM2_Ciphertext_free(SM2_Ciphertext * a)107 SM2_Ciphertext_free(SM2_Ciphertext *a)
108 {
109 ASN1_item_free((ASN1_VALUE *)a, &SM2_Ciphertext_it);
110 }
111
112 static size_t
ec_field_size(const EC_GROUP * group)113 ec_field_size(const EC_GROUP *group)
114 {
115 /* Is there some simpler way to do this? */
116 BIGNUM *p;
117 size_t field_size = 0;
118
119 if ((p = BN_new()) == NULL)
120 goto err;
121 if (!EC_GROUP_get_curve(group, p, NULL, NULL, NULL))
122 goto err;
123 field_size = BN_num_bytes(p);
124 err:
125 BN_free(p);
126 return field_size;
127 }
128
129 int
SM2_plaintext_size(const EC_KEY * key,const EVP_MD * digest,size_t msg_len,size_t * pl_size)130 SM2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
131 size_t *pl_size)
132 {
133 size_t field_size, overhead;
134 int md_size;
135
136 if ((field_size = ec_field_size(EC_KEY_get0_group(key))) == 0) {
137 SM2error(SM2_R_INVALID_FIELD);
138 return 0;
139 }
140
141 if ((md_size = EVP_MD_size(digest)) < 0) {
142 SM2error(SM2_R_INVALID_DIGEST);
143 return 0;
144 }
145
146 overhead = 10 + 2 * field_size + md_size;
147 if (msg_len <= overhead) {
148 SM2error(SM2_R_INVALID_ARGUMENT);
149 return 0;
150 }
151
152 *pl_size = msg_len - overhead;
153 return 1;
154 }
155
156 int
SM2_ciphertext_size(const EC_KEY * key,const EVP_MD * digest,size_t msg_len,size_t * c_size)157 SM2_ciphertext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
158 size_t *c_size)
159 {
160 size_t asn_size, field_size;
161 int md_size;
162
163 if ((field_size = ec_field_size(EC_KEY_get0_group(key))) == 0) {
164 SM2error(SM2_R_INVALID_FIELD);
165 return 0;
166 }
167
168 if ((md_size = EVP_MD_size(digest)) < 0) {
169 SM2error(SM2_R_INVALID_DIGEST);
170 return 0;
171 }
172
173 asn_size = 2 * ASN1_object_size(0, field_size + 1, V_ASN1_INTEGER) +
174 ASN1_object_size(0, md_size, V_ASN1_OCTET_STRING) +
175 ASN1_object_size(0, msg_len, V_ASN1_OCTET_STRING);
176
177 *c_size = ASN1_object_size(1, asn_size, V_ASN1_SEQUENCE);
178 return 1;
179 }
180
181 int
sm2_kdf(uint8_t * key,size_t key_len,uint8_t * secret,size_t secret_len,const EVP_MD * digest)182 sm2_kdf(uint8_t *key, size_t key_len, uint8_t *secret, size_t secret_len,
183 const EVP_MD *digest)
184 {
185 EVP_MD_CTX *hash;
186 uint8_t *hash_buf = NULL;
187 uint32_t ctr = 1;
188 uint8_t ctr_buf[4] = {0};
189 size_t hadd, hlen;
190 int rc = 0;
191
192 if ((hash = EVP_MD_CTX_new()) == NULL) {
193 SM2error(ERR_R_MALLOC_FAILURE);
194 goto err;
195 }
196
197 if ((hlen = EVP_MD_size(digest)) < 0) {
198 SM2error(SM2_R_INVALID_DIGEST);
199 goto err;
200 }
201 if ((hash_buf = malloc(hlen)) == NULL) {
202 SM2error(ERR_R_MALLOC_FAILURE);
203 goto err;
204 }
205
206 while ((key_len > 0) && (ctr != 0)) {
207 if (!EVP_DigestInit_ex(hash, digest, NULL)) {
208 SM2error(ERR_R_EVP_LIB);
209 goto err;
210 }
211 if (!EVP_DigestUpdate(hash, secret, secret_len)) {
212 SM2error(ERR_R_EVP_LIB);
213 goto err;
214 }
215
216 /* big-endian counter representation */
217 ctr_buf[0] = (ctr >> 24) & 0xff;
218 ctr_buf[1] = (ctr >> 16) & 0xff;
219 ctr_buf[2] = (ctr >> 8) & 0xff;
220 ctr_buf[3] = ctr & 0xff;
221 ctr++;
222
223 if (!EVP_DigestUpdate(hash, ctr_buf, 4)) {
224 SM2error(ERR_R_EVP_LIB);
225 goto err;
226 }
227 if (!EVP_DigestFinal(hash, hash_buf, NULL)) {
228 SM2error(ERR_R_EVP_LIB);
229 goto err;
230 }
231
232 hadd = key_len > hlen ? hlen : key_len;
233 memcpy(key, hash_buf, hadd);
234 memset(hash_buf, 0, hlen);
235 key_len -= hadd;
236 key += hadd;
237 }
238
239 rc = 1;
240 err:
241 free(hash_buf);
242 EVP_MD_CTX_free(hash);
243 return rc;
244 }
245
246 int
SM2_encrypt(const EC_KEY * key,const EVP_MD * digest,const uint8_t * msg,size_t msg_len,uint8_t * ciphertext_buf,size_t * ciphertext_len)247 SM2_encrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *msg,
248 size_t msg_len, uint8_t *ciphertext_buf, size_t *ciphertext_len)
249 {
250 SM2_Ciphertext ctext_struct;
251 EVP_MD_CTX *hash = NULL;
252 BN_CTX *ctx = NULL;
253 BIGNUM *order = NULL;
254 BIGNUM *k, *x1, *y1, *x2, *y2;
255 const EC_GROUP *group;
256 const EC_POINT *P;
257 EC_POINT *kG = NULL, *kP = NULL;
258 uint8_t *msg_mask = NULL, *x2y2 = NULL, *C3 = NULL;
259 size_t C3_size, field_size, i, x2size, y2size;
260 int rc = 0;
261 int clen;
262
263 ctext_struct.C2 = NULL;
264 ctext_struct.C3 = NULL;
265
266 if ((hash = EVP_MD_CTX_new()) == NULL) {
267 SM2error(ERR_R_MALLOC_FAILURE);
268 goto err;
269 }
270
271 if ((group = EC_KEY_get0_group(key)) == NULL) {
272 SM2error(SM2_R_INVALID_KEY);
273 goto err;
274 }
275
276 if ((order = BN_new()) == NULL) {
277 SM2error(ERR_R_MALLOC_FAILURE);
278 goto err;
279 }
280
281 if (!EC_GROUP_get_order(group, order, NULL)) {
282 SM2error(SM2_R_INVALID_GROUP_ORDER);
283 goto err;
284 }
285
286 if ((P = EC_KEY_get0_public_key(key)) == NULL) {
287 SM2error(SM2_R_INVALID_KEY);
288 goto err;
289 }
290
291 if ((field_size = ec_field_size(group)) == 0) {
292 SM2error(SM2_R_INVALID_FIELD);
293 goto err;
294 }
295
296 if ((C3_size = EVP_MD_size(digest)) < 0) {
297 SM2error(SM2_R_INVALID_DIGEST);
298 goto err;
299 }
300
301 if ((kG = EC_POINT_new(group)) == NULL) {
302 SM2error(ERR_R_MALLOC_FAILURE);
303 goto err;
304 }
305 if ((kP = EC_POINT_new(group)) == NULL) {
306 SM2error(ERR_R_MALLOC_FAILURE);
307 goto err;
308 }
309
310 if ((ctx = BN_CTX_new()) == NULL) {
311 SM2error(ERR_R_MALLOC_FAILURE);
312 goto err;
313 }
314
315 BN_CTX_start(ctx);
316 if ((k = BN_CTX_get(ctx)) == NULL) {
317 SM2error(ERR_R_BN_LIB);
318 goto err;
319 }
320 if ((x1 = BN_CTX_get(ctx)) == NULL) {
321 SM2error(ERR_R_BN_LIB);
322 goto err;
323 }
324 if ((x2 = BN_CTX_get(ctx)) == NULL) {
325 SM2error(ERR_R_BN_LIB);
326 goto err;
327 }
328 if ((y1 = BN_CTX_get(ctx)) == NULL) {
329 SM2error(ERR_R_BN_LIB);
330 goto err;
331 }
332 if ((y2 = BN_CTX_get(ctx)) == NULL) {
333 SM2error(ERR_R_BN_LIB);
334 goto err;
335 }
336
337 if ((x2y2 = calloc(2, field_size)) == NULL) {
338 SM2error(ERR_R_MALLOC_FAILURE);
339 goto err;
340 }
341
342 if ((C3 = calloc(1, C3_size)) == NULL) {
343 SM2error(ERR_R_MALLOC_FAILURE);
344 goto err;
345 }
346
347 memset(ciphertext_buf, 0, *ciphertext_len);
348
349 if (!BN_rand_range(k, order)) {
350 SM2error(SM2_R_RANDOM_NUMBER_GENERATION_FAILED);
351 goto err;
352 }
353
354 if (!EC_POINT_mul(group, kG, k, NULL, NULL, ctx)) {
355 SM2error(ERR_R_EC_LIB);
356 goto err;
357 }
358
359 if (!EC_POINT_get_affine_coordinates(group, kG, x1, y1, ctx)) {
360 SM2error(ERR_R_EC_LIB);
361 goto err;
362 }
363
364 if (!EC_POINT_mul(group, kP, NULL, P, k, ctx)) {
365 SM2error(ERR_R_EC_LIB);
366 goto err;
367 }
368
369 if (!EC_POINT_get_affine_coordinates(group, kP, x2, y2, ctx)) {
370 SM2error(ERR_R_EC_LIB);
371 goto err;
372 }
373
374 if ((x2size = BN_num_bytes(x2)) > field_size ||
375 (y2size = BN_num_bytes(y2)) > field_size) {
376 SM2error(SM2_R_BIGNUM_OUT_OF_RANGE);
377 goto err;
378 }
379
380 BN_bn2bin(x2, x2y2 + field_size - x2size);
381 BN_bn2bin(y2, x2y2 + 2 * field_size - y2size);
382
383 if ((msg_mask = calloc(1, msg_len)) == NULL) {
384 SM2error(ERR_R_MALLOC_FAILURE);
385 goto err;
386 }
387
388 if (!sm2_kdf(msg_mask, msg_len, x2y2, 2 * field_size, digest)) {
389 SM2error(SM2_R_KDF_FAILURE);
390 goto err;
391 }
392
393 for (i = 0; i != msg_len; i++)
394 msg_mask[i] ^= msg[i];
395
396 if (!EVP_DigestInit(hash, digest)) {
397 SM2error(ERR_R_EVP_LIB);
398 goto err;
399 }
400
401 if (!EVP_DigestUpdate(hash, x2y2, field_size)) {
402 SM2error(ERR_R_EVP_LIB);
403 goto err;
404 }
405
406 if (!EVP_DigestUpdate(hash, msg, msg_len)) {
407 SM2error(ERR_R_EVP_LIB);
408 goto err;
409 }
410
411 if (!EVP_DigestUpdate(hash, x2y2 + field_size, field_size)) {
412 SM2error(ERR_R_EVP_LIB);
413 goto err;
414 }
415
416 if (!EVP_DigestFinal(hash, C3, NULL)) {
417 SM2error(ERR_R_EVP_LIB);
418 goto err;
419 }
420
421 ctext_struct.C1x = x1;
422 ctext_struct.C1y = y1;
423 if ((ctext_struct.C3 = ASN1_OCTET_STRING_new()) == NULL) {
424 SM2error(ERR_R_MALLOC_FAILURE);
425 goto err;
426 }
427 if ((ctext_struct.C2 = ASN1_OCTET_STRING_new()) == NULL) {
428 SM2error(ERR_R_MALLOC_FAILURE);
429 goto err;
430 }
431 if (!ASN1_OCTET_STRING_set(ctext_struct.C3, C3, C3_size)) {
432 SM2error(ERR_R_INTERNAL_ERROR);
433 goto err;
434 }
435 if (!ASN1_OCTET_STRING_set(ctext_struct.C2, msg_mask, msg_len)) {
436 SM2error(ERR_R_INTERNAL_ERROR);
437 goto err;
438 }
439
440 if ((clen = i2d_SM2_Ciphertext(&ctext_struct, &ciphertext_buf)) < 0) {
441 SM2error(ERR_R_INTERNAL_ERROR);
442 goto err;
443 }
444
445 *ciphertext_len = clen;
446 rc = 1;
447
448 err:
449 ASN1_OCTET_STRING_free(ctext_struct.C2);
450 ASN1_OCTET_STRING_free(ctext_struct.C3);
451 free(msg_mask);
452 free(x2y2);
453 free(C3);
454 EVP_MD_CTX_free(hash);
455 BN_CTX_end(ctx);
456 BN_CTX_free(ctx);
457 EC_POINT_free(kG);
458 EC_POINT_free(kP);
459 BN_free(order);
460 return rc;
461 }
462
463 int
SM2_decrypt(const EC_KEY * key,const EVP_MD * digest,const uint8_t * ciphertext,size_t ciphertext_len,uint8_t * ptext_buf,size_t * ptext_len)464 SM2_decrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *ciphertext,
465 size_t ciphertext_len, uint8_t *ptext_buf, size_t *ptext_len)
466 {
467 SM2_Ciphertext *sm2_ctext = NULL;
468 EVP_MD_CTX *hash = NULL;
469 BN_CTX *ctx = NULL;
470 BIGNUM *x2, *y2;
471 const EC_GROUP *group;
472 EC_POINT *C1 = NULL;
473 const uint8_t *C2, *C3;
474 uint8_t *computed_C3 = NULL, *msg_mask = NULL, *x2y2 = NULL;
475 size_t field_size, x2size, y2size;
476 int msg_len = 0, rc = 0;
477 int hash_size, i;
478
479 if ((group = EC_KEY_get0_group(key)) == NULL) {
480 SM2error(SM2_R_INVALID_KEY);
481 goto err;
482 }
483
484 if ((field_size = ec_field_size(group)) == 0) {
485 SM2error(SM2_R_INVALID_FIELD);
486 goto err;
487 }
488
489 if ((hash_size = EVP_MD_size(digest)) < 0) {
490 SM2error(SM2_R_INVALID_DIGEST);
491 goto err;
492 }
493
494 memset(ptext_buf, 0xFF, *ptext_len);
495
496 if ((sm2_ctext = d2i_SM2_Ciphertext(NULL, &ciphertext,
497 ciphertext_len)) == NULL) {
498 SM2error(SM2_R_ASN1_ERROR);
499 goto err;
500 }
501
502 if (sm2_ctext->C3->length != hash_size) {
503 SM2error(SM2_R_INVALID_ENCODING);
504 goto err;
505 }
506
507 C2 = sm2_ctext->C2->data;
508 C3 = sm2_ctext->C3->data;
509 msg_len = sm2_ctext->C2->length;
510
511 if ((ctx = BN_CTX_new()) == NULL) {
512 SM2error(ERR_R_MALLOC_FAILURE);
513 goto err;
514 }
515
516 BN_CTX_start(ctx);
517 if ((x2 = BN_CTX_get(ctx)) == NULL) {
518 SM2error(ERR_R_BN_LIB);
519 goto err;
520 }
521 if ((y2 = BN_CTX_get(ctx)) == NULL) {
522 SM2error(ERR_R_BN_LIB);
523 goto err;
524 }
525
526 if ((msg_mask = calloc(1, msg_len)) == NULL) {
527 SM2error(ERR_R_MALLOC_FAILURE);
528 goto err;
529 }
530 if ((x2y2 = calloc(2, field_size)) == NULL) {
531 SM2error(ERR_R_MALLOC_FAILURE);
532 goto err;
533 }
534 if ((computed_C3 = calloc(1, hash_size)) == NULL) {
535 SM2error(ERR_R_MALLOC_FAILURE);
536 goto err;
537 }
538
539 if ((C1 = EC_POINT_new(group)) == NULL) {
540 SM2error(ERR_R_MALLOC_FAILURE);
541 goto err;
542 }
543
544 if (!EC_POINT_set_affine_coordinates(group, C1, sm2_ctext->C1x,
545 sm2_ctext->C1y, ctx))
546 {
547 SM2error(ERR_R_EC_LIB);
548 goto err;
549 }
550
551 if (!EC_POINT_mul(group, C1, NULL, C1, EC_KEY_get0_private_key(key),
552 ctx)) {
553 SM2error(ERR_R_EC_LIB);
554 goto err;
555 }
556
557 if (!EC_POINT_get_affine_coordinates(group, C1, x2, y2, ctx)) {
558 SM2error(ERR_R_EC_LIB);
559 goto err;
560 }
561
562 if ((x2size = BN_num_bytes(x2)) > field_size ||
563 (y2size = BN_num_bytes(y2)) > field_size) {
564 SM2error(SM2_R_BIGNUM_OUT_OF_RANGE);
565 goto err;
566 }
567
568 BN_bn2bin(x2, x2y2 + field_size - x2size);
569 BN_bn2bin(y2, x2y2 + 2 * field_size - y2size);
570
571 if (!sm2_kdf(msg_mask, msg_len, x2y2, 2 * field_size, digest)) {
572 SM2error(SM2_R_KDF_FAILURE);
573 goto err;
574 }
575
576 for (i = 0; i != msg_len; ++i)
577 ptext_buf[i] = C2[i] ^ msg_mask[i];
578
579 if ((hash = EVP_MD_CTX_new()) == NULL) {
580 SM2error(ERR_R_EVP_LIB);
581 goto err;
582 }
583
584 if (!EVP_DigestInit(hash, digest)) {
585 SM2error(ERR_R_EVP_LIB);
586 goto err;
587 }
588
589 if (!EVP_DigestUpdate(hash, x2y2, field_size)) {
590 SM2error(ERR_R_EVP_LIB);
591 goto err;
592 }
593
594 if (!EVP_DigestUpdate(hash, ptext_buf, msg_len)) {
595 SM2error(ERR_R_EVP_LIB);
596 goto err;
597 }
598
599 if (!EVP_DigestUpdate(hash, x2y2 + field_size, field_size)) {
600 SM2error(ERR_R_EVP_LIB);
601 goto err;
602 }
603
604 if (!EVP_DigestFinal(hash, computed_C3, NULL)) {
605 SM2error(ERR_R_EVP_LIB);
606 goto err;
607 }
608
609 if (memcmp(computed_C3, C3, hash_size) != 0)
610 goto err;
611
612 rc = 1;
613 *ptext_len = msg_len;
614
615 err:
616 if (rc == 0)
617 memset(ptext_buf, 0, *ptext_len);
618
619 free(msg_mask);
620 free(x2y2);
621 free(computed_C3);
622 EC_POINT_free(C1);
623 BN_CTX_end(ctx);
624 BN_CTX_free(ctx);
625 SM2_Ciphertext_free(sm2_ctext);
626 EVP_MD_CTX_free(hash);
627
628 return rc;
629 }
630
631 #endif /* OPENSSL_NO_SM2 */
632