gmssl national secret sm2 (generate key pair-private key signature-certificate verification)

Generate a key pair:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "e_os.h"
#include "sm2ToOC.h"
#include "string.h"
# include <openssl/bn.h>
# include <openssl/ec.h>
# include <openssl/evp.h>
# include <openssl/rand.h>
# include <openssl/engine.h>
# include <openssl/sm2.h>
# include "sm2_lcl.h"
# include "pkcs12.h"
#include <openssl/pem.h>
#include "ec/ec_lcl.h"
#include "bn/bn_lcl.h"

int genkey()
{
    EC_KEY *keypair = NULL;
    EC_GROUP *group1 = NULL;

    keypair = EC_KEY_new();
    if(!keypair) {
        printf("Failed to Gen Key");
        exit(1);
    }

    group1 = EC_GROUP_new_by_curve_name(NID_sm2p256v1);

    if(group1 == NULL){
        printf("Failed to Gen Key");
        exit(1);
    }

    int ret1 = EC_KEY_set_group(keypair, group1);
    if(ret1 != 1){
        printf("Failed to Gen Key");
        exit(1);
    }

    int ret2 = EC_KEY_generate_key(keypair);
    if(ret2 != 1){
        printf("Failed to Gen Key");
        exit(1);
    }

    size_t pri_len;
    size_t pub_len;
    char *pri_key = NULL;
    char *pub_key = NULL;
 
	BIO *pri = BIO_new(BIO_s_mem());
	BIO *pub = BIO_new(BIO_s_mem());
 
	PEM_write_bio_ECPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
	PEM_write_bio_EC_PUBKEY(pub, keypair);

    BIO *bio_out = BIO_new_file("private.key", "w");
	PEM_write_bio_ECPrivateKey(bio_out, keypair, NULL, NULL, 0, NULL, NULL);
    BIO_free(bio_out);
    bio_out = BIO_new_file("public.key", "w");
	PEM_write_bio_EC_PUBKEY(bio_out, keypair);
    BIO_free(bio_out);
 
	pri_len = BIO_pending(pri);
	pub_len = BIO_pending(pub);
 
	pri_key = (char *)malloc(pri_len + 1);
	pub_key = (char *)malloc(pub_len + 1);
 
	BIO_read(pri, pri_key, pri_len);
	BIO_read(pub, pub_key, pub_len);
 
	pri_key[pri_len] = '\0';
	pub_key[pub_len] = '\0';
 
	EC_KEY_free(keypair);
	BIO_free_all(pub);
	BIO_free_all(pri);
	
	free(pri_key);
	free(pub_key);
    
    return 1;
}

void main(void)
{
    genkey();
}

Sign and check:


#include <stdio.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>

#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/ecdsa.h>
#include <openssl/sha.h>
#include <openssl/asn1.h>
#include <openssl/x509.h>
#include <openssl/objects.h>
#include <openssl/buffer.h>
#include <openssl/sm2.h>

#include <apps/apps.h>

int bio_to_mem(unsigned char **out, int maxlen, BIO *in)
{
    BIO *mem;
    int len, ret;
    unsigned char tbuf[1024];

    mem = BIO_new(BIO_s_mem());
    if (mem == NULL)
        return -1;
    for (;;) {
        if ((maxlen != -1) && maxlen < 1024)
            len = maxlen;
        else
            len = 1024;
        len = BIO_read(in, tbuf, len);
        if (len < 0) {
            BIO_free(mem);
            return -1;
        }
        if (len == 0)
            break;
        if (BIO_write(mem, tbuf, len) != len) {
            BIO_free(mem);
            return -1;
        }
        maxlen -= len;

        if (maxlen == 0)
            break;
    }
    ret = BIO_get_mem_data(mem, (char **)out);
    BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY);
    BIO_free(mem);
    return ret;
}


static int sm2utl_sign(const EVP_MD *md, BIO *in, BIO *out, const char *id,
	ENGINE *e, EC_KEY *ec_key, int sign)
{
	int ret = 0;
	EVP_MD_CTX *md_ctx = NULL;
	ECDSA_SIG *sig = NULL;
	unsigned char buf[1024];
	size_t siz = sizeof(buf);
	unsigned int ulen = sizeof(buf);
	int len;

	printf("sm2utl_sign\n");

	if (!(md_ctx = EVP_MD_CTX_new())
		|| !EVP_DigestInit_ex(md_ctx, md, e)
		|| !SM2_compute_id_digest(md, id, strlen(id), buf, &siz, ec_key)
		|| !EVP_DigestUpdate(md_ctx, buf, siz)) {
	}
	while ((len = BIO_read(in, buf, sizeof(buf))) > 0) {
		if (!EVP_DigestUpdate(md_ctx, buf, len)) {
		}
	}
	if (!EVP_DigestFinal_ex(md_ctx, buf, &ulen)) {
	}
	len = (int)ulen;

	if (sign) {
		unsigned char *p = buf;
		if (!(sig = SM2_do_sign(buf, len, ec_key))
			|| (len = i2d_ECDSA_SIG(sig, &p)) <= 0) {
		}
	}
	if (BIO_write(out, buf, len) != len) {
	}

	ret = 1;
end:
	EVP_MD_CTX_free(md_ctx);
	ECDSA_SIG_free(sig);
	return ret;
}

