1. 程式人生 > >SM2橢圓曲線公鑰密碼演算法,完整c程式碼,前人栽樹,後人乘涼

SM2橢圓曲線公鑰密碼演算法,完整c程式碼,前人栽樹,後人乘涼

某電信安資訊保安數學基礎實驗要求實現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)))