SM3WithSM2摘要的SM2簽名驗籤
阿新 • • 發佈:2020-12-09
技術標籤:gmssl
#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> int hashForSM3(unsigned char* clearText, int clearTextLen, unsigned char* sm3Data){ int ret = -1; //初始化摘要結構體 EVP_MD_CTX *mdctx = EVP_MD_CTX_create(); if(!mdctx) return -1; EVP_MD_CTX_init(mdctx); //設定摘要演算法和密碼演算法引擎 if(!EVP_DigestInit_ex(mdctx, EVP_sm3(), NULL)) goto ERR; //輸入原文clearText if(!EVP_DigestUpdate(mdctx,clearText, clearTextLen)) goto ERR; //輸出摘要值,外部判斷ret是否為32作為成功條件 if(!EVP_DigestFinal(mdctx, sm3Data, (unsigned int*)&ret)) goto ERR; ERR: EVP_MD_CTX_destroy(mdctx); return ret; } int hashForSM3WithSM2(unsigned char* clearText, int clearTextLen, unsigned char* puk, int pukLen, unsigned char* sm3Data){ //以下為國密標準推薦引數,id="1234567812345678",長度是128bit則0x0080 unsigned char sm2_par_dig[210] = {//idlen[2]+id[16]+parm[128]+puk[64] 0x00,0x80, 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC, 0x28,0xE9,0xFA,0x9E,0x9D,0x9F,0x5E,0x34,0x4D,0x5A,0x9E,0x4B,0xCF,0x65,0x09,0xA7, 0xF3,0x97,0x89,0xF5,0x15,0xAB,0x8F,0x92,0xDD,0xBC,0xBD,0x41,0x4D,0x94,0x0E,0x93, 0x32,0xC4,0xAE,0x2C,0x1F,0x19,0x81,0x19,0x5F,0x99,0x04,0x46,0x6A,0x39,0xC9,0x94, 0x8F,0xE3,0x0B,0xBF,0xF2,0x66,0x0B,0xE1,0x71,0x5A,0x45,0x89,0x33,0x4C,0x74,0xC7, 0xBC,0x37,0x36,0xA2,0xF4,0xF6,0x77,0x9C,0x59,0xBD,0xCE,0xE3,0x6B,0x69,0x21,0x53, 0xD0,0xA9,0x87,0x7C,0xC6,0x2A,0x47,0x40,0x02,0xDF,0x32,0xE5,0x21,0x39,0xF0,0xA0, }; //對應規範pdf中的章節8.1 memcpy(sm2_par_dig + 2 + 16 + 128, puk, pukLen); unsigned char* sm3_e = (unsigned char*)malloc(32 + clearTextLen); if(32 != hashForSM3(sm2_par_dig, 210, sm3_e)){ free(sm3_e); return -1; } //對應規範pdf中的章節8.2 memcpy(sm3_e + 32, clearText, clearTextLen); if(32 != hashForSM3(sm3_e, 32 + clearTextLen, sm3Data)){ free(sm3_e); return -1; } free(sm3_e); return 0; } int main(){ int i = 0; BIO *bio_pri = NULL; BIO *bio_puk = NULL; EVP_PKEY *pkey_pri = NULL; EC_KEY *prikey = NULL; EVP_PKEY *pkey_puk = NULL; EC_KEY *pubkey = NULL; X509 *cert = NULL; unsigned char* puk = NULL; int pukLen = 0; unsigned char* clearText = (unsigned char*)"1234567890123456"; int clearTextLen = strlen((char*)clearText); unsigned char sm3Data[32] = {0}; int sm3DataLen = 0; unsigned char out[1024] = {0}; int outLen = 0; ///公鑰相關結構 //bio_puk = BIO_new_file("server_cert.der", "r"); bio_puk = BIO_new_file("server_cert.pem", "r"); if (!bio_puk) goto ERR; //cert = d2i_X509_bio(bio_puk, NULL); cert = PEM_read_bio_X509(bio_puk, NULL, NULL, NULL); if (!cert) goto ERR; pkey_puk = X509_get_pubkey(cert); if (!pkey_puk) goto ERR; pubkey = EVP_PKEY_get0_EC_KEY(pkey_puk);//don't free if (!pubkey) goto ERR; //要去除04標識 pukLen = i2d_PublicKey(pkey_puk,(unsigned char**)&puk) - 1; if (!puk) goto ERR; ///私鑰相關結構 bio_pri = BIO_new_file("server_private.key", "r"); if (!bio_pri) goto ERR; pkey_pri = PEM_read_bio_PrivateKey(bio_pri, NULL, NULL, NULL); if (!pkey_pri) goto ERR; prikey = EVP_PKEY_get0_EC_KEY(pkey_pri);//don't free if (!prikey) goto ERR; ///sm3 sm2 sign/verify if(hashForSM3WithSM2(clearText, clearTextLen, puk, pukLen, sm3Data)) goto ERR; if (!SM2_sign(NID_undef, sm3Data, sm3DataLen, out, (unsigned int*)&outLen, prikey)) goto ERR; printf("out[%d]:\n", outLen); for (int i = 0; i != outLen; i++) { printf("%02x ", *(out + i)); if ((i != 0 && (i + 1) % 16 == 0) || i == outLen - 1) { printf("\n"); } } printf("\n"); FILE *fp_w = fopen("server_16.sig", "wb"); for(int i=0; i < outLen; i++) { fwrite(((unsigned char*)(out+i)), 1, 1, fp_w); } fclose(fp_w); FILE *fp_r = fopen("server_16.sig", "rb"); size_t slen = 0; fseek(fp_r, 0, SEEK_SET); int nRet; for(int i=0; ; i++) { nRet=fread(&(out[i]), 1, 1, fp_r); if(1 != nRet) { break; } printf("%02x ",out[i]); slen++; } fclose(fp_r); if (1 != SM2_verify(NID_undef, sm3Data, sm3DataLen, out, outLen, pubkey)) goto ERR; printf("verify success\n"); ERR: if(puk) OPENSSL_free(puk); if(bio_pri) BIO_free_all(bio_pri); if(bio_puk) BIO_free_all(bio_puk); if(pkey_pri) EVP_PKEY_free(pkey_pri); if(pkey_puk) EVP_PKEY_free(pkey_puk); if(cert) X509_free(cert); return 0; }
參考: