SM9-加解密


算法过程

           

             

程序实现

///************************************************************************ 
//  File name:    SM9_enc_dec.c 
//  Version:      SM9_enc_dec_V1.0 
//  Date:         Dec 29,2016 
//  Description:  implementation of SM9 encryption algorithm and decryption algorithm 
//                all operations based on BN curve line function 
//  Function List: 
//        1.bytes128_to_ecn2        //convert 128 bytes into ecn2 
//        2.zzn12_ElementPrint      //print all element of struct zzn12 
//        3.ecn2_Bytes128_Print     //print 128 bytes of ecn2 
//        4.LinkCharZzn12           //link two different types(unsigned char and zzn12)to one(unsigned char) 
//        5.Test_Point              //test if the given point is on SM9 curve 
//        6.SM4_Block_Encrypt       //encrypt the message with padding,according to PKS#5 
//        7.SM4_Block_Decrypt       //decrypt the cipher with padding,according to PKS#5 
//        8.SM9_H1                  //function H1 in SM9 standard 5.4.2.2 
//        9.SM9_Enc_MAC             //MAC in SM9 standard 5.4.5 
//        10.SM9_Init               //initiate SM9 curve 
//        11.SM9_GenerateEncryptKey //generate encrypted private and public key 
//        12.SM9_Encrypt            //SM9 encryption algorithm 
//        13.SM9_Decrypt            //SM9 decryption algorithm 
//        14.SM9_SelfCheck()        //SM9 slef-check 

// 
// Notes: 
// This SM9 implementation source code can be used for academic, non-profit making or non-commercial use only. 
// This SM9 implementation is created on MIRACL. SM9 implementation source code provider does not provide MIRACL library, MIRACL license or any permission to use MIRACL library. Any commercial use of MIRACL requires a license which may be obtained from Shamus Software Ltd. 

//**************************************************************************/ 
#include "SM9_enc_dec.h" 
#include "kdf.h" 
#include "SM4.h" 

/****************************************************************
Function:       bytes128_to_ecn2
Description:    convert 128 bytes into ecn2
Calls:          MIRACL functions
Called By:      SM9_Init,SM9_Decrypt
Input:          Ppubs[]
Output:         ecn2 *res
Return:         FALSE: execution error
TRUE: execute correctly
Others:
****************************************************************/
BOOL bytes128_to_ecn2(unsigned char Ppubs[], ecn2 *res)
{
	zzn2 x, y;
	big a, b;
	ecn2 r;
	r.x.a = mirvar(0); r.x.b = mirvar(0);
	r.y.a = mirvar(0); r.y.b = mirvar(0);
	r.z.a = mirvar(0); r.z.b = mirvar(0);
	r.marker = MR_EPOINT_INFINITY;

	x.a = mirvar(0); x.b = mirvar(0);
	y.a = mirvar(0); y.b = mirvar(0);
	a = mirvar(0); b = mirvar(0);

	bytes_to_big(BNLEN, Ppubs, b);
	bytes_to_big(BNLEN, Ppubs + BNLEN, a);
	zzn2_from_bigs(a, b, &x);
	bytes_to_big(BNLEN, Ppubs + BNLEN * 2, b);
	bytes_to_big(BNLEN, Ppubs + BNLEN * 3, a);
	zzn2_from_bigs(a, b, &y);

	return ecn2_set(&x, &y, res);
}
/****************************************************************
Function:       zzn12_ElementPrint
Description:    print all element of struct zzn12
Calls:          MIRACL functions
Called By:      SM9_Encrypt,SM9_Decrypt
Input:          zzn12 x
Output:         NULL
Return:         NULL
Others:
****************************************************************/
void zzn12_ElementPrint(zzn12 x)
{
	big tmp;
	tmp = mirvar(0);

	redc(x.c.b.b, tmp); cotnum(tmp, stdout);
	redc(x.c.b.a, tmp); cotnum(tmp, stdout);
	redc(x.c.a.b, tmp); cotnum(tmp, stdout);
	redc(x.c.a.a, tmp); cotnum(tmp, stdout);
	redc(x.b.b.b, tmp); cotnum(tmp, stdout);
	redc(x.b.b.a, tmp); cotnum(tmp, stdout);
	redc(x.b.a.b, tmp); cotnum(tmp, stdout);
	redc(x.b.a.a, tmp); cotnum(tmp, stdout);
	redc(x.a.b.b, tmp); cotnum(tmp, stdout);
	redc(x.a.b.a, tmp); cotnum(tmp, stdout);
	redc(x.a.a.b, tmp); cotnum(tmp, stdout);
	redc(x.a.a.a, tmp); cotnum(tmp, stdout);
}

/****************************************************************
Function:       ecn2_Bytes128_Print
Description:    print 128 bytes of ecn2
Calls:          MIRACL functions
Called By:      SM9_Encrypt,SM9_Decrypt
Input:          ecn2 x
Output:         NULL
Return:         NULL
Others:
****************************************************************/
void ecn2_Bytes128_Print(ecn2 x)
{
	big tmp;
	tmp = mirvar(0);

	redc(x.x.b, tmp); cotnum(tmp, stdout);
	redc(x.x.a, tmp); cotnum(tmp, stdout);
	redc(x.y.b, tmp); cotnum(tmp, stdout);
	redc(x.y.a, tmp); cotnum(tmp, stdout);
}
/****************************************************************
Function:       LinkCharZzn12
Description:    link two different types(unsigned char and zzn12)to one(unsigned char)
Calls:          MIRACL functions
Called By:      SM9_Encrypt,SM9_Decrypt
Input:          message:
len:    length of message
w:      zzn12 element
Output:         Z:      the characters array stored message and w
Zlen:   length of Z
Return:         NULL
Others:
****************************************************************/
void LinkCharZzn12(unsigned char *message, int len, zzn12 w, unsigned char *Z, int Zlen)
{
	big tmp;

	tmp = mirvar(0);

	memcpy(Z, message, len);
	redc(w.c.b.b, tmp); big_to_bytes(BNLEN, tmp, Z + len, 1);
	redc(w.c.b.a, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN, 1);
	redc(w.c.a.b, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 2, 1);
	redc(w.c.a.a, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 3, 1);
	redc(w.b.b.b, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 4, 1);
	redc(w.b.b.a, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 5, 1);
	redc(w.b.a.b, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 6, 1);
	redc(w.b.a.a, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 7, 1);
	redc(w.a.b.b, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 8, 1);
	redc(w.a.b.a, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 9, 1);
	redc(w.a.a.b, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 10, 1);
	redc(w.a.a.a, tmp); big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 11, 1);
}
/****************************************************************
Function:       Test_Point
Description:    test if the given point is on SM9 curve
Calls:
Called By:      SM9_Decrypt
Input:          point
Output:         null
Return:         0: success
1: not a valid point on curve

Others:
****************************************************************/
int Test_Point(epoint* point)
{
	big x, y, x_3, tmp;
	epoint *buf;

	x = mirvar(0); y = mirvar(0);
	x_3 = mirvar(0);
	tmp = mirvar(0);
	buf = epoint_init();

	//test if y^2=x^3+b 
	epoint_get(point, x, y);
	power(x, 3, para_q, x_3);     //x_3=x^3 mod p 
	multiply(x, para_a, x);
	divide(x, para_q, tmp);
	add(x_3, x, x);                  //x=x^3+ax+b 
	add(x, para_b, x);
	divide(x, para_q, tmp);          //x=x^3+ax+b mod p 
	power(y, 2, para_q, y);        //y=y^2 mod p 
	if (mr_compare(x, y) != 0)
		return 1;

	//test infinity 
	ecurve_mult(N, point, buf);
	if (point_at_infinity(buf) == FALSE)
		return 1;

	return 0;
}

