某电信安信息安全数学基础实验要求实现SM2椭圆曲线公钥密码算法

这是基于mircal库实现的,没有mircal库的下载我以前的博客发的文件,根据教程在vs上搭建。

一共四个文件  SM2.c SM2.h SM3.c SM3.h

SM2.c

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <time.h>
#include<string.h>
#include "sm2.h"void Buf_Out(unsigned char *buf, int  buflen) //每32项为一行输出buf
{int i;printf("\n");for (i = 0; i < buflen; i++) {if (i % 32 != 31)printf("%02x", buf[i]);elseprintf("%02x\n", buf[i]);}printf("\n");return;
}
#define SEED_CONST 0x1BD8C95A
struct QXCS
{char *p;//椭圆曲线的参数char *a;char *b;char *n;  //G的阶char *x;   //g=(x,y)char *y;
};struct QXCS pdf = {"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF","FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93","FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7","BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0",
};//接收方B的私钥和公钥产生
void sm2_keygen(unsigned char *wx, int *wxlen, unsigned char *wy, int *wylen,unsigned char *privkey, int *privkeylen)
{struct QXCS *cfig = &pdf;epoint *g,*pB;big a,b,p,n,x,y,key1;miracl *mip = mirsys(20,0);   //初始化大数系统mip->IOBASE = 16;   //输入为16进制数改为大数p = mirvar(0);a = mirvar(0);b = mirvar(0);n = mirvar(0);x = mirvar(0);y = mirvar(0);key1 = mirvar(0);cinstr(p,cfig->p);      //将大数字符串转换成大数,这里是16进制的字符串转换大数cinstr(a,cfig->a);cinstr(b,cfig->b);cinstr(n,cfig->n);cinstr(x,cfig->x);cinstr(y,cfig->y);ecurve_init(a,b,p,MR_PROJECTIVE);   //初始化椭圆曲线g = epoint_init();pB = epoint_init();epoint_set(x,y,0,g);    //g=(x,y)为基点G//产生私钥irand(time(NULL)+SEED_CONST);   //初始化种子bigrand(n,key1);    //生成随机数key1ecurve_mult(key1,g,pB);   //pB=key1*gepoint_get(pB,x,y);    //取pB上的点(x,y)x和y即为公钥*wxlen = big_to_bytes(0, x, (char *)wx, FALSE);    //公钥写入wx,长度wxlen*wylen = big_to_bytes(0, y, (char *)wy, FALSE);*privkeylen = big_to_bytes(0, key1, (char *)privkey, FALSE);mirkill(key1);mirkill(p);mirkill(a);mirkill(b);mirkill(n);mirkill(x);mirkill(y);epoint_free(g);epoint_free(pB);mirexit();
}int kdf(unsigned char *zl, unsigned char *zr, int klen, unsigned char *kbuf)  //zl,zr为(x2,y2)
{                                          unsigned char buf[70];unsigned char digest[32];unsigned int ct = 0x00000001;int i, m, n;unsigned char *p;memcpy(buf, zl, 32);                   //把x2,y2传入bufmemcpy(buf+32, zr, 32);m = klen / 32;n = klen % 32;p = kbuf;for(i = 0; i < m; i++)       //buf 64-70{buf[64] = (ct >> 24) & 0xFF;   //ct前8位buf[65] = (ct >> 16) & 0xFF;    buf[66] = (ct >> 8) & 0xFF;buf[67] = ct & 0xFF;sm3(buf, 68, p);                       //sm3后结果放在p中p += 32;ct++;}if(n != 0){buf[64] = (ct >> 24) & 0xFF;buf[65] = (ct >> 16) & 0xFF;buf[66] = (ct >> 8) & 0xFF;buf[67] = ct & 0xFF;sm3(buf, 68, digest);}memcpy(p, digest, n);for(i = 0; i < klen; i++){if(kbuf[i] != 0)      //kbuf中有i+1个0break;}if(i < klen)return 1;   //kbuf(t)中的bit全是0, kdf判断通过,执行下一步C2=M异或telsereturn 0;   }int A_encrypt(char *msg,int msglen, char *wx,int wxlen, char *wy,int wylen, char *outmsg)//wx,wy公钥的x,y的坐标
{struct QXCS *cfig = &pdf;big x2, y2, x1, y1, k;big a,b,p,n,x,y;epoint *g, *w, *pb, *c1,*kpb;int ret = -1;int i;unsigned char zl[32], zr[32];unsigned char *tmp;miracl *mip;tmp = malloc(msglen+64);if(tmp == NULL)return -1;mip = mirsys(20, 0);mip->IOBASE = 16;          //读入16进制数p=mirvar(0);a=mirvar(0);b=mirvar(0);n=mirvar(0);x=mirvar(0);y=mirvar(0);k=mirvar(0);x2=mirvar(0); y2=mirvar(0); x1=mirvar(0); y1=mirvar(0); cinstr(p,cfig->p);                    //大数字符串变为大数cinstr(a,cfig->a);cinstr(b,cfig->b);cinstr(n,cfig->n);cinstr(x,cfig->x);cinstr(y,cfig->y);                                   //g=(x,y)ecurve_init(a,b,p,MR_PROJECTIVE);     //椭圆曲线方程初始化  y2 =x3 + Ax + B mod pg=epoint_init();                                   //点坐标初始化pb=epoint_init(); kpb = epoint_init();c1= epoint_init();w= epoint_init();epoint_set(x,y,0,g);                             //点坐标设置  g=(x,y),现在无值bytes_to_big(wxlen,(char *)wx,x);       //把公钥wx和wy赋值给x,ybytes_to_big(wylen,(char *)wy,y);epoint_set(x,y,0,pb);                          //=(x1,y1)//选择小于n的随机数kirand(time(NULL)+SEED_CONST);sm2_encrypt_again:     do{bigrand(n, k);             }while(k->len == 0);ecurve_mult(k, g, c1);                 //  点乘c1=k*g(第三个=第一个*第二个)epoint_get(c1, x1, y1);            //从c1里面得到x1,y1big_to_bytes(32, x1, (char *)outmsg, TRUE);big_to_bytes(32, y1, (char *)outmsg+32, TRUE);if(point_at_infinity(pb))          //如果s是无穷点,返回1,报错退出goto exit_sm2_encrypt;ecurve_mult(k, pb, kpb);    //kpb=K*pbepoint_get(kpb, x2, y2);   //从kpb得到x2,y2big_to_bytes(32, x2, (char *)zl, TRUE);   //把大数x2,y2变为字节放入zl,zrbig_to_bytes(32, y2, (char *)zr, TRUE);//t=KDF(x2||y2,klen)if (kdf(zl, zr, msglen, outmsg+64) == 0)  //如果kdf返回的值为0,从头开始重新计算goto sm2_encrypt_again;for(i = 0; i < msglen; i++)     {outmsg[64+i] ^= msg[i];}//tmp=x2 || M| |y2 相连memcpy(tmp, zl, 32);   memcpy(tmp+32, msg, msglen);memcpy(tmp+32+msglen, zr, 32);//C3=outmsg=hash(SM3)(tmp)sm3(tmp, 64+msglen, &outmsg[64+msglen]);ret = msglen+64+32;exit_sm2_encrypt:  //退出释放内存mirkill(x2);  mirkill(y2);  mirkill(x1);  mirkill(y1);  mirkill(k);mirkill(a);  mirkill(b);mirkill(p);  mirkill(n);  mirkill(x);mirkill(y);epoint_free(g);   //释放点内存epoint_free(w);epoint_free(pb);epoint_free(kpb);mirexit();free(tmp);return ret;
}//B收到密文后开始解密运算
int decrypt(char *msg,int msglen, char *privkey, int privkeylen,char *outmsg)
{struct QXCS *cfig = &pdf;big x2, y2, c, k;big a,b,p,n,x,y,key1,dB;epoint *g,*C1,*dBC1;unsigned char c3[32];unsigned char zl[32], zr[32];int i, ret = -1;unsigned char *tmp;miracl *mip;if(msglen < 96)return 0;msglen -= 96;tmp = malloc(msglen+64);if(tmp == NULL)return 0;mip = mirsys(20, 0);mip->IOBASE = 16;x2=mirvar(0); y2=mirvar(0); c=mirvar(0); k = mirvar(0);p = mirvar(0);a = mirvar(0);b = mirvar(0);n = mirvar(0);x = mirvar(0);y = mirvar(0);key1 = mirvar(0);dB= mirvar(0);bytes_to_big(privkeylen,(char *)privkey,dB);cinstr(p,cfig->p);cinstr(a,cfig->a);cinstr(b,cfig->b);cinstr(n,cfig->n);cinstr(x,cfig->x);cinstr(y,cfig->y);ecurve_init(a,b,p,MR_PROJECTIVE);  //初始化椭圆曲线 y2=x3+Ax+B (mod p)g = epoint_init(); dBC1 = epoint_init();C1 = epoint_init();bytes_to_big(32, (char *)msg, x);    //从msg中分别取出32位放入x和ybytes_to_big(32, (char *)msg+32, y);if(!epoint_set(x,y,0,C1))     //初始化点C1=(x,y)点C1=(x,y)是否在椭圆曲线 上goto exit_sm2_decrypt;if(point_at_infinity(C1))     //如果s(test)是无穷远点,报错并退出goto exit_sm2_decrypt;ecurve_mult(dB, C1, dBC1);   //dBC1=dB*c1epoint_get(dBC1, x2, y2);    //从dBC1中读取x2,y2big_to_bytes(32, x2, (char *)zl, TRUE);big_to_bytes(32, y2, (char *)zr, TRUE);if (kdf(zl, zr, msglen, outmsg) == 0)  //判断:t=kdf不是全0,才继续goto exit_sm2_decrypt;for(i = 0; i < msglen; i++)     //M'(outmsg)=C2 ^ t(outmsg){outmsg[i] ^= msg[i+64];//密文从65位开始为c2}memcpy(tmp, zl, 32);memcpy(tmp+32, outmsg, msglen);memcpy(tmp+32+msglen, zr, 32);sm3(tmp, 64+msglen, c3);      if(memcmp(c3, msg+64+msglen, 32) != 0)//判断u=c3则继续goto exit_sm2_decrypt;ret =  msglen;exit_sm2_decrypt:mirkill(x2);  mirkill(y2);  mirkill(c);  mirkill(k);mirkill(p);mirkill(a); mirkill(b); mirkill(n); mirkill(x); mirkill(y); mirkill(key1);mirkill(dB);epoint_free(g);epoint_free(dBC1);mirexit();free(tmp);return ret;
}int main()
{unsigned char dB[32];   //存放私钥unsigned char xB[32];   //存放公钥pb(x,y)unsigned char yB[32];unsigned char tx[256]="0";unsigned char etx[256] ;unsigned char mtx[256] ="0";int j;struct QXCS *cfig = &pdf;printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<SM2椭圆曲线公钥密码>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" );printf("由pdf给出的参数:\n\tp:%s\n\ta:%s\n\tb:%s\n\tn:%s\n\tG(x):%s\n\tG(y):%s\n", cfig->p, cfig->a, cfig->b, cfig->n, cfig->x, cfig->y);FILE *fp;fopen_s(&fp,"7.txt", "r+");fgets(tx, 200, fp);fclose(fp);printf("\n文件中明文为:\n\t%s\n", tx);int msglen = strlen(tx);int wxlen, wylen, privkeylen;sm2_keygen(xB, &wxlen, yB, &wylen, dB, &privkeylen);  //公钥(xB,yB)dB私钥 空值进入,产生公私钥printf("\n\t公钥x坐标:");for (j = 0; j< wxlen; j++)printf("%02x", xB[j]);printf("\n\t公钥y坐标:");for (j = 0; j < wylen; j++)printf("%02x", yB[j]);printf("\n\t私钥:");for (j = 0; j< privkeylen; j++)printf("%02x", dB[j]);printf("\n");A_encrypt(tx,msglen,xB,32,yB,32,etx); //传入明文和公钥xb,ybprintf("加密结果: ");Buf_Out(etx, 64+msglen+32);   decrypt(etx,64+msglen+32,dB,32,mtx);  //传入密文与私钥pbif(decrypt(etx,64+msglen+32,dB,32,mtx) < 0)printf("sm2_decrypt error!\n");else{printf("\n解密结果: ");Buf_Out(mtx, msglen);printf("解密出的明文为:\n\t%s\n", mtx);}return 0;
}

SM2.h

#ifndef __SM2_HEADER_2015_12_28__
#define __SM2_HEADER_2015_12_28__#include "sm3.h"
#include "miracl.h"#ifdef __cplusplus
extern "C"{
#endifint sm3_e(unsigned char *userid, int userid_len, unsigned char *xa, int xa_len, unsigned char *ya, int ya_len, unsigned char *msg, int msg_len, unsigned char *e);
/*
功能:根据用户ID及公钥,求用于签名或验签的消息HASH值
[输入] userid: 用户ID
[输入] userid_len: userid的字节数
[输入] xa: 公钥的X坐标
[输入] xa_len: xa的字节数
[输入] ya: 公钥的Y坐标
[输入] ya_len: ya的字节数
[输入] msg:要签名的消息
[输入] msg_len: msg的字节数
[输出] e:32字节,用于签名或验签
返回值:-1:内存不足0:成功
*/void sm2_keygen(unsigned char *wx,int *wxlen, unsigned char *wy,int *wylen,unsigned char *privkey, int *privkeylen);
/*
功能:生成SM2公私钥对
[输出] wx:   公钥的X坐标,不足32字节在前面加0x00
[输出] wxlen: wx的字节数,32
[输出] wy:   公钥的Y坐标,不足32字节在前面加0x00
[输出] wylen: wy的字节数,32
[输出] privkey:私钥,不足32字节在前面加0x00
[输出] privkeylen: privkey的字节数,32
*/void sm2_sign(unsigned char *hash,int hashlen,unsigned char *privkey,int privkeylen,unsigned char *cr,int *rlen,unsigned char *cs,int *slen);
/*
功能:SM2签名
[输入] hash:    sm3_e()的结果
[输入] hashlen: hash的字节数,应为32
[输入] privkey: 私钥
[输入] privkeylen: privkeylen的字节数[输出] cr:  签名结果的第一部分,不足32字节在前面加0x00。
[输出] rlen:cr的字节数,32
[输出] cs:  签名结果的第二部分,不足32字节在前面加0x00。
[输出] slen:cs的字节数,32
*/int  sm2_verify(unsigned char *hash,int hashlen,unsigned char  *cr,int rlen,unsigned char *cs,int slen, unsigned char *wx,int wxlen, unsigned char *wy,int wylen);
/*
功能:验证SM2签名
[输入] hash:    sm3_e()的结果
[输入] hashlen: hash的字节数,应为32
[输入] cr:  签名结果的第一部分
[输入] rlen:cr的字节数
[输入] cs:  签名结果的第二部分。
[输入] slen:cs的字节数
[输入] wx:   公钥的X坐标
[输入] wxlen: wx的字节数,不超过32字节
[输入] wy:   公钥的Y坐标
[输入] wylen: wy的字节数,不超过32字节
返回值:0:验证失败1:验证通过
*/int  A_encrypt(char *msg,int msglen, char *wx,int wxlen, char *wy,int wylen,char *outmsg);
/*
功能:用SM2公钥加密数据。加密结果比输入数据多96字节!
[输入] msg     要加密的数据
[输入] msglen:msg的字节数
[输入] wx:    公钥的X坐标
[输入] wxlen:  wx的字节数,不超过32字节
[输入] wy:    公钥的Y坐标
[输入] wylen:  wy的字节数,不超过32字节
[输出] outmsg: 加密结果,比输入数据多96字节!,C1(64字节)和C3(32字节)保留前导0x00
返回值:-1:        加密失败msglen+96: 加密成功
*/int  decrypt(char *msg,int msglen, char *privkey, int privkeylen, char *outmsg);
/*
功能:用SM2私钥解密数据。解密结果比输入数据少96字节!
[输入] msg     要解密的数据,是sm2_encrypt()加密的结果,不少于96字节。
[输入] msglen:msg的字节数
[输入] privkey: 私钥
[输入] privkeylen: privkeylen的字节数
[输出] outmsg: 解密结果,比输入数据少96字节!
返回值:-1:        解密失败msglen-96: 解密成功
*/void sm2_keyagreement_a1_3(unsigned char *kx1, int *kx1len, unsigned char *ky1, int *ky1len,unsigned char *ra,  int *ralen);/*
功能:密钥协商的发起方调用此函数产生一对临时公钥(kx1, ky1)和相应的随机数。公钥发送给对方,随机数ra自己保存。
[输出] kx1:   公钥的X坐标,不足32字节在前面加0x00
[输出] kx1len:kx1的字节数,32
[输出] ky1:   公钥的Y坐标,不足32字节在前面加0x00
[输出] ky1len:ky1的字节数,32
[输出] ra:     随机数,不足32字节在前面加0x00
[输出] ralen: ra的字节数,32
返回值:无*/int sm2_keyagreement_b1_9( unsigned char *kx1, int kx1len,unsigned char *ky1, int ky1len,unsigned char *pax, int paxlen,unsigned char *pay, int paylen,unsigned char *private_b,   int private_b_len,unsigned char *pbx, int pbxlen,unsigned char *pby, int pbylen,unsigned char *ida, int idalen,unsigned char *idb, int idblen,unsigned int  kblen,unsigned char *kbbuf,unsigned char *kx2, int *kx2len,unsigned char *ky2, int *ky2len,unsigned char *xv,  int *xvlen,unsigned char *yv,  int *yvlen,unsigned char *sb);/*
功能:密钥协商的接收方调用此函数协商出密钥kbbuf,同时产生一对临时公钥(kx2, ky2)以及(xv, yv)、sb。(kx2, ky2)和sb发送给对方,kbbuf和(xv, yv)自己保存。
说明:
[输入] (kx1, ky1)是发起方产生的临时公钥
[输入] (pax, pay)是发起方的公钥
[输入] private_b是接收方的私钥
[输入] (pbx, pby)是接收方的公钥
[输入] ida是发起方的用户标识
[输入] idb是接收方的用户标识
[输入] kblen是要约定的密钥字节数
[输出] kbbuf是协商密钥输出缓冲区
[输出] (kx2, ky2)是接收方产生的临时公钥,不足32字节在前面加0x00
[输出] (xv, yv)是接收方产生的中间结果,自己保存,用于验证协商的正确性。,不足32字节在前面加0x00。如果(xv, yv)=NULL,则不输出。
[输出] sb是接收方产生的32字节的HASH值,要传送给发起方,用于验证协商的正确性。如果为sb=NULL,则不输出。
返回值:0-失败  1-成功*/int sm2_keyagreement_a4_10( unsigned char *kx1, int kx1len,unsigned char *ky1, int ky1len,unsigned char *pax, int paxlen,unsigned char *pay, int paylen,unsigned char *private_a,   int private_a_len,unsigned char *pbx, int pbxlen,unsigned char *pby, int pbylen,unsigned char *ida, int idalen,unsigned char *idb, int idblen,unsigned char *kx2, int kx2len,unsigned char *ky2, int ky2len,unsigned char *ra,  int ralen,unsigned int  kalen,unsigned char *kabuf,unsigned char *s1,unsigned char *sa);/*
功能:密钥协商的发起方调用此函数协商出密钥kabuf,同时产生s1和sa。s1和kabuf自己保存,sa发送给接收方,用于确认协商过程的正确性。
说明:
[输入] (kx1, ky1)是发起方产生的临时公钥
[输入] (pax, pay)是发起方的公钥
[输入] private_a是发起方的私钥
[输入] (pbx, pby)是接收方的公钥
[输入] ida是发起方的用户标识
[输入] idb是接收方的用户标识
[输入] (kx2, ky2)是接收方产生的临时公钥
[输入] ra是发起方调用sm2_keyagreement_a1_3产生的随机数
[输入] kalen是要约定的密钥字节数
[输出] kabuf是协商密钥输出缓冲区
[输出] s1和sa是发起方产生的32字节的HASH值,s1自己保存(应等于sb),sa要传送给接收方,用于验证协商的正确性。如果s1和sa为NULL,则不输出。
返回值:0-失败  1-成功*/void sm2_keyagreement_b10( unsigned char *pax, int paxlen,unsigned char *pay, int paylen,unsigned char *pbx, int pbxlen,unsigned char *pby, int pbylen,unsigned char *kx1, int kx1len,unsigned char *ky1, int ky1len,unsigned char *kx2, int kx2len,unsigned char *ky2, int ky2len,unsigned char *xv, int xvlen,unsigned char *yv, int yvlen,unsigned char *ida, int idalen,unsigned char *idb, int idblen,unsigned char *s2);
/*
功能:密钥协商的接收方调用此函数产生s2,用于验证协商过程的正确性。
说明:
[输入] (pax, pay)是发起方的公钥
[输入] (pbx, pby)是接收方的公钥
[输入] (kx1, ky1)是发起方产生的临时公钥
[输入] (kx2, ky2)是接收方产生的临时公钥
[输入] (xv, yv)是接收方产生的中间结果
[输入] ida是发起方的用户标识
[输入] idb是接收方的用户标识
[输出] s2是接收方产生的32字节的HASH值,应等于sa。
返回值:无*/
#ifdef __cplusplus
}
#endif#endif

SM3.c

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "sm3.h"void sm3_block(SM3_CTX *ctx)
{int j, k;unsigned long t;unsigned long ss1, ss2, tt1, tt2;unsigned long a, b, c, d, e, f, g, h;unsigned long w[132];for(j = 0; j < 16; j++)w[j] = ctx->data[j];for(j = 16; j < 68; j++){t = w[j-16] ^ w[j-9] ^ ROTATE(w[j-3], 15);w[j] = P1(t) ^ ROTATE(w[j-13], 7) ^ w[j-6];}for(j = 0, k = 68; j < 64; j++, k++){w[k] = w[j] ^ w[j+4];}a = ctx->h[0];b = ctx->h[1];c = ctx->h[2];d = ctx->h[3];e = ctx->h[4];f = ctx->h[5];g = ctx->h[6];h = ctx->h[7];for(j = 0; j < 16; j++){ss1 = ROTATE(ROTATE(a, 12) +  e + ROTATE(TH, j), 7);ss2 = ss1 ^ ROTATE(a, 12);tt1 = FFH(a, b, c) + d + ss2 + w[68 + j];tt2 = GGH(e, f, g) + h + ss1 + w[j];d = c; c = ROTATE(b, 9);b = a;a = tt1;h = g;g = ROTATE(f, 19);f = e;e = P0(tt2);}for(j = 16; j < 33; j++){ss1 = ROTATE(ROTATE(a, 12) +  e + ROTATE(TL, j), 7);ss2 = ss1 ^ ROTATE(a, 12);tt1 = FFL(a, b, c) + d + ss2 + w[68 + j];tt2 = GGL(e, f, g) + h + ss1 + w[j];d = c;c = ROTATE(b, 9);b = a;a = tt1;h = g;g = ROTATE(f, 19);f = e;e = P0(tt2);}for(j = 33; j < 64; j++){ss1 = ROTATE(ROTATE(a, 12) +  e + ROTATE(TL, (j-32)), 7);ss2 = ss1 ^ ROTATE(a, 12);tt1 = FFL(a, b, c) + d + ss2 + w[68 + j];tt2 = GGL(e, f, g) + h + ss1 + w[j];d = c;c = ROTATE(b, 9);b = a;a = tt1;h = g;g = ROTATE(f, 19);f = e;e = P0(tt2);}ctx->h[0]  ^=  a ;ctx->h[1]  ^=  b ;ctx->h[2]  ^=  c ;ctx->h[3]  ^=  d ;ctx->h[4]  ^=  e ;ctx->h[5]  ^=  f ;ctx->h[6]  ^=  g ;ctx->h[7]  ^=  h ;}void SM3_Init (SM3_CTX *ctx)
{ctx->h[0] = 0x7380166fUL;ctx->h[1] = 0x4914b2b9UL;ctx->h[2] = 0x172442d7UL;ctx->h[3] = 0xda8a0600UL;ctx->h[4] = 0xa96f30bcUL;ctx->h[5] = 0x163138aaUL;ctx->h[6] = 0xe38dee4dUL;ctx->h[7] = 0xb0fb0e4eUL;ctx->Nl   = 0;ctx->Nh   = 0;ctx->num  = 0;
}void SM3_Update(SM3_CTX *ctx, const void *data, unsigned int len)
{unsigned char *d;unsigned long l;int i, sw, sc;if (len == 0)return;l = (ctx->Nl + (len << 3)) & 0xffffffffL;if (l < ctx->Nl) /* overflow */ctx->Nh++;ctx->Nh += (len >> 29);ctx->Nl = l;d = (unsigned char *)data;while (len >= SM3_CBLOCK){ctx->data[0] = c_2_nl(d);d += 4;ctx->data[1] = c_2_nl(d);d += 4;ctx->data[2] = c_2_nl(d);d += 4;ctx->data[3] = c_2_nl(d);d += 4;ctx->data[4] = c_2_nl(d);d += 4;ctx->data[5] = c_2_nl(d);d += 4;ctx->data[6] = c_2_nl(d);d += 4;ctx->data[7] = c_2_nl(d);d += 4;ctx->data[8] = c_2_nl(d);d += 4;ctx->data[9] = c_2_nl(d);d += 4;ctx->data[10] = c_2_nl(d);d += 4;ctx->data[11] = c_2_nl(d);d += 4;ctx->data[12] = c_2_nl(d);d += 4;ctx->data[13] = c_2_nl(d);d += 4;ctx->data[14] = c_2_nl(d);d += 4;ctx->data[15] = c_2_nl(d);d += 4;sm3_block(ctx);len -= SM3_CBLOCK;}if(len > 0){memset(ctx->data, 0, 64);ctx->num = len + 1;sw = len >> 2;sc = len & 0x3;for(i = 0; i < sw; i++){ctx->data[i] = c_2_nl(d);d += 4;}switch(sc){case 0:ctx->data[i] = 0x80000000;break;case 1:ctx->data[i] = (d[0] << 24) | 0x800000;break;case 2:ctx->data[i] = (d[0] << 24) | (d[1] << 16) | 0x8000;break;case 3:ctx->data[i] = (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | 0x80;break;}}}void SM3_Final(unsigned char *md, SM3_CTX *ctx)
{if(ctx->num == 0){memset(ctx->data, 0, 64);ctx->data[0] = 0x80000000;ctx->data[14] = ctx->Nh;ctx->data[15] = ctx->Nl;}else{if(ctx->num <= SM3_LAST_BLOCK){ctx->data[14] = ctx->Nh;ctx->data[15] = ctx->Nl;}else{sm3_block(ctx);memset(ctx->data, 0, 56);ctx->data[14] = ctx->Nh;ctx->data[15] = ctx->Nl;}}sm3_block(ctx);nl2c(ctx->h[0], md);nl2c(ctx->h[1], md);nl2c(ctx->h[2], md);nl2c(ctx->h[3], md);nl2c(ctx->h[4], md);nl2c(ctx->h[5], md);nl2c(ctx->h[6], md);nl2c(ctx->h[7], md);
}unsigned char *sm3(const unsigned char *d, unsigned int n, unsigned char *md)
{SM3_CTX ctx;SM3_Init(&ctx);SM3_Update(&ctx, d, n);SM3_Final(md, &ctx);memset(&ctx, 0, sizeof(ctx));return(md);
}#if 0int main()
{unsigned char data[] = "abc";/*66c7f0f4 62eeedd9 d1f2d46b dc10e4e2 4167c487 5cf2f7a2 297da02b 8f4ba8e0*/unsigned char data1[] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd";/*debe9ff9 2275b8a1 38604889 c18e5a4d 6fdb70e5 387e5765 293dcba3 9c0c5732*/unsigned char md[SM3_DIGEST_LENGTH];clock_t start,end;double tt;int j;memset(md, 0, sizeof(md));sm3(data, 3, md);
#if DEBUG_SM3PrintBuf(md, 32);
#endifmemset(md, 0, sizeof(md));sm3(data1, 64, md);
#if DEBUG_SM3PrintBuf(md, 32);
#endifstart = clock();for(j=0;j<1000000;j++){sm3(data1, 55, md);}end = clock();tt = (double)(end-start)/CLOCKS_PER_SEC;printf("speed:%lfMbps\n", (double)512/tt);return 0;
}
#endif

SM3.h

#ifndef __SM3_HEADER__
#define __SM3_HEADER__#ifdef __cplusplus
extern "C"{
#endif#define  SM3_LBLOCK         16
#define  SM3_CBLOCK         64
#define  SM3_DIGEST_LENGTH  32
#define  SM3_LAST_BLOCK     56typedef struct SM3state_st
{unsigned long h[8];unsigned long Nl,Nh;unsigned long data[SM3_LBLOCK];unsigned int  num;
} SM3_CTX;void SM3_Init (SM3_CTX *ctx);
void SM3_Update(SM3_CTX *ctx, const void *data, unsigned int len);
void SM3_Final(unsigned char *md, SM3_CTX *ctx);
unsigned char *sm3(const unsigned char *d, unsigned int n, unsigned char *md);
/*
d:  data
n:  byte length
md: 32 bytes digest
*/#ifdef __cplusplus
}
#endif#endif#define nl2c(l,c)   (*((c)++) = (unsigned char)(((l) >> 24) & 0xff), \*((c)++) = (unsigned char)(((l) >> 16) & 0xff), \*((c)++) = (unsigned char)(((l) >> 8)  & 0xff), \*((c)++) = (unsigned char)(((l)    )   & 0xff))#define c_2_nl(c)  ((*(c) << 24) | (*(c+1) << 16) | (*(c+2) << 8) | *(c+3))
#define ROTATE(X, C) (((X) << (C)) | ((X) >> (32 - (C))))#define TH 0x79cc4519
#define TL 0x7a879d8a
#define FFH(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define FFL(X, Y, Z) (((X) & (Y)) | ((X) & (Z)) | ((Y) & (Z)))
#define GGH(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define GGL(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
#define P0(X)  ((X) ^ (((X) << 9) | ((X) >> 23)) ^ (((X) << 17) | ((X) >> 15)))
#define P1(X)  ((X) ^ (((X) << 15) | ((X) >> 17)) ^ (((X) << 23) | ((X) >> 9)))

SM2 椭圆曲线公钥密码算法,完整c代码,前人栽树,后人乘凉相关推荐

  1. 国密算法Go语言实现(详解)(九) ——SM2(椭圆曲线公钥密码算法)

    国密算法Go语言实现(详解)(九) --SM2(椭圆曲线公钥密码算法) 原创代码:https://github.com/ZZMarquis/gm 引用时,请导入原创代码库.本文仅以注释方式详解代码逻辑 ...

  2. SM2椭圆曲线公钥密码算法(Python实现)

    本文目录 一.实验目的(包括实验环境.实现目标等等) 1. 实验环境 2. 实现目标 3. 实验中需要导入的库 二.方案设计(包括背景.原理.必要的公式.图表.算法步骤等等) 1. 实验背景 2. 实 ...

  3. 国密算法Go语言实现(详解)(十) ——SM2(椭圆曲线公钥密码算法)

    国密算法Go语言实现(详解)(十) --SM2(椭圆曲线公钥密码算法) 原创代码:https://github.com/ZZMarquis/gm 引用时,请导入原创代码库.本文仅以注释方式详解代码逻辑 ...

  4. SM2椭圆曲线公钥密码算法的C语言实现(基于Miracl大数运算库)

    SM2椭圆曲线公钥密码算法的C语言实现(基于Miracl大数运算库) 实验环境 预备知识 FpF_pFp​ 及椭圆曲线 素域 FpF_pFp​ FpF_pFp​ 上的椭圆曲线 FpF_pFp​ 上椭圆 ...

  5. GMSSL :SM2椭圆曲线公钥密码算法——数字签名算法1

    2021SC@SDUSC 一.相关术语以及定义 二.数字签名算法 1.辅助函数 密码杂凑算法和随机数发生器 杂凑运算:这个输出串称为该消息的杂凑值. 就是一种可将一个 key 对应到一个索引的函数,一 ...

  6. 12、SM2椭圆曲线公钥密码算法

    参考推荐: 国家密码管理局关于发布<SM2椭圆曲线公钥密码算法>公告(国密局公告第21号)_国家密码管理局 https://blog.csdn.net/u013137970/article ...

  7. GMSSL :SM2椭圆曲线公钥密码算法——数字签名算法4

    2021SC@SDUSC 目录 一.ECDSA介绍 二.代码分析 一.ECDSA介绍 ECDSA的全名是Elliptic Curve DSA,即椭圆曲线DSA.它是Digital Signature ...

  8. SM2椭圆曲线公钥密码算法的JAVA实现

    2019独角兽企业重金招聘Python工程师标准>>> package com.zpc.cryptography;import java.io.ByteArrayInputStrea ...

  9. GMSSL :SM2椭圆曲线公钥密码算法-密钥交换协议

    2021SC@SDUSC 目录 一.整体架构 二.具体分析 前一篇文章写了密钥交换协议的基本流程,这一篇文章看一下代码实现 一.整体架构 整体来看这一部分有6个函数,相对重要的是序号3,4代表的函数 ...

  10. SM2国密算法公钥解压缩

    SM2一般用到的或者第三方提供的公钥都是压缩过的,长度为66个长度,既33字节. 格式如下,保密期间秘钥内容用*代替了,从02到....3F3B共33字节.66个长度 06:028736002931F ...

最新文章

  1. 绝地求生现在服务器稳定吗,吃鸡服务器不稳定?《绝地求生》国服宣布将首次使用超性能服务器...
  2. vsftpd学习笔记
  3. do filtering will real delete note in DB
  4. 7-45 航空公司VIP客户查询 (25 分)(思路+详解+map用法解释+超时解决)兄弟们来呀冲压呀呀呀呀
  5. 队列和消息队列_消息队列概述[幻灯片]
  6. class触发后让另一个class加样式_Bootstrap的按钮组样式
  7. 这部日本「神作」彻底拉低了我入门AI的门槛
  8. (93)异步FIFO结构,为什么用格雷码? ,面试必问(十七)(第19天)
  9. kettle的变量空间接口VariableSpace实现与委托模式
  10. Linux Kernel 5.13 稳定版发布:初步支持 M1 芯片
  11. Linux内核协议栈分析之网卡初始化——tcp/ip通信并不神秘(1)
  12. 安装CentOS7虚拟机
  13. 3ds max 2020 vray 5.0 渲染设置
  14. matlab根据直方图求均值方差_matlab求方差,均值,均方差,协方差的函数
  15. rainmeter 皮肤_Rainmeter入门指南:在桌面上显示系统统计信息
  16. Python3入门视频教程百度网盘
  17. Select, Supplement and Focus for RGB-D Saliency Detection CVPR2020 卢湖川团队
  18. 视频接口:DP接口和HDMI接口介绍,看完你就懂了
  19. word 条件多项式公式对齐
  20. $%7BpageContext.request.contextPath%7D

热门文章

  1. word文档设置页眉页脚的技巧
  2. linux修改hostid
  3. C++ 使用GDI+剪切图片
  4. Android中的PCM设备
  5. WindowsMac本地搭建Code-Push-Server热更新服务器
  6. win的名词_英语语法系列:名词性从句
  7. 攻防世界-misc高手进阶篇-2017_Dating_in_Singapore
  8. 全奖热招 | TUM、HKU、McGill、UTS等8所高校全奖博士招生信息汇总
  9. 记关于DNS协议的一次学习(递归查询与迭代查询)
  10. Post-processing of merged bean definition failed; spring cloud Eureka 启动报错