sm2椭圆曲线公钥密码算法,完整c代码,前人栽树,后人乘凉

张志翔̮ 张志翔̮     2023-03-16     371

关键词:

某电信安信息安全数学基础实验要求实现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]);
		else
			printf("%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);    //生成随机数key1
       ecurve_mult(key1,g,pB);   //pB=key1*g
       epoint_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传入buf
	memcpy(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个0
			break;
	
 
	if(i < klen)
		return 1;   //kbuf(t)中的bit全是0, kdf判断通过,执行下一步C2=M异或t
	else
		return 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 p
	g=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,y
	bytes_to_big(wylen,(char *)wy,y);
	epoint_set(x,y,0,pb);                          //=(x1,y1)
       
	
	  //选择小于n的随机数k
	irand(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,y1
	big_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*pb
	epoint_get(kpb, x2, y2);   //从kpb得到x2,y2
 
 
	big_to_bytes(32, x2, (char *)zl, TRUE);   //把大数x2,y2变为字节放入zl,zr
	big_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和y
	bytes_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*c1
	epoint_get(dBC1, x2, y2);    //从dBC1中读取x2,y2
 
	big_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,yb
	printf("加密结果: ");
	Buf_Out(etx, 64+msglen+32);   
	decrypt(etx,64+msglen+32,dB,32,mtx);  //传入密文与私钥pb
	if(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"
#endif
 
int 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 0
 
int 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_SM3
	PrintBuf(md, 32);
#endif
 
	memset(md, 0, sizeof(md));
	sm3(data1, 64, md);
#if DEBUG_SM3
	PrintBuf(md, 32);
#endif
 
	start = 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     56
 
typedef 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椭圆曲线公钥密码算法

...其中的原理 国家密码管理局于2010年12月17日发布了SM2椭圆曲线公钥密码算法,并要求为对现有基于RSA算法的电子认证系统、密钥管理系统、应用系统进行升级改造。关于算法标准,请参见《国家密码管理局公告(第21号)》... 查看详情

003国密算法【技术】

...非对称加密算法(公钥算法),加密强度为256位,是一种椭圆曲线算法。公钥密码学与其他密码学完全不同,使用这种方法的加密系统,不仅公开加密算法本身,也公开了加密用的密钥。公钥密码系统与只使用一个密钥的对称传... 查看详情

sm2国密ssl证书为https加密提速

...是我国自主设计的公钥密码算法。SM2基于更加安全先进的椭圆曲线密码机制,在国际标准的ECC椭圆曲线密码理论基础上进行改进而来,其加密强 查看详情

sm系列国密算法(转)

...应用领域(包括国家政务通、警务通等重要领域)。2SM2椭圆曲线公钥密码算法SM2算法就是ECC椭圆曲线密码机制,但在签名、密钥交换方面不同于ECDSA、ECDH等国际标准,而是采取了更为安全的机制。另外,SM2推荐了一条256位的曲... 查看详情

密码学系列-国密sm2为什么不支持恢复公钥(代码片段)

...,EOS之类的公链代码底层密码库替换成国密库,因为它们的椭圆曲线验签采用的都是recover模式,而非verify模式.verify模式:输入签名,消息摘要,公钥;输出是否是该公钥对应的私钥做的签名recover模式:输入签名,消息摘要,recoverid;输出签名... 查看详情

密码学系列-国密sm2为什么不支持恢复公钥(代码片段)

...,EOS之类的公链代码底层密码库替换成国密库,因为它们的椭圆曲线验签采用的都是recover模式,而非verify模式.verify模式:输入签名,消息摘要,公钥;输出是否是该公钥对应的私钥做的签名recover模式:输入签名,消息摘要,recoverid;输出签名... 查看详情

椭圆曲线密码学(代码片段)

椭圆曲线密码学是下一代的公钥密码学,它比之前的公钥密码学系统例如RSA和Diffe-Hellman在安全性方面有显著提高。椭圆曲线密码学是目前被广泛使用的最强大的密码学算法之一,但是真正理解其工作原理的开发者并不多... 查看详情

椭圆曲线密码学ecc

??椭圆曲线密码学(Ellipticcurvecryptography),简称ECC,是一种建立公开密钥加密的算法,也就是非对称加密。类似的还有RSA,ElGamal算法等。ECC被公认为在给定密钥长度下最安全的加密算法。比特币中的公私钥生成以及签名算法ECDSA... 查看详情

信息安全工程师笔记-国产密码算法(国密)概念

国产密码算法国产密码算法有SM1分组密码算法、SM2椭圆曲线公钥密码算法、SM3密码杂凑算法、SM4分组算法、SM9标识密码算法。算法名称算法特征描述SM1对称加密,分组长度和密钥长度都为128比特SM2非对称加密,用于公钥... 查看详情

2017-2018-220179216《网络攻防与实践》sm234算法

国密商用算法是指国密SM系列算法,包括基于椭圆曲线的非对称公钥密码SM2算法、密码杂凑SM3算法、分组密码SM4算法,还有只以IP核形式提供的非公开算法流程的对称密码SM1算法等。国密即国家密码局认定的国产密码算法。主要... 查看详情

libsecp256k1比特币密码算法开源库(代码片段)

2021SC@SDUSClibsecp256k1代码分析综述有限域GaloisField椭圆曲线EllipticCurves椭圆曲线几何加法椭圆曲线标量乘法从本篇开始我将开始分析libsecp256k1中的代码。本开源库可以实现:私钥经标量乘法生成公钥;私钥签名(ECDSA&#... 查看详情

密码学——公钥密码体系之背包算法1(代码片段)

...解难解性(RSA)离散对数难解性(ElGamal)椭圆曲线离散对数难解性(ECC)1.背包算法本次介绍的并不是以上三种类型的公钥密码 查看详情

centos7编译安装openssl1.1.1支持国密标准(代码片段)

OpenSSL项目新版本增加了中国SM2/SM3/SM4算法的支持:SM2椭圆曲线:https://github.com/openssl/openssl/pull/4793SM3哈希摘要:https://github.com/openssl/openssl/pull/4616SM4对称加密:https://github.com/openssl/openssl/pull/4552参考:中国×××制定的商业密码算法标准《G... 查看详情

国密算法介绍

...。2010年底,国家密码管理局公布了我国自主研制的“椭圆曲线公钥密码算法”(SM2算法)。为保障重要经济系统密码应用安全,国家密码管理局于2011年发布了《关于做好公钥密码算法升级工作的通知》,要求... 查看详情

国密算法介绍

...。2010年底,国家密码管理局公布了我国自主研制的“椭圆曲线公钥密码算法”(SM2算法)。为保障重要经济系统密码应用安全,国家密码管理局于2011年发布了《关于做好公钥密码算法升级工作的通知》,要求... 查看详情

算法2_非对称加密算法之ecdsa(椭圆曲线数字签名算法)(代码片段)

ECDSA(椭圆曲线数字签名算法)AES(高级加密标准):=>对称加密​对业务数据进行加密,防止他人可以看见ECDSA(椭圆曲线数字签名算法):=>非对称加密算法(公钥和私钥)​验证数据的真实性,防止业务数据被篡改SHA(安全哈希算法)... 查看详情

国密算法

...RSA2048位高,但运算速度快于RSA。国家密码管理局公布的公钥算法,其加密强度为256位SM3消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。SM4无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度... 查看详情

椭圆曲线算法:简单介绍(代码片段)

椭圆曲线首先:什么是椭圆曲线,WolframMathWorld提供了出色而完整的定义。但是对于我们的目标,椭圆曲线将简单表示为方程式所描述的点集:y^2=x^3+ax+b其中4a^3+27b^2!=0需要排除特殊曲线。上面的等式是椭圆曲线的Weierstrass范式。... 查看详情