/***************************************************************
Function:       SM4_Block_Encrypt
Description:    encrypt the message with padding,according to PKS#5
Calls:          SM4_Encrypt
Called By:      SM9_Encrypt
Input:
key:the key of SM4
message:data to be encrypted
mlen:   the length of message
Output:
cipher: ciphertext
cipher_len:the length of ciphertext
Return:         NULL
Others:
****************************************************************/
void SM4_Block_Encrypt(unsigned char key[], unsigned char * message, int mlen, unsigned char *cipher, int * cipher_len)
{
	unsigned char mess[16];
	int i, rem = mlen % 16;

	for (i = 0; i= 0; i--)//key[从大到小] 
	{
		premult(i256, ha[i], tmp);
		add(hh, tmp, hh);
		premult(i256, 256, i256);
		divide(i256, n1, tmp);
		divide(hh, n1, tmp);
	}
	incr(hh, 1, h1);
	free(ZH); free(ha);
	return 0;
}

/****************************************************************
Function:       SM9_Enc_MAC
Description:    MAC in SM9 standard 5.4.5
Calls:          SM3_256
Called By:      SM9_Encrypt,SM9_Decrypt
Input:
K:key
Klen:the length of K
M:message
Mlen:the length of message
Output:         C=MAC(K,Z)
Return:         0: success;
1: asking for memory error
Others:
****************************************************************/
int SM9_Enc_MAC(unsigned char *K, int Klen, unsigned char *M, int Mlen, unsigned char C[])
{
	unsigned char *Z = NULL;
	int len = Klen + Mlen;
	Z = (char *)malloc(sizeof(char)*(len + 1));
	if (Z == NULL) return SM9_ASK_MEMORY_ERR;
	memcpy(Z, M, Mlen);
	memcpy(Z + Mlen, K, Klen);
	SM3_256(Z, len, C);

	free(Z);
	return 0;
}

/****************************************************************
Function:       SM9_Init
Description:    Initiate SM9 curve
Calls:          MIRACL functions
Called By:      SM9_SelfCheck
Input:          null
Output:         null
Return:         0: success;
5: base point P1 error
6: base point P2 error
Others:
****************************************************************/
int SM9_Init()
{
	big P1_x, P1_y;

	mip = mirsys(1000, 16);;
	mip->IOBASE = 16;

	para_q = mirvar(0); N = mirvar(0);
	P1_x = mirvar(0);  P1_y = mirvar(0);
	para_a = mirvar(0);
	para_b = mirvar(0); para_t = mirvar(0);
	X.a = mirvar(0);  X.b = mirvar(0);
	P2.x.a = mirvar(0); P2.x.b = mirvar(0);
	P2.y.a = mirvar(0); P2.y.b = mirvar(0);
	P2.z.a = mirvar(0); P2.z.b = mirvar(0);
	P2.marker = MR_EPOINT_INFINITY;

	P1 = epoint_init();
	bytes_to_big(BNLEN, SM9_q, para_q);
	bytes_to_big(BNLEN, SM9_P1x, P1_x);
	bytes_to_big(BNLEN, SM9_P1y, P1_y);
	bytes_to_big(BNLEN, SM9_a, para_a);
	bytes_to_big(BNLEN, SM9_b, para_b);
	bytes_to_big(BNLEN, SM9_N, N);
	bytes_to_big(BNLEN, SM9_t, para_t);

	mip->TWIST = MR_SEXTIC_M;
	ecurve_init(para_a, para_b, para_q, MR_PROJECTIVE);  //Initialises GF(q) elliptic curve 
														 //MR_PROJECTIVE specifying  projective coordinates 

	if (!epoint_set(P1_x, P1_y, 0, P1)) return SM9_G1BASEPOINT_SET_ERR;


	if (!(bytes128_to_ecn2(SM9_P2, &P2)))   return SM9_G2BASEPOINT_SET_ERR;
	set_frobenius_constant(&X);

	return 0;
}