static int sm2utl_verify(const EVP_MD *md, BIO *in, BIO *out, BIO *sig,
	const char *id, ENGINE *e, EC_KEY *ec_key)
{
	int ret = 0;
	EVP_MD_CTX *md_ctx = NULL;
	unsigned char *sigbuf = NULL;
	unsigned char buf[1024];
	size_t siz = sizeof(buf);
	unsigned int ulen = sizeof(buf);
	int siglen, len;

	siglen = bio_to_mem(&sigbuf, 256, sig);
	if (siglen < 0) {
	}

	if (!(md_ctx = EVP_MD_CTX_new())
		|| !EVP_DigestInit_ex(md_ctx, md, e)
		|| !SM2_compute_id_digest(md, id, strlen(id), buf, &siz, ec_key)
		|| !EVP_DigestUpdate(md_ctx, buf, siz)) {
	}
	while ((len = BIO_read(in, buf, sizeof(buf))) > 0) {
		if (!EVP_DigestUpdate(md_ctx, buf, len)) {
		}
	}
	siz = sizeof(buf);
	if (!EVP_DigestFinal_ex(md_ctx, buf, &ulen)) {
	}
	/* SM2_verify() can check no suffix on signature */
	ret = SM2_verify(NID_undef, buf, ulen, sigbuf, siglen, ec_key);
	if (ret == 1) {
		printf("Signature Verification Successful\n");
	} else {
		printf("Signature Verification Failure\n");
		ret = 0;
	}

end:
	OPENSSL_free(sigbuf);
	EVP_MD_CTX_free(md_ctx);
	return ret;
}

int signature(char *msg)
{
    BIO *in = NULL, *out = NULL, *sig = NULL;
    char *keyfile = NULL;
    EVP_PKEY *pkey = NULL;
    EC_KEY *ec_key = NULL;
    int keyform = FORMAT_PEM;
    const EVP_MD *md = EVP_sm3();
    
    in  =  BIO_new_file("text.txt", "rb"); 
    out = BIO_new_file("text.sig", "wb");
    
    BIO  * key  =  NULL;
    key = BIO_new_file("private.key", "r");
    pkey=PEM_read_bio_PrivateKey(key, NULL, 0, NULL);

	if (!(ec_key = EVP_PKEY_get0_EC_KEY(pkey))
		|| !EC_KEY_is_sm2p256v1(ec_key)) {
		printf("Invalid key type\n");
		return -1;
	}
    
    sm2utl_sign(md, in, out, "1234567812345678", 0, ec_key, 1);

    return 1;
}

int verify_sig(void)
{
    const EVP_MD *md = EVP_sm3();
    BIO *in = NULL, *out = NULL, *sig = NULL;
    
    in  =  BIO_new_file("text.txt", "rb"); 
    sig = BIO_new_file("text_1.sig", "rb");

    //FILE *fp = fopen("public_cert.pem", "r");
    //X509 *cert = PEM_read_X509(fp, NULL, NULL, NULL);
    FILE *fp = fopen("public.cer", "r");
    X509 *cert = d2i_X509_fp(fp, NULL);

    EVP_PKEY *evk = X509_get_pubkey(cert);
    EC_KEY *ec_key=EVP_PKEY_get0_EC_KEY(evk);
    if (1==sm2utl_verify(md, in, out, sig, "1234567812345678", 0, ec_key))
    {
        printf("verify success\n");
    }
    else
    {
        printf("verify fail\n");
    }
    return 1;
}

void main(void)
{
    signature("1234567890123456");
    //verify_sig();
}

In the SM2 signature and verification process, the digest of the signed data is not directly calculated, but the digest is obtained through a special preprocessing process. This process consists of two stages of summary calculation:

1)Z = SM3(ENTL || ID || a || b || x_G || y_G || x_A || y_A)

ENTL || ID || a || b || x_G || y_G || x_A || y_A represents the splicing (cascade) of signature element data.

Among them, ENTL is the bit length of the signer ID, which occupies two bytes; ID is the signer ID, the default signer ID defined in the national secret standard is represented by the UFT_8 string as "1234567812345678", expressed in hexadecimal It is 0x31323334353637383132333435363738. So by default, the ENTL value is 0x0080.a, b, x_G, y_G are all the values ​​given in the SM2 algorithm standard. a and b are the coefficients of the elliptic curve y=x+ax+b, and x_G, y_G are the coordinates of the base point selected by the SM2 algorithm. The above parameters are all fixed values: a=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC

b=0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93

x_G= 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7

y_G = 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0

x_A || y_A is the concatenation of the two parts of the public key. Note that there is no part of 0x04; perform the SM3 operation on the concatenated values ​​of the above elements to get the result Z. 2) H=SM3(Z || M)

Z is the digest obtained in the first step of the calculation, and M is the original text of the signature. Join the two together, and then perform the SM3 digest calculation. The obtained digest is the result of preprocessing, which will be used in subsequent signature and verification operations.

reference:

https://www.pianshen.com/article/2043152732/
https://github.com/guanzhi/GmSSL/

https://baijiahao.baidu.com/s?id=1674018830496556781&wfr=spider&for=pc

Guess you like

Origin blog.csdn.net/eidolon_foot/article/details/111036065