SM3WithSM2摘要的SM2签名验签

这个代码有可能不符合国标。。。

#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;
}

参考:

https://nycko.gitee.io/nycko-pages/c++/GmSsl-SM2.html

猜你喜欢

转载自blog.csdn.net/eidolon_foot/article/details/110876657
sm2