/***************************************************************
Function:       SM9_GenerateEncryptKey
Description:    Generate encryption keys(public key and private key)
Calls:          MIRACL functions,SM9_H1,xgcd,ecn2_Bytes128_Print
Called By:      SM9_SelfCheck
Input:          hid:0x03
ID:identification
IDlen:the length of ID
ke:master private key used to generate encryption public key and private key
Output:         Ppubs:encryption public key
deB: encryption private key
Return:         0: success;
1: asking for memory error
Others:
****************************************************************/
int SM9_GenerateEncryptKey(unsigned char hid[], unsigned char *ID, int IDlen, big ke, unsigned char Ppubs[], unsigned char deB[])
{
	big h1, t1, t2, rem, xPpub, yPpub, tmp;
	unsigned char *Z = NULL;
	int Zlen = IDlen + 1, buf;
	ecn2 dEB;
	epoint *Ppub;

	h1 = mirvar(0); t1 = mirvar(0);
	t2 = mirvar(0); rem = mirvar(0); tmp = mirvar(0);
	xPpub = mirvar(0); yPpub = mirvar(0);
	Ppub = epoint_init();
	dEB.x.a = mirvar(0); dEB.x.b = mirvar(0); dEB.y.a = mirvar(0); dEB.y.b = mirvar(0);
	dEB.z.a = mirvar(0); dEB.z.b = mirvar(0); dEB.marker = MR_EPOINT_INFINITY;

	Z = (char *)malloc(sizeof(char)*(Zlen + 1));
	memcpy(Z, ID, IDlen);
	memcpy(Z + IDlen, hid, 1);

	buf = SM9_H1(Z, Zlen, N, h1);
	if (buf != 0)    return buf;
	add(h1, ke, t1);//t1=H1(IDA||hid,N)+ks 
	xgcd(t1, N, t1, t1, t1);//t1=t1(-1) 
	multiply(ke, t1, t2); divide(t2, N, rem);//t2=ks*t1(-1) 

											 //Ppub=[ke]P2 
	ecurve_mult(ke, P1, Ppub);

	//deB=[t2]P2 
	ecn2_copy(&P2, &dEB);
	ecn2_mul(t2, &dEB);

	printf("\n**************用户B私钥 deB = (xdeB, ydeB):*********************\n");
	ecn2_Bytes128_Print(dEB);
	printf("\n*******************加密主公钥 Ppubs=[ke]P1:**********************\n");
	epoint_get(Ppub, xPpub, yPpub);
	cotnum(xPpub, stdout); cotnum(yPpub, stdout);

	epoint_get(Ppub, xPpub, yPpub);
	big_to_bytes(BNLEN, xPpub, Ppubs, 1);
	big_to_bytes(BNLEN, yPpub, Ppubs + BNLEN, 1);

	redc(dEB.x.b, tmp); big_to_bytes(BNLEN, tmp, deB, 1);
	redc(dEB.x.a, tmp); big_to_bytes(BNLEN, tmp, deB + BNLEN, 1);
	redc(dEB.y.b, tmp); big_to_bytes(BNLEN, tmp, deB + BNLEN * 2, 1);
	redc(dEB.y.a, tmp); big_to_bytes(BNLEN, tmp, deB + BNLEN * 3, 1);

	free(Z);
	return 0;
}


