1*aeeaa6d4Stb /* $OpenBSD: sm2_crypt.c,v 1.3 2024/02/09 07:43:52 tb Exp $ */
251892d90Stb /*
351892d90Stb * Copyright (c) 2017, 2019 Ribose Inc
451892d90Stb *
551892d90Stb * Permission to use, copy, modify, and/or distribute this software for any
651892d90Stb * purpose with or without fee is hereby granted, provided that the above
751892d90Stb * copyright notice and this permission notice appear in all copies.
851892d90Stb *
951892d90Stb * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1051892d90Stb * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1151892d90Stb * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1251892d90Stb * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1351892d90Stb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1451892d90Stb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1551892d90Stb * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1651892d90Stb */
1751892d90Stb
1851892d90Stb #ifndef OPENSSL_NO_SM2
1951892d90Stb
2051892d90Stb #include <string.h>
2151892d90Stb
2251892d90Stb #include <openssl/asn1.h>
2351892d90Stb #include <openssl/asn1t.h>
2451892d90Stb #include <openssl/bn.h>
2551892d90Stb #include <openssl/err.h>
2651892d90Stb #include <openssl/evp.h>
2751892d90Stb #include <openssl/sm2.h>
2851892d90Stb
29c9675a23Stb #include "sm2_local.h"
3051892d90Stb
3151892d90Stb typedef struct SM2_Ciphertext_st SM2_Ciphertext;
3251892d90Stb
3351892d90Stb SM2_Ciphertext *SM2_Ciphertext_new(void);
3451892d90Stb void SM2_Ciphertext_free(SM2_Ciphertext *a);
3551892d90Stb SM2_Ciphertext *d2i_SM2_Ciphertext(SM2_Ciphertext **a, const unsigned char **in,
3651892d90Stb long len);
3751892d90Stb int i2d_SM2_Ciphertext(SM2_Ciphertext *a, unsigned char **out);
3851892d90Stb
3951892d90Stb struct SM2_Ciphertext_st {
4051892d90Stb BIGNUM *C1x;
4151892d90Stb BIGNUM *C1y;
4251892d90Stb ASN1_OCTET_STRING *C3;
4351892d90Stb ASN1_OCTET_STRING *C2;
4451892d90Stb };
4551892d90Stb
4651892d90Stb static const ASN1_TEMPLATE SM2_Ciphertext_seq_tt[] = {
4751892d90Stb {
4851892d90Stb .flags = 0,
4951892d90Stb .tag = 0,
5051892d90Stb .offset = offsetof(SM2_Ciphertext, C1x),
5151892d90Stb .field_name = "C1x",
5251892d90Stb .item = &BIGNUM_it,
5351892d90Stb },
5451892d90Stb {
5551892d90Stb .flags = 0,
5651892d90Stb .tag = 0,
5751892d90Stb .offset = offsetof(SM2_Ciphertext, C1y),
5851892d90Stb .field_name = "C1y",
5951892d90Stb .item = &BIGNUM_it,
6051892d90Stb },
6151892d90Stb {
6251892d90Stb .flags = 0,
6351892d90Stb .tag = 0,
6451892d90Stb .offset = offsetof(SM2_Ciphertext, C3),
6551892d90Stb .field_name = "C3",
6651892d90Stb .item = &ASN1_OCTET_STRING_it,
6751892d90Stb },
6851892d90Stb {
6951892d90Stb .flags = 0,
7051892d90Stb .tag = 0,
7151892d90Stb .offset = offsetof(SM2_Ciphertext, C2),
7251892d90Stb .field_name = "C2",
7351892d90Stb .item = &ASN1_OCTET_STRING_it,
7451892d90Stb },
7551892d90Stb };
7651892d90Stb
7751892d90Stb const ASN1_ITEM SM2_Ciphertext_it = {
7851892d90Stb .itype = ASN1_ITYPE_SEQUENCE,
7951892d90Stb .utype = V_ASN1_SEQUENCE,
8051892d90Stb .templates = SM2_Ciphertext_seq_tt,
8151892d90Stb .tcount = sizeof(SM2_Ciphertext_seq_tt) / sizeof(ASN1_TEMPLATE),
8251892d90Stb .funcs = NULL,
8351892d90Stb .size = sizeof(SM2_Ciphertext),
8451892d90Stb .sname = "SM2_Ciphertext",
8551892d90Stb };
8651892d90Stb
8751892d90Stb SM2_Ciphertext *
d2i_SM2_Ciphertext(SM2_Ciphertext ** a,const unsigned char ** in,long len)8851892d90Stb d2i_SM2_Ciphertext(SM2_Ciphertext **a, const unsigned char **in, long len)
8951892d90Stb {
9051892d90Stb return (SM2_Ciphertext *) ASN1_item_d2i((ASN1_VALUE **)a, in, len,
9151892d90Stb &SM2_Ciphertext_it);
9251892d90Stb }
9351892d90Stb
9451892d90Stb int
i2d_SM2_Ciphertext(SM2_Ciphertext * a,unsigned char ** out)9551892d90Stb i2d_SM2_Ciphertext(SM2_Ciphertext *a, unsigned char **out)
9651892d90Stb {
9751892d90Stb return ASN1_item_i2d((ASN1_VALUE *)a, out, &SM2_Ciphertext_it);
9851892d90Stb }
9951892d90Stb
10051892d90Stb SM2_Ciphertext *
SM2_Ciphertext_new(void)10151892d90Stb SM2_Ciphertext_new(void)
10251892d90Stb {
10351892d90Stb return (SM2_Ciphertext *)ASN1_item_new(&SM2_Ciphertext_it);
10451892d90Stb }
10551892d90Stb
10651892d90Stb void
SM2_Ciphertext_free(SM2_Ciphertext * a)10751892d90Stb SM2_Ciphertext_free(SM2_Ciphertext *a)
10851892d90Stb {
10951892d90Stb ASN1_item_free((ASN1_VALUE *)a, &SM2_Ciphertext_it);
11051892d90Stb }
11151892d90Stb
11251892d90Stb static size_t
ec_field_size(const EC_GROUP * group)11351892d90Stb ec_field_size(const EC_GROUP *group)
11451892d90Stb {
11551892d90Stb /* Is there some simpler way to do this? */
11651892d90Stb BIGNUM *p;
11751892d90Stb size_t field_size = 0;
11851892d90Stb
11951892d90Stb if ((p = BN_new()) == NULL)
12051892d90Stb goto err;
12151892d90Stb if (!EC_GROUP_get_curve(group, p, NULL, NULL, NULL))
12251892d90Stb goto err;
12351892d90Stb field_size = BN_num_bytes(p);
12451892d90Stb err:
12551892d90Stb BN_free(p);
12651892d90Stb return field_size;
12751892d90Stb }
12851892d90Stb
12951892d90Stb int
SM2_plaintext_size(const EC_KEY * key,const EVP_MD * digest,size_t msg_len,size_t * pl_size)13051892d90Stb SM2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
13151892d90Stb size_t *pl_size)
13251892d90Stb {
13351892d90Stb size_t field_size, overhead;
13451892d90Stb int md_size;
13551892d90Stb
13651892d90Stb if ((field_size = ec_field_size(EC_KEY_get0_group(key))) == 0) {
13751892d90Stb SM2error(SM2_R_INVALID_FIELD);
13851892d90Stb return 0;
13951892d90Stb }
14051892d90Stb
14151892d90Stb if ((md_size = EVP_MD_size(digest)) < 0) {
14251892d90Stb SM2error(SM2_R_INVALID_DIGEST);
14351892d90Stb return 0;
14451892d90Stb }
14551892d90Stb
14651892d90Stb overhead = 10 + 2 * field_size + md_size;
14751892d90Stb if (msg_len <= overhead) {
14851892d90Stb SM2error(SM2_R_INVALID_ARGUMENT);
14951892d90Stb return 0;
15051892d90Stb }
15151892d90Stb
15251892d90Stb *pl_size = msg_len - overhead;
15351892d90Stb return 1;
15451892d90Stb }
15551892d90Stb
15651892d90Stb int
SM2_ciphertext_size(const EC_KEY * key,const EVP_MD * digest,size_t msg_len,size_t * c_size)15751892d90Stb SM2_ciphertext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
15851892d90Stb size_t *c_size)
15951892d90Stb {
16051892d90Stb size_t asn_size, field_size;
16151892d90Stb int md_size;
16251892d90Stb
16351892d90Stb if ((field_size = ec_field_size(EC_KEY_get0_group(key))) == 0) {
16451892d90Stb SM2error(SM2_R_INVALID_FIELD);
16551892d90Stb return 0;
16651892d90Stb }
16751892d90Stb
16851892d90Stb if ((md_size = EVP_MD_size(digest)) < 0) {
16951892d90Stb SM2error(SM2_R_INVALID_DIGEST);
17051892d90Stb return 0;
17151892d90Stb }
17251892d90Stb
17351892d90Stb asn_size = 2 * ASN1_object_size(0, field_size + 1, V_ASN1_INTEGER) +
17451892d90Stb ASN1_object_size(0, md_size, V_ASN1_OCTET_STRING) +
17551892d90Stb ASN1_object_size(0, msg_len, V_ASN1_OCTET_STRING);
17651892d90Stb
17751892d90Stb *c_size = ASN1_object_size(1, asn_size, V_ASN1_SEQUENCE);
17851892d90Stb return 1;
17951892d90Stb }
18051892d90Stb
18151892d90Stb int
sm2_kdf(uint8_t * key,size_t key_len,uint8_t * secret,size_t secret_len,const EVP_MD * digest)18251892d90Stb sm2_kdf(uint8_t *key, size_t key_len, uint8_t *secret, size_t secret_len,
18351892d90Stb const EVP_MD *digest)
18451892d90Stb {
18551892d90Stb EVP_MD_CTX *hash;
18651892d90Stb uint8_t *hash_buf = NULL;
18751892d90Stb uint32_t ctr = 1;
18851892d90Stb uint8_t ctr_buf[4] = {0};
18951892d90Stb size_t hadd, hlen;
19051892d90Stb int rc = 0;
19151892d90Stb
19251892d90Stb if ((hash = EVP_MD_CTX_new()) == NULL) {
19351892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
19451892d90Stb goto err;
19551892d90Stb }
19651892d90Stb
19751892d90Stb if ((hlen = EVP_MD_size(digest)) < 0) {
19851892d90Stb SM2error(SM2_R_INVALID_DIGEST);
19951892d90Stb goto err;
20051892d90Stb }
20151892d90Stb if ((hash_buf = malloc(hlen)) == NULL) {
20251892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
20351892d90Stb goto err;
20451892d90Stb }
20551892d90Stb
20651892d90Stb while ((key_len > 0) && (ctr != 0)) {
20751892d90Stb if (!EVP_DigestInit_ex(hash, digest, NULL)) {
20851892d90Stb SM2error(ERR_R_EVP_LIB);
20951892d90Stb goto err;
21051892d90Stb }
21151892d90Stb if (!EVP_DigestUpdate(hash, secret, secret_len)) {
21251892d90Stb SM2error(ERR_R_EVP_LIB);
21351892d90Stb goto err;
21451892d90Stb }
21551892d90Stb
21651892d90Stb /* big-endian counter representation */
21751892d90Stb ctr_buf[0] = (ctr >> 24) & 0xff;
21851892d90Stb ctr_buf[1] = (ctr >> 16) & 0xff;
21951892d90Stb ctr_buf[2] = (ctr >> 8) & 0xff;
22051892d90Stb ctr_buf[3] = ctr & 0xff;
22151892d90Stb ctr++;
22251892d90Stb
22351892d90Stb if (!EVP_DigestUpdate(hash, ctr_buf, 4)) {
22451892d90Stb SM2error(ERR_R_EVP_LIB);
22551892d90Stb goto err;
22651892d90Stb }
22751892d90Stb if (!EVP_DigestFinal(hash, hash_buf, NULL)) {
22851892d90Stb SM2error(ERR_R_EVP_LIB);
22951892d90Stb goto err;
23051892d90Stb }
23151892d90Stb
23251892d90Stb hadd = key_len > hlen ? hlen : key_len;
23351892d90Stb memcpy(key, hash_buf, hadd);
23451892d90Stb memset(hash_buf, 0, hlen);
23551892d90Stb key_len -= hadd;
23651892d90Stb key += hadd;
23751892d90Stb }
23851892d90Stb
23951892d90Stb rc = 1;
24051892d90Stb err:
24151892d90Stb free(hash_buf);
24251892d90Stb EVP_MD_CTX_free(hash);
24351892d90Stb return rc;
24451892d90Stb }
24551892d90Stb
24651892d90Stb 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)24751892d90Stb SM2_encrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *msg,
24851892d90Stb size_t msg_len, uint8_t *ciphertext_buf, size_t *ciphertext_len)
24951892d90Stb {
25051892d90Stb SM2_Ciphertext ctext_struct;
25151892d90Stb EVP_MD_CTX *hash = NULL;
25251892d90Stb BN_CTX *ctx = NULL;
25351892d90Stb BIGNUM *order = NULL;
25451892d90Stb BIGNUM *k, *x1, *y1, *x2, *y2;
25551892d90Stb const EC_GROUP *group;
25651892d90Stb const EC_POINT *P;
25751892d90Stb EC_POINT *kG = NULL, *kP = NULL;
25851892d90Stb uint8_t *msg_mask = NULL, *x2y2 = NULL, *C3 = NULL;
25951892d90Stb size_t C3_size, field_size, i, x2size, y2size;
26051892d90Stb int rc = 0;
26151892d90Stb int clen;
26251892d90Stb
26351892d90Stb ctext_struct.C2 = NULL;
26451892d90Stb ctext_struct.C3 = NULL;
26551892d90Stb
26651892d90Stb if ((hash = EVP_MD_CTX_new()) == NULL) {
26751892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
26851892d90Stb goto err;
26951892d90Stb }
27051892d90Stb
27151892d90Stb if ((group = EC_KEY_get0_group(key)) == NULL) {
27251892d90Stb SM2error(SM2_R_INVALID_KEY);
27351892d90Stb goto err;
27451892d90Stb }
27551892d90Stb
27651892d90Stb if ((order = BN_new()) == NULL) {
27751892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
27851892d90Stb goto err;
27951892d90Stb }
28051892d90Stb
28151892d90Stb if (!EC_GROUP_get_order(group, order, NULL)) {
28251892d90Stb SM2error(SM2_R_INVALID_GROUP_ORDER);
28351892d90Stb goto err;
28451892d90Stb }
28551892d90Stb
28651892d90Stb if ((P = EC_KEY_get0_public_key(key)) == NULL) {
28751892d90Stb SM2error(SM2_R_INVALID_KEY);
28851892d90Stb goto err;
28951892d90Stb }
29051892d90Stb
29151892d90Stb if ((field_size = ec_field_size(group)) == 0) {
29251892d90Stb SM2error(SM2_R_INVALID_FIELD);
29351892d90Stb goto err;
29451892d90Stb }
29551892d90Stb
29651892d90Stb if ((C3_size = EVP_MD_size(digest)) < 0) {
29751892d90Stb SM2error(SM2_R_INVALID_DIGEST);
29851892d90Stb goto err;
29951892d90Stb }
30051892d90Stb
30151892d90Stb if ((kG = EC_POINT_new(group)) == NULL) {
30251892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
30351892d90Stb goto err;
30451892d90Stb }
30551892d90Stb if ((kP = EC_POINT_new(group)) == NULL) {
30651892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
30751892d90Stb goto err;
30851892d90Stb }
30951892d90Stb
31051892d90Stb if ((ctx = BN_CTX_new()) == NULL) {
31151892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
31251892d90Stb goto err;
31351892d90Stb }
31451892d90Stb
31551892d90Stb BN_CTX_start(ctx);
31651892d90Stb if ((k = BN_CTX_get(ctx)) == NULL) {
31751892d90Stb SM2error(ERR_R_BN_LIB);
31851892d90Stb goto err;
31951892d90Stb }
32051892d90Stb if ((x1 = BN_CTX_get(ctx)) == NULL) {
32151892d90Stb SM2error(ERR_R_BN_LIB);
32251892d90Stb goto err;
32351892d90Stb }
32451892d90Stb if ((x2 = BN_CTX_get(ctx)) == NULL) {
32551892d90Stb SM2error(ERR_R_BN_LIB);
32651892d90Stb goto err;
32751892d90Stb }
32851892d90Stb if ((y1 = BN_CTX_get(ctx)) == NULL) {
32951892d90Stb SM2error(ERR_R_BN_LIB);
33051892d90Stb goto err;
33151892d90Stb }
33251892d90Stb if ((y2 = BN_CTX_get(ctx)) == NULL) {
33351892d90Stb SM2error(ERR_R_BN_LIB);
33451892d90Stb goto err;
33551892d90Stb }
33651892d90Stb
33751892d90Stb if ((x2y2 = calloc(2, field_size)) == NULL) {
33851892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
33951892d90Stb goto err;
34051892d90Stb }
34151892d90Stb
34251892d90Stb if ((C3 = calloc(1, C3_size)) == NULL) {
34351892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
34451892d90Stb goto err;
34551892d90Stb }
34651892d90Stb
34751892d90Stb memset(ciphertext_buf, 0, *ciphertext_len);
34851892d90Stb
34951892d90Stb if (!BN_rand_range(k, order)) {
35051892d90Stb SM2error(SM2_R_RANDOM_NUMBER_GENERATION_FAILED);
35151892d90Stb goto err;
35251892d90Stb }
35351892d90Stb
35451892d90Stb if (!EC_POINT_mul(group, kG, k, NULL, NULL, ctx)) {
35551892d90Stb SM2error(ERR_R_EC_LIB);
35651892d90Stb goto err;
35751892d90Stb }
35851892d90Stb
35951892d90Stb if (!EC_POINT_get_affine_coordinates(group, kG, x1, y1, ctx)) {
36051892d90Stb SM2error(ERR_R_EC_LIB);
36151892d90Stb goto err;
36251892d90Stb }
36351892d90Stb
36451892d90Stb if (!EC_POINT_mul(group, kP, NULL, P, k, ctx)) {
36551892d90Stb SM2error(ERR_R_EC_LIB);
36651892d90Stb goto err;
36751892d90Stb }
36851892d90Stb
36951892d90Stb if (!EC_POINT_get_affine_coordinates(group, kP, x2, y2, ctx)) {
37051892d90Stb SM2error(ERR_R_EC_LIB);
37151892d90Stb goto err;
37251892d90Stb }
37351892d90Stb
37451892d90Stb if ((x2size = BN_num_bytes(x2)) > field_size ||
37551892d90Stb (y2size = BN_num_bytes(y2)) > field_size) {
37651892d90Stb SM2error(SM2_R_BIGNUM_OUT_OF_RANGE);
37751892d90Stb goto err;
37851892d90Stb }
37951892d90Stb
38051892d90Stb BN_bn2bin(x2, x2y2 + field_size - x2size);
38151892d90Stb BN_bn2bin(y2, x2y2 + 2 * field_size - y2size);
38251892d90Stb
38351892d90Stb if ((msg_mask = calloc(1, msg_len)) == NULL) {
38451892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
38551892d90Stb goto err;
38651892d90Stb }
38751892d90Stb
38851892d90Stb if (!sm2_kdf(msg_mask, msg_len, x2y2, 2 * field_size, digest)) {
38951892d90Stb SM2error(SM2_R_KDF_FAILURE);
39051892d90Stb goto err;
39151892d90Stb }
39251892d90Stb
39351892d90Stb for (i = 0; i != msg_len; i++)
39451892d90Stb msg_mask[i] ^= msg[i];
39551892d90Stb
39651892d90Stb if (!EVP_DigestInit(hash, digest)) {
39751892d90Stb SM2error(ERR_R_EVP_LIB);
39851892d90Stb goto err;
39951892d90Stb }
40051892d90Stb
40151892d90Stb if (!EVP_DigestUpdate(hash, x2y2, field_size)) {
40251892d90Stb SM2error(ERR_R_EVP_LIB);
40351892d90Stb goto err;
40451892d90Stb }
40551892d90Stb
40651892d90Stb if (!EVP_DigestUpdate(hash, msg, msg_len)) {
40751892d90Stb SM2error(ERR_R_EVP_LIB);
40851892d90Stb goto err;
40951892d90Stb }
41051892d90Stb
41151892d90Stb if (!EVP_DigestUpdate(hash, x2y2 + field_size, field_size)) {
41251892d90Stb SM2error(ERR_R_EVP_LIB);
41351892d90Stb goto err;
41451892d90Stb }
41551892d90Stb
41651892d90Stb if (!EVP_DigestFinal(hash, C3, NULL)) {
41751892d90Stb SM2error(ERR_R_EVP_LIB);
41851892d90Stb goto err;
41951892d90Stb }
42051892d90Stb
42151892d90Stb ctext_struct.C1x = x1;
42251892d90Stb ctext_struct.C1y = y1;
42351892d90Stb if ((ctext_struct.C3 = ASN1_OCTET_STRING_new()) == NULL) {
42451892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
42551892d90Stb goto err;
42651892d90Stb }
42751892d90Stb if ((ctext_struct.C2 = ASN1_OCTET_STRING_new()) == NULL) {
42851892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
42951892d90Stb goto err;
43051892d90Stb }
43151892d90Stb if (!ASN1_OCTET_STRING_set(ctext_struct.C3, C3, C3_size)) {
43251892d90Stb SM2error(ERR_R_INTERNAL_ERROR);
43351892d90Stb goto err;
43451892d90Stb }
43551892d90Stb if (!ASN1_OCTET_STRING_set(ctext_struct.C2, msg_mask, msg_len)) {
43651892d90Stb SM2error(ERR_R_INTERNAL_ERROR);
43751892d90Stb goto err;
43851892d90Stb }
43951892d90Stb
44051892d90Stb if ((clen = i2d_SM2_Ciphertext(&ctext_struct, &ciphertext_buf)) < 0) {
44151892d90Stb SM2error(ERR_R_INTERNAL_ERROR);
44251892d90Stb goto err;
44351892d90Stb }
44451892d90Stb
44551892d90Stb *ciphertext_len = clen;
44651892d90Stb rc = 1;
44751892d90Stb
44851892d90Stb err:
44951892d90Stb ASN1_OCTET_STRING_free(ctext_struct.C2);
45051892d90Stb ASN1_OCTET_STRING_free(ctext_struct.C3);
45151892d90Stb free(msg_mask);
45251892d90Stb free(x2y2);
45351892d90Stb free(C3);
45451892d90Stb EVP_MD_CTX_free(hash);
45551892d90Stb BN_CTX_end(ctx);
45651892d90Stb BN_CTX_free(ctx);
45751892d90Stb EC_POINT_free(kG);
45851892d90Stb EC_POINT_free(kP);
45951892d90Stb BN_free(order);
46051892d90Stb return rc;
46151892d90Stb }
46251892d90Stb
46351892d90Stb 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)46451892d90Stb SM2_decrypt(const EC_KEY *key, const EVP_MD *digest, const uint8_t *ciphertext,
46551892d90Stb size_t ciphertext_len, uint8_t *ptext_buf, size_t *ptext_len)
46651892d90Stb {
46751892d90Stb SM2_Ciphertext *sm2_ctext = NULL;
46851892d90Stb EVP_MD_CTX *hash = NULL;
46951892d90Stb BN_CTX *ctx = NULL;
47051892d90Stb BIGNUM *x2, *y2;
47151892d90Stb const EC_GROUP *group;
47251892d90Stb EC_POINT *C1 = NULL;
47351892d90Stb const uint8_t *C2, *C3;
47451892d90Stb uint8_t *computed_C3 = NULL, *msg_mask = NULL, *x2y2 = NULL;
47551892d90Stb size_t field_size, x2size, y2size;
47651892d90Stb int msg_len = 0, rc = 0;
47751892d90Stb int hash_size, i;
47851892d90Stb
47951892d90Stb if ((group = EC_KEY_get0_group(key)) == NULL) {
48051892d90Stb SM2error(SM2_R_INVALID_KEY);
48151892d90Stb goto err;
48251892d90Stb }
48351892d90Stb
48451892d90Stb if ((field_size = ec_field_size(group)) == 0) {
48551892d90Stb SM2error(SM2_R_INVALID_FIELD);
48651892d90Stb goto err;
48751892d90Stb }
48851892d90Stb
48951892d90Stb if ((hash_size = EVP_MD_size(digest)) < 0) {
49051892d90Stb SM2error(SM2_R_INVALID_DIGEST);
49151892d90Stb goto err;
49251892d90Stb }
49351892d90Stb
49451892d90Stb memset(ptext_buf, 0xFF, *ptext_len);
49551892d90Stb
49651892d90Stb if ((sm2_ctext = d2i_SM2_Ciphertext(NULL, &ciphertext,
49751892d90Stb ciphertext_len)) == NULL) {
49851892d90Stb SM2error(SM2_R_ASN1_ERROR);
49951892d90Stb goto err;
50051892d90Stb }
50151892d90Stb
50251892d90Stb if (sm2_ctext->C3->length != hash_size) {
50351892d90Stb SM2error(SM2_R_INVALID_ENCODING);
50451892d90Stb goto err;
50551892d90Stb }
50651892d90Stb
50751892d90Stb C2 = sm2_ctext->C2->data;
50851892d90Stb C3 = sm2_ctext->C3->data;
50951892d90Stb msg_len = sm2_ctext->C2->length;
51051892d90Stb
51151892d90Stb if ((ctx = BN_CTX_new()) == NULL) {
51251892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
51351892d90Stb goto err;
51451892d90Stb }
51551892d90Stb
51651892d90Stb BN_CTX_start(ctx);
51751892d90Stb if ((x2 = BN_CTX_get(ctx)) == NULL) {
51851892d90Stb SM2error(ERR_R_BN_LIB);
51951892d90Stb goto err;
52051892d90Stb }
52151892d90Stb if ((y2 = BN_CTX_get(ctx)) == NULL) {
52251892d90Stb SM2error(ERR_R_BN_LIB);
52351892d90Stb goto err;
52451892d90Stb }
52551892d90Stb
52651892d90Stb if ((msg_mask = calloc(1, msg_len)) == NULL) {
52751892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
52851892d90Stb goto err;
52951892d90Stb }
53051892d90Stb if ((x2y2 = calloc(2, field_size)) == NULL) {
53151892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
53251892d90Stb goto err;
53351892d90Stb }
53451892d90Stb if ((computed_C3 = calloc(1, hash_size)) == NULL) {
53551892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
53651892d90Stb goto err;
53751892d90Stb }
53851892d90Stb
53951892d90Stb if ((C1 = EC_POINT_new(group)) == NULL) {
54051892d90Stb SM2error(ERR_R_MALLOC_FAILURE);
54151892d90Stb goto err;
54251892d90Stb }
54351892d90Stb
54451892d90Stb if (!EC_POINT_set_affine_coordinates(group, C1, sm2_ctext->C1x,
54551892d90Stb sm2_ctext->C1y, ctx))
54651892d90Stb {
54751892d90Stb SM2error(ERR_R_EC_LIB);
54851892d90Stb goto err;
54951892d90Stb }
55051892d90Stb
55151892d90Stb if (!EC_POINT_mul(group, C1, NULL, C1, EC_KEY_get0_private_key(key),
55251892d90Stb ctx)) {
55351892d90Stb SM2error(ERR_R_EC_LIB);
55451892d90Stb goto err;
55551892d90Stb }
55651892d90Stb
55751892d90Stb if (!EC_POINT_get_affine_coordinates(group, C1, x2, y2, ctx)) {
55851892d90Stb SM2error(ERR_R_EC_LIB);
55951892d90Stb goto err;
56051892d90Stb }
56151892d90Stb
56251892d90Stb if ((x2size = BN_num_bytes(x2)) > field_size ||
56351892d90Stb (y2size = BN_num_bytes(y2)) > field_size) {
56451892d90Stb SM2error(SM2_R_BIGNUM_OUT_OF_RANGE);
56551892d90Stb goto err;
56651892d90Stb }
56751892d90Stb
56851892d90Stb BN_bn2bin(x2, x2y2 + field_size - x2size);
56951892d90Stb BN_bn2bin(y2, x2y2 + 2 * field_size - y2size);
57051892d90Stb
57151892d90Stb if (!sm2_kdf(msg_mask, msg_len, x2y2, 2 * field_size, digest)) {
57251892d90Stb SM2error(SM2_R_KDF_FAILURE);
57351892d90Stb goto err;
57451892d90Stb }
57551892d90Stb
57651892d90Stb for (i = 0; i != msg_len; ++i)
57751892d90Stb ptext_buf[i] = C2[i] ^ msg_mask[i];
57851892d90Stb
57951892d90Stb if ((hash = EVP_MD_CTX_new()) == NULL) {
58051892d90Stb SM2error(ERR_R_EVP_LIB);
58151892d90Stb goto err;
58251892d90Stb }
58351892d90Stb
58451892d90Stb if (!EVP_DigestInit(hash, digest)) {
58551892d90Stb SM2error(ERR_R_EVP_LIB);
58651892d90Stb goto err;
58751892d90Stb }
58851892d90Stb
58951892d90Stb if (!EVP_DigestUpdate(hash, x2y2, field_size)) {
59051892d90Stb SM2error(ERR_R_EVP_LIB);
59151892d90Stb goto err;
59251892d90Stb }
59351892d90Stb
59451892d90Stb if (!EVP_DigestUpdate(hash, ptext_buf, msg_len)) {
59551892d90Stb SM2error(ERR_R_EVP_LIB);
59651892d90Stb goto err;
59751892d90Stb }
59851892d90Stb
59951892d90Stb if (!EVP_DigestUpdate(hash, x2y2 + field_size, field_size)) {
60051892d90Stb SM2error(ERR_R_EVP_LIB);
60151892d90Stb goto err;
60251892d90Stb }
60351892d90Stb
60451892d90Stb if (!EVP_DigestFinal(hash, computed_C3, NULL)) {
60551892d90Stb SM2error(ERR_R_EVP_LIB);
60651892d90Stb goto err;
60751892d90Stb }
60851892d90Stb
60951892d90Stb if (memcmp(computed_C3, C3, hash_size) != 0)
61051892d90Stb goto err;
61151892d90Stb
61251892d90Stb rc = 1;
61351892d90Stb *ptext_len = msg_len;
61451892d90Stb
61551892d90Stb err:
61651892d90Stb if (rc == 0)
61751892d90Stb memset(ptext_buf, 0, *ptext_len);
61851892d90Stb
61951892d90Stb free(msg_mask);
62051892d90Stb free(x2y2);
62151892d90Stb free(computed_C3);
62251892d90Stb EC_POINT_free(C1);
62351892d90Stb BN_CTX_end(ctx);
62451892d90Stb BN_CTX_free(ctx);
62551892d90Stb SM2_Ciphertext_free(sm2_ctext);
62651892d90Stb EVP_MD_CTX_free(hash);
62751892d90Stb
62851892d90Stb return rc;
62951892d90Stb }
63051892d90Stb
63151892d90Stb #endif /* OPENSSL_NO_SM2 */
632