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 * 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 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 * 101 SM2_Ciphertext_new(void) 102 { 103 return (SM2_Ciphertext *)ASN1_item_new(&SM2_Ciphertext_it); 104 } 105 106 void 107 SM2_Ciphertext_free(SM2_Ciphertext *a) 108 { 109 ASN1_item_free((ASN1_VALUE *)a, &SM2_Ciphertext_it); 110 } 111 112 static size_t 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 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 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 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 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 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