/****************************************************************
Function:       SM9_Encrypt
Description:    SM9 encryption algorithm
Calls:          MIRACL functions,zzn12_init(),ecap(),member(),zzn12_ElementPrint(),
zzn12_pow(),LinkCharZzn12(),SM3_KDF(),SM9_Enc_MAC(),SM4_Block_Encrypt()
Called By:      SM9_SelfCheck()
Input:
hid:0x03
IDB          //identification of userB
message      //the message to be encrypted
len          //the length of message
rand         //a random number K lies in [1,N-1]
EncID        //encryption identification,0:stream cipher  1:block cipher
k1_len       //the byte length of K1 in block cipher algorithm
k2_len       //the byte length of K2 in MAC algorithm
Ppubs        //encrtption public key

Output:         C            //cipher C1||C3||C2
Clen         //the byte length of C
Return:
0: success
1: asking for memory error
2: element is out of order q
3: R-ate calculation error
A: K1 equals 0
Others:
****************************************************************/
int SM9_Encrypt(unsigned char hid[], unsigned char *IDB, unsigned char *message, int mlen, unsigned char rand[],int EncID, int k1_len, int k2_len, unsigned char Ppub[], unsigned char C[], int *C_len)
{
	big h, x, y, r;
	zzn12 g, w;
	epoint *Ppube, *QB, *C1;
	unsigned char *Z = NULL, *K = NULL, *C2 = NULL, C3[SM3_len / 8];
	int i = 0, j = 0, Zlen, buf, klen, C2_len;

	//initiate 
	h = mirvar(0); r = mirvar(0); x = mirvar(0); y = mirvar(0);
	QB = epoint_init(); Ppube = epoint_init(); C1 = epoint_init();
	zzn12_init(&g); zzn12_init(&w);

	bytes_to_big(BNLEN, Ppub, x);
	bytes_to_big(BNLEN, Ppub + BNLEN, y);
	epoint_set(x, y, 0, Ppube);

	//Step1:calculate QB=[H1(IDB||hid,N)]P1+Ppube 
	Zlen = strlen(IDB) + 1;
	Z = (char *)malloc(sizeof(char)*(Zlen + 1));
	if (Z == NULL) return SM9_ASK_MEMORY_ERR;
	memcpy(Z, IDB, strlen(IDB));
	memcpy(Z + strlen(IDB), hid, 1);
	buf = SM9_H1(Z, Zlen, N, h);
	if (buf) return buf;
	ecurve_mult(h, P1, QB);
	ecurve_add(Ppube, QB);

	printf("\n*******************QB:=[H1(IDB||hid,N)]P1+Ppube*****************\n");
	epoint_get(QB, x, y);
	cotnum(x, stdout); cotnum(y, stdout);

	//Step2:randnom 
	bytes_to_big(BNLEN, rand, r);
	printf("\n***********************随机数 r:********************************\n");
	cotnum(r, stdout);

	//Step3:C1=[r]QB 
	ecurve_mult(r, QB, C1);
	printf("\n*************************:C1=[r]QB*******************************\n");
	epoint_get(C1, x, y);
	cotnum(x, stdout); cotnum(y, stdout);
	big_to_bytes(BNLEN, x, C, 1); big_to_bytes(BNLEN, y, C + BNLEN, 1);

	//Step4:g = e(P2, Ppub-e) 
	if (!ecap(P2, Ppube, para_t, X, &g)) return SM9_MY_ECAP_12A_ERR;
	//test if a ZZn12 element is of order q 
	if (!member(g, para_t, X)) return SM9_MEMBER_ERR;
	printf("\n***********************g=e(P2,Ppube):****************************\n");
	zzn12_ElementPrint(g);

	//Step5:calculate w=g^r 
	w = zzn12_pow(g, r);
	printf("\n***************************w=g^r:**********************************\n");
	zzn12_ElementPrint(w);

	free(Z);
	//Step6:calculate C2 
	if (EncID == 0)
	{
		//基于密钥派生函数的序列密码算法
		//加密时间: 0.739000 seconds
		//解密时间: 0.156000 seconds
		C2_len = mlen;
		*C_len = BNLEN * 2 + SM3_len / 8 + C2_len;

		//Step:6-1: calculate K=KDF(C1||w||IDB,klen) 
		klen = mlen + k2_len;
		Zlen = strlen(IDB) + BNLEN * 14;
		Z = (char *)malloc(sizeof(char)*(Zlen + 1));
		K = (char *)malloc(sizeof(char)*(klen + 1));
		C2 = (char *)malloc(sizeof(char)*(mlen + 1));
		if (Z == NULL || K == NULL || C2 == NULL) return SM9_ASK_MEMORY_ERR;

		LinkCharZzn12(C, BNLEN * 2, w, Z, (Zlen - strlen(IDB)));
		memcpy(Z + BNLEN * 14, IDB, strlen(IDB));
		SM3_KDF(Z, Zlen, klen, K);
	
		printf("\n*****************K=KDF(C1||w||IDB,klen):***********************\n");
		for (i = 0; i

完整代码见github

参考文献

1、国标—SM9-加解密

2、密码学-基础理论与应用(李子臣著)

3、商用密码检测中心-源码下载