2020-11-25

SM2算法

1、公钥密码算法介绍
消息鉴别:是一个证实收到的消息来自可信的源点并且未被篡改的过程。它的目的是信源识别,保证信息完整性。
数字签名:是一种确保数据完整性和非否认的手段,通过给消息附加一段数据来实现。
公钥密码学与其他密码学完全不同, 使用这种方法的加密系统,不仅公开加密算法本身,也公开了加密用的密钥。
  公钥密码系统与只使用一个密钥的对称传统密码不同,算法是基于数学函数而不是基于替换和置换。公钥密码学是非对称的,它使用两个独立的密钥,即密钥分为公钥和私钥,因此称双密钥体制。双钥体制的公钥可以公开,因此称为公钥算法。
  公钥算法的出现,给密码的发展开辟了新的方向。公钥算法虽然已经历了20多年的发展,但仍具有强劲的发展势头,在鉴别系统和密钥交换等安全技术领域起着关键的作用
  公钥算法的加密与解密由不同的密钥完成,并且从加密密钥得到解密密钥在计算上是不可行的。通常,公钥算法的两个密钥中任何一个都可以作为加密而另一个用作解密,但不是所有的公钥算法都是如此。
2. SM2椭圆曲线公钥密码算法
SM2算法就是ECC椭圆曲线密码机制,但在签名、密钥交换方面不同于ECDSA、ECDH等国际标准,而是采取了更为安全的机制。另外,SM2推荐了一条256位的曲线作为标准曲线。
SM2标准包括总则,数字签名算法,密钥交换协议,公钥加密算法四个部分,并在每个部分的附录详细说明了实现的相关细节及示例。
SM2算法主要考虑素域Fp和F2m上的椭圆曲线,分别介绍了这两类域的表示,运算,以及域上的椭圆曲线的点的表示,运算和多倍点计算算法。然后介绍了编程语言中的数据转换,包括整数和字节串,字节串和比特串,域元素和比特串,域元素和整数,点和字节串之间的数据转换规则。
详细说明了有限域上椭圆曲线的参数生成以及验证,椭圆曲线的参数包括有限域的选取,椭圆曲线方程参数,椭圆曲线群基点的选取等,并给出了选取的标准以便于验证。最后给椭圆曲线上密钥对的生成以及公钥的验证,用户的密钥对为(s,sP),其中s为用户的私钥,sP为用户的公钥,由于离散对数问题从sP难以得到s,并针对素域和二元扩域给出了密钥对生成细节和验证方式。
在总则的基础上给出了数字签名算法(包括数字签名生成算法和验证算法),密钥交换协议以及公钥加密算法(包括加密算法和解密算法),并在每个部分给出了算法描述,算法流程和相关示例。
数字签名算法,密钥交换协议以及公钥加密算法都使用了国家密管理局批准的SM3密码杂凑算法和随机数发生器。数字签名算法,密钥交换协议以及公钥加密算法根据总则来选取有限域和椭圆曲线,并生成密钥对。
SM2算法在很多方面都优于RSA算法(RSA发展得早应用普遍,SM2领先也很自然)RSA算法的危机在于其存在亚指数算法,对ECC算法而言一般没有亚指数攻击算法
SM2椭圆曲线公钥密码算法:我国自主知识产权的商用密码算法,是ECC(Elliptic Curve Cryptosystem)算法的一种,基于椭圆曲线离散对数问题,计算复杂度是指数级,求解难度较大,同等安全程度要求下,椭圆曲线密码较其他公钥算法所需密钥长度小很多。
ECC算法描述:
  1、用户A选定一条适合加密的椭圆曲线Ep(a,b)(如:y2=x3+ax+b),并取椭圆曲线上一点,作为基点G。
  2、用户A选择一个私有密钥k,并生成公开密钥(公钥PB)K=kG。
  3、用户A将Ep(a,b)和点(公钥)K,G传给用户B。
  4、用户B接到信息后 ,将待传输的明文(M)编码到Ep(a,b)上一点M,并产生一个随机整数r(r<n)。加密开始
  5、用户B计算点C1=M+rK;C2=rG。
  6、用户B将C1、C2传给用户A。
  7、用户A接到信息后,计算C1-kC2,结果就是点M。因为C1-kC2=M+rK-k(rG)=M+rK-r(kG)=M
  再对点M进行解码就可以得到明文。
  密码学中,描述一条Fp上的椭圆曲线,常用到六个参量:
  T=(p,a,b,G,n,h)。
  (p 、a 、b 用来确定一条椭圆曲线,G为基点,n为点G的阶,h 是椭圆曲线上所有点的个数m与n相除的整数部分)
  这几个参量取值的选择,直接影响了加密的安全性。参量值一般要求满足以下几个条件:
  1、p 当然越大越安全,但越大,计算速度会变慢,200位左右可以满足一般安全要求;
  2、p≠n×h;
  3、pt≠1 (mod n),1≤t<20;
  4、4a3+27b2≠0 (mod p);
  5、n 为素数;
  6、h≤4。
M2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。
随着密码技术和计算机技术的发展,目前常用的1024位RSA算法面临严重的安全威胁,我们国家密码管理部门经过研究,决定采用SM2椭圆曲线算法替换RSA算法。
2.1 SM2算法和RSA算法比较
SM2性能更优更安全:密码复杂度高、处理速度快、机器性能消耗更小。
SM2 RSA
算法结构 基本椭圆曲线(ECC) 基于特殊的可逆模幂运算
计算复杂度 完全指数级 亚指数级
存储空间 192-256bit 2048-4096bit
秘钥生成速度 较RSA算法快百倍以上 慢
解密加密速度 较快 一般

椭圆曲线算法那公钥密码所基于的曲线性质:椭圆曲线多倍点运算构成一个单向函数。在多倍点运算中,已知多倍点与基点,求解倍数的问题称为椭圆曲线离散对数问题。对于一般椭圆曲线的离散对数问题,目前只存在指数级计算复杂度的求解方法。与大数分解问题及有限域上离散对数问题相比,椭圆曲线离散对数问题的求解难度要大得多。因此,在相同安全程度要求下,椭圆曲线密码较其他公钥密码所需的秘钥规模要小得多。
数字签名算法由一个签名者对数据产生数字签名,并由一个验证者验证签名的可靠性。每个签名者都有一个公钥和一个私钥,其中私钥用于产生签名,验证者用签名者的公钥验证签名。在签名的生成过程之前,要用密码杂凑算法对 Z A Z_AZA 和待签消息 M MM 进行压缩;在验证过程之前,要用密码杂凑算法对 Z A Z_AZA 和待签消息 M MM 进行同样的压缩。
2.2 基础参数
SM2的曲线方程为 y 2 = x 3 + a x + b \displaystyle y^2 = x^3 + ax + by2=x3+ax+b ,其中:

•	a aa:0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC
•	b bb:0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93
•	p pp:0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF

私钥长度:32字节。
公钥长度:SM2非压缩公钥格式字节串长度为65字节,压缩格式长度为33字节,若公钥y坐标最后一位为0,则首字节为0x02,否则为0x03。非压缩格式公钥首字节为0x04。
签名长度:64字节。
2.3密钥对生成
SM2密钥生成是指生成SM2算法的密钥对的过程,该密钥对包括私钥和与之对应的公钥。
• 输入:无
• 输出:
• k:SM2PrivateKey,SM2私钥
• Q:SM2PublicKey,SM2公钥

  1. 用随机数发生器产生整数 d ∈ [ 1 , n − 2 ] \displaystyle d\in[1,n-2]d∈[1,n−2] ;
  2. G GG 为基点,计算点 P = ( x P , y P ) = [ d ] G \displaystyle P=(x_P,y_P)=[d]GP=(xP,yP)=[d]G 。
    则私钥是d dd,公钥为P PP。
    2.4签名算法
    2.4.1预处理1
    预处理1是指使用签名方的用户身份标识和签名方公钥,通过运算得到Z值的过程。Z值用于预处理2。
    • 输入:
    • ID:字符串,用户身份标识
    • Q:SM2PublicKey,用户的公钥
    • 输出:
    • Z:字节串,预处理1的输出
    • 计算公式:Z = S M 3 ( E N T L ∣ ∣ I D ∣ ∣ a ∣ ∣ b ∣ ∣ x G ∣ ∣ y G ∣ ∣ x A ∣ ∣ y A ) Z=SM3(ENTL||ID||a||b||x_G||y_G||x_A||y_A)Z=SM3(ENTL∣∣ID∣∣a∣∣b∣∣xG∣∣yG∣∣xA∣∣yA)
    • 参数说明:
    • E N T L ENTLENTL:为由2个字节标识的ID的比特长度;
    • I D IDID:为用户身份标识。无特殊约定的情况下,用户身份标识ID的长度为16字节,其默认值从左至右依次为:0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38。
    • a , b a,ba,b:为系统曲线参数;
    • x G , y G \displaystyle x_G,\ y_GxG, yG 为基点;
    • x A , y A \displaystyle x_A,\ y_AxA, yA 为用户的公钥。
    2.4.2预处理2
    预处理2是指使用Z值和待签名消息,通过SM3运算得到杂凑值H的过程。杂凑值H用于SM2数字签名。
    • 输入:
    • Z:字节串,预处理2的输入
    • M:字节串,待签名消息
    • 输出:
    • H:字节串,杂凑值
    • 计算公式:H = S M 3 ( Z ∣ ∣ M ) \displaystyle H=SM3(Z||M)H=SM3(Z∣∣M)
    2.4.3生成签名
    SM2签名是指使用预处理2的结果和签名者的私钥,通过签名计算得到签名结果的过程。
    • 输入:
    • d:SM2PrivateKey,签名者私钥
    • H:字节串,预处理2的结果
    • 输出:
    • sign:SM2Signature,签名值
    设待签名的消息为M,为了获取消息M的数字签名 ( r , s ) (r,s)(r,s),作为签名者的用户A应实现以下运算步骤:
  3. 置 M ‾ = Z A ∣ ∣ M \displaystyle \overline{M}=Z_A||MM=ZA∣∣M ;
  4. 计算 e = H v ( M ‾ ) \displaystyle e=H_v(\overline{M})e=Hv(M) ,将 e ee 的数据类型转化为整数;
  5. 用随机数发生器产生随机数 k ∈ [ 1 , n − 1 ] \displaystyle k\in[1,n-1]k∈[1,n−1] ;
  6. 计算椭圆曲线点 ( x 1 , y 1 ) = [ k ] G \displaystyle (x_1,y_1)=[k]G(x1,y1)=[k]G ,将 x 1 \displaystyle x_1x1 的数据类型转化为整数;
  7. 计算 r = ( e + x 1 ) m o d n \displaystyle r=(e+x_1) mod \ nr=(e+x1)mod n ,若 r = 0 r = 0r=0 或 r + k = n r + k = nr+k=n 则返回第3步;
  8. 计算 s = ( ( 1 + d A ) − 1 ⋅ ( k − r ⋅ d A ) ) m o d n \displaystyle s=((1+d_A)^{-1}\cdot (k-r \cdot d_A)) mod\ ns=((1+dA)−1⋅(k−r⋅dA))mod n ,若 s = 0 s=0s=0 则返回第3步;
  9. 将 r , s r, sr,s 转化为字节串。
    消息M的签名为( r , s ) (r, s)(r,s)。
    2.4.5签名验证
    SM2签名验证是指使用预处理2的结果、签名值和签名者的公钥,通过验签计算确定签名是否通过验证的过程。
    • 输入:
    • H:字节串,预处理2的结果
    • sign:SM2Signature,签名值
    • Q:PublicKey,签名者的公钥
    • 输出:为真表示验证通过,为假表示验证不通过。
    为了检验收到的消息 M及其数字签名( r , s ) (r, s)(r,s),作为验证者的用户B应实现以下运算步骤:
  10. 检验 r ∈ [ 1 , n − 1 ] \displaystyle r\in[1,n-1]r∈[1,n−1] 是否成立,若不成立则验证不通过;
  11. 检验 s ∈ [ 1 , n − 1 ] \displaystyle s\in[1,n-1]s∈[1,n−1] 是否成立,若不成立则验证不通过;
  12. 置 M ‾ = Z A ∣ ∣ M \displaystyle \overline{M}=Z_A||MM=ZA∣∣M ;
  13. 计算 e = H v ( M ‾ ) \displaystyle e=H_v(\overline{M})e=Hv(M) ,将e ee的数据类型转化为整数;
  14. 将 r , s r,sr,s 的数据类型转化为整数,计算 t = ( r + s ) m o d n \displaystyle t=(r+s) mod \ nt=(r+s)mod n ,若 t = 0 t=0t=0,则验证不通过;
  15. 计算椭圆曲线点 ( x 1 , y 1 ) = [ s ] G + [ t ] P A \displaystyle (x_1,y_1)=[s]G+[t]P_A(x1,y1)=[s]G+[t]PA ;
  16. 将 x 1 \displaystyle x_1x1 的数据类型转化为整数,计算 R = ( e + x 1 ) m o d n \displaystyle R=(e+x_1) mod \ nR=(e+x1)mod n ,检验 R = r R=rR=r 是否成立,若成立则验证通过;否则验证不通过。
    签名验证原理
[ s ] G + [ t ] P A = s G + ( r + s ) P A = s G + ( r + s ) d A G = s G + s d A G + r d A G = ( 1 + d A ) s G + r d A G = ( 1 + d A ) ( 1 + d A ) − 1 ( k − r d A ) G + r d A G = ( k − r d A ) G + r d A G = k G − r d A G + r d A G = k G = ( x 1 , y 1 ) \displaystyle
G+[t]PAamp;=sG+(r+s)PAamp;=sG+(r+s)dAGamp;=sG+sdAG+rdAGamp;=(1+dA)sG+rdAGamp;=(1+dA)(1+dA)−1(k−rdA)G+rdAGamp;=(k−rdA)G+rdAGamp;=kG−rdAG+rdAGamp;=kGamp;=(x1,y1)G+[t]PAamp;=sG+(r+s)PAamp;=sG+(r+s)dAGamp;=sG+sdAG+rdAGamp;=(1+dA)sG+rdAGamp;=(1+dA)(1+dA)−1(k−rdA)G+rdAGamp;=(k−rdA)G+rdAGamp;=kG−rdAG+rdAGamp;=kGamp;=(x1,y1)
[s]G+[t]PA=sG+(r+s)PA=sG+(r+s)dAG=sG+sdAG+rdAG=(1+dA)sG+rdAG=(1+dA)(1+dA)−1(k−rdA)G+rdAG=(k−rdA)G+rdAG=kG−rdAG+rdAG=kG=(x1,y1)
  1. 国密SM2算法标准
    国密SM2算法标准包括4个部分,第1部分为总则,主要介绍了ECC基本的算法描述,包括素数域和二元扩域两种算法描述,第2部分为数字签名算法,这个算法不同于ECDSA算法,其计算量大,也比ECDSA复杂些,也许这样会更安全吧,第3部分为密钥交换协议,与ECDH功能相同,但复杂性高,计算量加大,第4部分为公钥加密算法,使用ECC公钥进行加密和ECC私钥进行加密算法,其实现上是在ECDH上分散出流密钥,之后与明文或者是密文进行异或运算,并没有采用第3部分的密钥交换协议产生的密钥。对于SM2算法的总体感觉,应该是国家发明,其计算上比国际上公布的ECC算法复杂,相对来说算法速度可能慢,但可能是更安全一点。
    SM2标准还公布了一条建议的256位的ECC曲线,但没有在国际上被公认。SM2算法是好,但要使用,又有很多障碍,就是统一的国际标识与互认,如算法没有OID标识,曲线也没有公认OID标识,这在通用上就大打折扣了,这一点需要考虑的。
    网上可以查到一些SM2算法的实现代码,有C#的、有Java的,还有C的,这些代码都是使用Openssl或bouncycastle这些开源的算法库实现的,可以使用开源密码算法可以实现SM2算法。
  2. SM2算法的硬件实现
    国内有一些专门生产国密芯片的公司,比如说:清华同方、宏思等。这些公司会生产一系列的国密芯片,硬件实现SM1、SM2、SM3、SM4、SM6、SM9、SSF33等国密算法,可实现身份认证签名/验签,加密解密,安全存储等。你可以购买它们的芯片,用硬件的方式实现国密的算法。芯片的使用比较简单,通常国密芯片使用SPI接口,通过SPI就可以访问国密芯片。有些国密芯片还可以编程,可以理解为一个简单的单片机。可以定义一个简单的CPU与国密芯片的通信协议,这样就可以访问访问国密芯片了。国密芯片里面已经实现了常用的国密算法,并提供了API接口,只需要关注这些接口需要什么样的参数,返回值就可以了,在你的通信协议中定义你需要关心的数据即可。
    5.使用Openssl实现的SM2算法源码
//kdf.h
#include <memory.h>
#include <openssl/evp.h>

// ----- KDF FUNCTIONS START -----
//typedef void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen);

int x9_63_kdf(const EVP_MD *md, const unsigned char *share, size_t sharelen, size_t keylen, unsigned char *outkey)
{
	int ret = 0;

	EVP_MD_CTX ctx;
	unsigned char counter[4] = {0, 0, 0, 1};
	unsigned char dgst[EVP_MAX_MD_SIZE];
	unsigned int dgstlen;
	int rlen = (int)keylen;
	unsigned char * pp;

	pp = outkey;

	if (keylen > (size_t)EVP_MD_size(md)*255)
	{
		fprintf(stderr, "%s(%d):", __FILE__, __LINE__);
		goto end;
	}

	while (rlen > 0)
	{
		EVP_MD_CTX_init(&ctx);

		if (!EVP_DigestInit(&ctx, md))
		{
			fprintf(stderr, "%s(%d):", __FILE__, __LINE__);
			goto end;
		}

		if (!EVP_DigestUpdate(&ctx, share, sharelen))
		{
			fprintf(stderr, "%s(%d):", __FILE__, __LINE__);
			goto end;
		}
		if (!EVP_DigestUpdate(&ctx, counter, 4))
		{
			fprintf(stderr, "%s(%d):", __FILE__, __LINE__);
			goto end;
		}
		if (!EVP_DigestFinal(&ctx, dgst, &dgstlen))
		{
			fprintf(stderr, "%s(%d):", __FILE__, __LINE__);
			goto end;
		}

		EVP_MD_CTX_cleanup(&ctx);

		memcpy(pp, dgst, keylen>=dgstlen ? dgstlen:keylen);

		rlen -= dgstlen;
		pp += dgstlen;
		counter[3]++;
	}

	ret = 1;

end:
	return ret;
}

// ----- KDF FUNCTIONS END -----

//sm2.h

//SM2_sign_setup
int SM2_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp);

//SM2_sign_ex
int	SM2_sign_ex(int type, const unsigned char *dgst, int dlen, unsigned char 
	*sig, unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey);

//SM2_sign
int	SM2_sign(int type, const unsigned char *dgst, int dlen, unsigned char 
		*sig, unsigned int *siglen, EC_KEY *eckey);

//SM2_verify
int SM2_verify(int type, const unsigned char *dgst, int dgst_len,
		const unsigned char *sigbuf, int sig_len, EC_KEY *eckey);

//SM2 DH, comupting shared point
int SM2_DH_key(const EC_GROUP * group,const EC_POINT *b_pub_key_r, const EC_POINT *b_pub_key, const BIGNUM *a_r,EC_KEY *a_eckey,
			   unsigned char *outkey,size_t keylen);
// sm2.c
//depending:opnessl library
//SM2 Standards: http://www.oscca.gov.cn/News/201012/News_1197.htm

#include <limits.h>
#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/ecdsa.h>
#include <openssl/ecdh.h>
#include "kdf.h"

#define  NID_X9_62_prime_field 406
static void BNPrintf(BIGNUM* bn)
{
	char *p=NULL;
	p=BN_bn2hex(bn);
	printf("%s",p);
	OPENSSL_free(p);
}


static int sm2_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kp, BIGNUM **rp)
{
	BN_CTX   *ctx = NULL;
	BIGNUM	 *k = NULL, *r = NULL, *order = NULL, *X = NULL;
	EC_POINT *tmp_point=NULL;
	const EC_GROUP *group;
	int 	 ret = 0;

	if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL)
	{
		ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_PASSED_NULL_PARAMETER);
		return 0;
	}

	if (ctx_in == NULL) 
	{
		if ((ctx = BN_CTX_new()) == NULL)
		{
			ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,ERR_R_MALLOC_FAILURE);
			return 0;
		}
	}
	else
		ctx = ctx_in;

	k     = BN_new();	/* this value is later returned in *kp */
	r     = BN_new();	/* this value is later returned in *rp */
	order = BN_new();
	X     = BN_new();
	if (!k || !r || !order || !X)
	{
		ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE);
		goto err;
	}
	if ((tmp_point = EC_POINT_new(group)) == NULL)
	{
		ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB);
		goto err;
	}
	if (!EC_GROUP_get_order(group, order, ctx))
	{
		ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB);
		goto err;
	}
	
	do
	{
		/* get random k */	
		do
			if (!BN_rand_range(k, order))
			{
				ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);	
				goto err;
			}
		while (BN_is_zero(k));

		/* compute r the x-coordinate of generator * k */
		if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx))
		{
			ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB);
			goto err;
		}
		if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field)
		{
			if (!EC_POINT_get_affine_coordinates_GFp(group,
				tmp_point, X, NULL, ctx))
			{
				ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,ERR_R_EC_LIB);
				goto err;
			}
		}
		else /* NID_X9_62_characteristic_two_field */
		{
			if (!EC_POINT_get_affine_coordinates_GF2m(group,
				tmp_point, X, NULL, ctx))
			{
				ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,ERR_R_EC_LIB);
				goto err;
			}
		}
		if (!BN_nnmod(r, X, order, ctx))
		{
			ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
			goto err;
		}
	}
	while (BN_is_zero(r));

	/* compute the inverse of k */
// 	if (!BN_mod_inverse(k, k, order, ctx))
// 	{
// 		ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
// 		goto err;	
// 	}
	/* clear old values if necessary */
	if (*rp != NULL)
		BN_clear_free(*rp);
	if (*kp != NULL) 
		BN_clear_free(*kp);
	/* save the pre-computed values  */
	*rp = r;
	*kp = k;
	ret = 1;
err:
	if (!ret)
	{
		if (k != NULL) BN_clear_free(k);
		if (r != NULL) BN_clear_free(r);
	}
	if (ctx_in == NULL) 
		BN_CTX_free(ctx);
	if (order != NULL)
		BN_free(order);
	if (tmp_point != NULL) 
		EC_POINT_free(tmp_point);
	if (X)
		BN_clear_free(X);
	return(ret);
}


static ECDSA_SIG *sm2_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *in_k, const BIGNUM *in_r, EC_KEY *eckey)
{
	int     ok = 0, i;
	BIGNUM *k=NULL, *s, *m=NULL,*tmp=NULL,*order=NULL;
	const BIGNUM *ck;
	BN_CTX     *ctx = NULL;
	const EC_GROUP   *group;
	ECDSA_SIG  *ret;
	//ECDSA_DATA *ecdsa;
	const BIGNUM *priv_key;
    BIGNUM *r,*x=NULL,*a=NULL;	//new added
	//ecdsa    = ecdsa_check(eckey);
	group    = EC_KEY_get0_group(eckey);
	priv_key = EC_KEY_get0_private_key(eckey);
	
	if (group == NULL || priv_key == NULL /*|| ecdsa == NULL*/)
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_PASSED_NULL_PARAMETER);
		return NULL;
	}

	ret = ECDSA_SIG_new();
	if (!ret)
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE);
		return NULL;
	}
	s = ret->s;
	r = ret->r;

	if ((ctx = BN_CTX_new()) == NULL || (order = BN_new()) == NULL ||
		(tmp = BN_new()) == NULL || (m = BN_new()) == NULL || 
		(x = BN_new()) == NULL || (a = BN_new()) == NULL)
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE);
		goto err;
	}

	if (!EC_GROUP_get_order(group, order, ctx))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_EC_LIB);
		goto err;
	}
// 	for(i=0;i<dgst_len;i++)
// 		printf("%02X",dgst[i]);
//  	printf("\n");
	i = BN_num_bits(order);
	/* Need to truncate digest if it is too long: first truncate whole
	 * bytes.
	 */
	if (8 * dgst_len > i)
		dgst_len = (i + 7)/8;
	if (!BN_bin2bn(dgst, dgst_len, m))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
		goto err;
	}
	/* If still too long truncate remaining bits with a shift */
	if ((8 * dgst_len > i) && !BN_rshift(m, m, 8 - (i & 0x7)))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
		goto err;
	}
// 	fprintf(stdout,"m: ");
// 	BNPrintf(m);
// 	fprintf(stdout,"\n");
	do
	{
		if (in_k == NULL || in_r == NULL)
		{
			if (!sm2_sign_setup(eckey, ctx, &k, &x))
			{
				ECDSAerr(ECDSA_F_ECDSA_DO_SIGN,ERR_R_ECDSA_LIB);
				goto err;
			}
			ck = k;
		}
		else
		{
			ck  = in_k;
			if (BN_copy(x, in_r) == NULL)
			{
				ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE);
				goto err;
			}
		}
		
		//r=(e+x1) mod n
		if (!BN_mod_add_quick(r, m, x, order))
		{
			ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
			goto err;
		}

// 	    BNPrintf(r);
// 		fprintf(stdout,"\n");

		if(BN_is_zero(r) )
			continue;

		BN_add(tmp,r,ck);
		if(BN_ucmp(tmp,order) == 0)
			continue;
		
		if (!BN_mod_mul(tmp, priv_key, r, order, ctx))
		{
			ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
			goto err;
		}
		if (!BN_mod_sub_quick(s, ck, tmp, order))
		{
			ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
			goto err;
		}
		BN_one(a);
		//BN_set_word((a),1);

		if (!BN_mod_add_quick(tmp, priv_key, a, order))
		{
			ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
			goto err;
		}
		/* compute the inverse of 1+dA */
		if (!BN_mod_inverse(tmp, tmp, order, ctx))
		{
			ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB);
			goto err;	
		}
// 		BNPrintf(tmp);
// 		fprintf(stdout,"\n");

		if (!BN_mod_mul(s, s, tmp, order, ctx))
		{
			ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB);
			goto err;
		}
		if (BN_is_zero(s))
		{
			/* if k and r have been supplied by the caller
			 * don't to generate new k and r values */
			if (in_k != NULL && in_r != NULL)
			{
				ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ECDSA_R_NEED_NEW_SETUP_VALUES);
				goto err;
			}
		}
		else
			/* s != 0 => we have a valid signature */
			break;
	}
	while (1);

	ok = 1;
err:
	if (!ok)
	{
		ECDSA_SIG_free(ret);
		ret = NULL;
	}
	if (ctx)
		BN_CTX_free(ctx);
	if (m)
		BN_clear_free(m);
	if (tmp)
		BN_clear_free(tmp);
	if (order)
		BN_free(order);
	if (k)
		BN_clear_free(k);
	if (x)
		BN_clear_free(x);
	if (a)
		BN_clear_free(a);
	return ret;
}

static int sm2_do_verify(const unsigned char *dgst, int dgst_len,
		const ECDSA_SIG *sig, EC_KEY *eckey)
{
	int ret = -1, i;
	BN_CTX   *ctx;
	BIGNUM   *order, *R,  *m, *X,*t;
	EC_POINT *point = NULL;
	const EC_GROUP *group;
	const EC_POINT *pub_key;

	/* check input values */
	if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL ||
	    (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || sig == NULL)
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ECDSA_R_MISSING_PARAMETERS);
		return -1;
	}

	ctx = BN_CTX_new();
	if (!ctx)
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_MALLOC_FAILURE);
		return -1;
	}
	BN_CTX_start(ctx);
	order = BN_CTX_get(ctx);	
	R    = BN_CTX_get(ctx);
	t    = BN_CTX_get(ctx);
	m     = BN_CTX_get(ctx);
	X     = BN_CTX_get(ctx);
	if (!X)
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB);
		goto err;
	}
	
	if (!EC_GROUP_get_order(group, order, ctx))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_EC_LIB);
		goto err;
	}

	if (BN_is_zero(sig->r)          || BN_is_negative(sig->r) || 
	    BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s)  ||
	    BN_is_negative(sig->s)      || BN_ucmp(sig->s, order) >= 0)
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ECDSA_R_BAD_SIGNATURE);
		ret = 0;	/* signature is invalid */
		goto err;
	}

	//t =(r+s) mod n
	if (!BN_mod_add_quick(t, sig->s, sig->r,order))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB);
		goto err;
	}
	if (BN_is_zero(t))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ECDSA_R_BAD_SIGNATURE);
		ret = 0;	/* signature is invalid */
		goto err;
	}
	
	//point = s*G+t*PA
	if ((point = EC_POINT_new(group)) == NULL)
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_MALLOC_FAILURE);
		goto err;
	}
	if (!EC_POINT_mul(group, point, sig->s, pub_key, t, ctx))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_EC_LIB);
		goto err;
	}
	if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field)
	{
		if (!EC_POINT_get_affine_coordinates_GFp(group,
			point, X, NULL, ctx))
		{
			ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_EC_LIB);
			goto err;
		}
	}
	else /* NID_X9_62_characteristic_two_field */
	{
		if (!EC_POINT_get_affine_coordinates_GF2m(group,
			point, X, NULL, ctx))
		{
			ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_EC_LIB);
			goto err;
		}
	}
 	
	i = BN_num_bits(order);
	/* Need to truncate digest if it is too long: first truncate whole
	 * bytes.
	 */
	if (8 * dgst_len > i)
		dgst_len = (i + 7)/8;
	if (!BN_bin2bn(dgst, dgst_len, m))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB);
		goto err;
	}
	/* If still too long truncate remaining bits with a shift */
	if ((8 * dgst_len > i) && !BN_rshift(m, m, 8 - (i & 0x7)))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB);
		goto err;
	}

	/* R = m + X mod order */
	if (!BN_mod_add_quick(R, m, X, order))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB);
		goto err;
	}

	/*  if the signature is correct R is equal to sig->r */
	ret = (BN_ucmp(R, sig->r) == 0);
err:
	BN_CTX_end(ctx);
	BN_CTX_free(ctx);
	if (point)
		EC_POINT_free(point);
	return ret;
}


EC_POINT *sm2_compute_key(const EC_POINT *b_pub_key_r, const EC_POINT *b_pub_key, const BIGNUM *a_r,EC_KEY *a_eckey)
{
	BN_CTX *ctx;
	EC_POINT *tmp=NULL;
	BIGNUM *x=NULL, *y=NULL, *order=NULL,*z=NULL;
	const BIGNUM *priv_key;
	const EC_GROUP* group;
	EC_POINT *ret= NULL;
/*	size_t buflen, len;*/
	unsigned char *buf=NULL;
	int i, j;
	//char *p=NULL;
	BIGNUM *x1,*x2,*t,*h;

	if ((ctx = BN_CTX_new()) == NULL) goto err;
	BN_CTX_start(ctx);
	x = BN_CTX_get(ctx);
	y = BN_CTX_get(ctx);
	order = BN_CTX_get(ctx);
	z = BN_CTX_get(ctx);
	x1 = BN_CTX_get(ctx);
	x2 = BN_CTX_get(ctx);
	t = BN_CTX_get(ctx);
	h = BN_CTX_get(ctx);

	
	priv_key = EC_KEY_get0_private_key(a_eckey);
	if (priv_key == NULL)
	{
		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_NO_PRIVATE_VALUE);
		goto err;
	}

	group = EC_KEY_get0_group(a_eckey);
	if ((tmp=EC_POINT_new(group)) == NULL)
	{
		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ERR_R_MALLOC_FAILURE);
		goto err;
	}

	if (!EC_POINT_mul(group, tmp, a_r, NULL, NULL, ctx)) 
	{
		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_POINT_ARITHMETIC_FAILURE);
		goto err;
	}
	
	if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) 
	{
		if (!EC_POINT_get_affine_coordinates_GFp(group, tmp, x, NULL, ctx)) 
		{
			ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_POINT_ARITHMETIC_FAILURE);
			goto err;
		}
	}
	else
	{
		if (!EC_POINT_get_affine_coordinates_GF2m(group, tmp, x, NULL, ctx)) 
		{
			ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_POINT_ARITHMETIC_FAILURE);
			goto err;
		}
	}
	
	if (!EC_GROUP_get_order(group, order, ctx))
	{
		ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_EC_LIB);
		goto err;
	}
		
	i = BN_num_bits(order);
	j = i/2 -1;
	BN_mask_bits(x,j);
	BN_set_word(y,2);
	BN_set_word(z,j);
	BN_exp(y,y,z,ctx);
	BN_add(x1,x,y);
	
// 	fprintf(stdout,"X1=: ");
// 	BNPrintf(x1);
// 	fprintf(stdout,"\n");

	BN_mod_mul(t,x1,a_r,order,ctx);
	BN_mod_add_quick(t,t,priv_key,order);
// 
// 	fprintf(stdout,"ta=: ");
// 	BNPrintf(t);
// 	fprintf(stdout,"\n");

	
	if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) 
	{
		if (!EC_POINT_get_affine_coordinates_GFp(group, b_pub_key_r, x, NULL, ctx)) 
		{
			ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_POINT_ARITHMETIC_FAILURE);
			goto err;
		}
	}
	else
	{
		if (!EC_POINT_get_affine_coordinates_GF2m(group, b_pub_key_r, x, NULL, ctx)) 
		{
			ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_POINT_ARITHMETIC_FAILURE);
			goto err;
		}
	}

	i = BN_num_bits(order);
	j = i/2 -1;
	BN_mask_bits(x,j);
	BN_set_word(y,2);
	BN_set_word(z,j);
	BN_exp(y,y,z,ctx);
	BN_add(x2,x,y);
	
// 	fprintf(stdout,"X2=: ");
// 	BNPrintf(x2);
// 	fprintf(stdout,"\n");


	//x2*Rb+Pb;
	if (!EC_POINT_mul(group, tmp, NULL,b_pub_key_r,x2,ctx) )
	{
		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_POINT_ARITHMETIC_FAILURE);
		goto err;
	}
	if ((ret=EC_POINT_new(group)) == NULL)
	{
		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ERR_R_MALLOC_FAILURE);
		goto err;
	}
	if (!EC_POINT_add(group, ret, b_pub_key, tmp, ctx))
	{
		ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_POINT_ARITHMETIC_FAILURE);
		goto err;
	}
	if (!EC_POINT_get_affine_coordinates_GFp(group,ret, x, y, ctx)) 
	{
		goto err;
	}
// 	fprintf(stdout, "\nTesting x2*Rb+Pb Key Point\n     x = 0x");
// 	BNPrintf(x);
// 	fprintf(stdout, "\n     y = 0x");
// 	BNPrintf( y);
// 	fprintf(stdout, "\n");
// 	
	if(!EC_GROUP_get_cofactor(group, h, ctx))
	{
		goto err;
	}
    BN_mul(t,t,h,ctx);

	//h*t*(x2*Rb+Pb)
	if (!EC_POINT_mul(group, ret, NULL,ret,t,ctx) ) 
	{
		goto err;
	}
	if (!EC_POINT_get_affine_coordinates_GFp(group,ret, x, y, ctx)) 
	{
		goto err;
	}
// 	fprintf(stdout, "\nTesting ret Key Point\n     x = 0x");
// 	BNPrintf(x);
// 	fprintf(stdout, "\n     y = 0x");
// 	BNPrintf( y);
// 	fprintf(stdout, "\n");

	
err:
	if (tmp) EC_POINT_free(tmp);
	if (ctx) BN_CTX_end(ctx);
	if (ctx) BN_CTX_free(ctx);
	if (buf) OPENSSL_free(buf);
	return(ret);
}

/** SM2_sign_setup
* precompute parts of the signing operation. 
* \param eckey pointer to the EC_KEY object containing a private EC key
* \param ctx  pointer to a BN_CTX object (may be NULL)
* \param k pointer to a BIGNUM pointer for the inverse of k
* \param rp   pointer to a BIGNUM pointer for x coordinate of k * generator
* \return 1 on success and 0 otherwise
 */

int  SM2_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
{
// 	ECDSA_DATA *ecdsa = ecdsa_check(eckey);
// 	if (ecdsa == NULL)
// 		return 0;
	return SM2_sign_setup(eckey, ctx_in, kinvp, rp); 
}
/** SM2_sign_ex
 * computes ECDSA signature of a given hash value using the supplied
 * private key (note: sig must point to ECDSA_size(eckey) bytes of memory).
 * \param type this parameter is ignored
 * \param dgst pointer to the hash value to sign
 * \param dgstlen length of the hash value
 * \param sig buffer to hold the DER encoded signature
 * \param siglen pointer to the length of the returned signature
 * \param k optional pointer to a pre-computed inverse k
 * \param rp optional pointer to the pre-computed rp value (see 
 *        ECDSA_sign_setup
 * \param eckey pointer to the EC_KEY object containing a private EC key
 * \return 1 on success and 0 otherwise
 */
int	  SM2_sign_ex(int type, const unsigned char *dgst, int dlen, unsigned char 
	*sig, unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, 
	EC_KEY *eckey)
{
	ECDSA_SIG *s;
	RAND_seed(dgst, dlen);
	s = sm2_do_sign(dgst, dlen, kinv, r, eckey);
	if (s == NULL)
	{
		*siglen=0;
		return 0;
	}
	*siglen = i2d_ECDSA_SIG(s, &sig);
	ECDSA_SIG_free(s);
	return 1;
}

/** SM2_sign
  * computes ECDSA signature of a given hash value using the supplied
  * private key (note: sig must point to ECDSA_size(eckey) bytes of memory).
  * \param type this parameter is ignored
  * \param dgst pointer to the hash value to sign
  * \param dgstlen length of the hash value
  * \param sig buffer to hold the DER encoded signature
  * \param siglen pointer to the length of the returned signature
  * \param eckey pointer to the EC_KEY object containing a private EC key
  * \return 1 on success and 0 otherwise
 */
int	  SM2_sign(int type, const unsigned char *dgst, int dlen, unsigned char 
		*sig, unsigned int *siglen, EC_KEY *eckey)
{

	return SM2_sign_ex(type, dgst, dlen, sig, siglen, NULL, NULL, eckey);

}


/** SM2_verify
  * verifies that the given signature is valid ECDSA signature
  * of the supplied hash value using the specified public key.
  * \param type this parameter is ignored
  * \param dgst pointer to the hash value 
  * \param dgstlen length of the hash value
  * \param sig  pointer to the DER encoded signature
  * \param siglen length of the DER encoded signature
  * \param eckey pointer to the EC_KEY object containing a public EC key
  * \return 1 if the signature is valid, 0 if the signature is invalid and -1 on error
  */
int SM2_verify(int type, const unsigned char *dgst, int dgst_len,
		const unsigned char *sigbuf, int sig_len, EC_KEY *eckey)
 {
	ECDSA_SIG *s;
	int ret=-1;

	s = ECDSA_SIG_new();
	if (s == NULL) return(ret);
	if (d2i_ECDSA_SIG(&s, &sigbuf, sig_len) == NULL) goto err;
	ret=sm2_do_verify(dgst, dgst_len, s, eckey);
err:
	ECDSA_SIG_free(s);
	return(ret);
}

int SM2_DH_key(const EC_GROUP * group, const EC_POINT *b_pub_key_r, const EC_POINT *b_pub_key, const BIGNUM *a_r,EC_KEY *a_eckey,
			   unsigned char *outkey,size_t keylen)
{
	EC_POINT *dhpoint = NULL;
	BN_CTX * ctx;
	EC_POINT *P;
	BIGNUM *x, *y;
	int ret = 0;
	unsigned char in[128];
	int inlen;
	int len;

	P = EC_POINT_new(group);
	if (!P ) goto err;
	ctx = BN_CTX_new();
	x = BN_new();
	y = BN_new();
	if (!x || !y ) goto err;
	
	dhpoint = sm2_compute_key(b_pub_key_r,b_pub_key,a_r,a_eckey);

	if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) 
	{
		if (!EC_POINT_get_affine_coordinates_GFp(group,dhpoint, x, y, ctx))
		{
			fprintf(stdout, " failed\n");
			goto err;
		}
	}
	else
	{
		if (!EC_POINT_get_affine_coordinates_GF2m(group,dhpoint, x, y, ctx)) 
		{
			ECDHerr(ECDH_F_ECDH_COMPUTE_KEY,ECDH_R_POINT_ARITHMETIC_FAILURE);
			goto err;
		}
	}

// 	if (!EC_POINT_get_affine_coordinates_GFp(group,dhpoint, x, y, ctx))
// 	{
// 		fprintf(stdout, " failed\n");
// 		goto err;
// 	}
	fprintf(stdout, "\nTesting DH Point\n     Xv = 0x");
	BNPrintf(x);
	fprintf(stdout, "\n     Yv = 0x");
	BNPrintf( y);
	fprintf(stdout, "\n");

	len = BN_bn2bin(x,in);
	inlen =BN_bn2bin(y,in+len);
	inlen = inlen + len;
	ret = x9_63_kdf(EVP_sha256(),in,inlen,keylen,outkey);
	//ret  = 1;
err:
	EC_POINT_free(P);
	EC_POINT_free(dhpoint);
	BN_CTX_free(ctx);

	return ret;
}

//sm2_test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/ecdsa.h>
#include <openssl/ecdh.h>
#include "sm2.h"


#pragma comment(lib,"libeay32.lib")

#define ABORT do { \
	fflush(stdout); \
	fprintf(stderr, "%s:%d: ABORT\n", __FILE__, __LINE__); \
	ERR_print_errors_fp(stderr); \
	exit(1); \
} while (0)

static const char rnd_seed[] = "string to make the random number generator think it has entropy";

void BNPrintf(BIGNUM* bn)
{
	char *p=NULL;
	p=BN_bn2hex(bn);
	printf("%s",p);
	OPENSSL_free(p);
}


int SM2_Test_Vecotor()
{
	BN_CTX *ctx = NULL;
	BIGNUM *p, *a, *b;
	EC_GROUP *group;
	EC_POINT *P, *Q, *R;
	BIGNUM *x, *y, *z;
	EC_KEY	*eckey = NULL;
	unsigned char	digest[20];
	unsigned char	*signature = NULL; 
	int	sig_len;


	CRYPTO_set_mem_debug_functions(0, 0, 0, 0, 0);
	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
	ERR_load_crypto_strings();
	RAND_seed(rnd_seed, sizeof rnd_seed); /* or BN_generate_prime may fail */
	
	ctx = BN_CTX_new();
	if (!ctx) ABORT;

	/* Curve SM2 (Chinese National Algorithm) */
	//http://www.oscca.gov.cn/News/201012/News_1197.htm
	p = BN_new();
	a = BN_new();
	b = BN_new();
	if (!p || !a || !b) ABORT;
	group = EC_GROUP_new(EC_GFp_mont_method()); /* applications should use EC_GROUP_new_curve_GFp
 	                                             * so that the library gets to choose the EC_METHOD */
	if (!group) ABORT;
	
	if (!BN_hex2bn(&p, "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3")) ABORT;
	if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT;
	if (!BN_hex2bn(&a, "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498")) ABORT;
	if (!BN_hex2bn(&b, "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A")) ABORT;
	if (!EC_GROUP_set_curve_GFp(group, p, a, b, ctx)) ABORT;

	P = EC_POINT_new(group);
	Q = EC_POINT_new(group);
	R = EC_POINT_new(group);
	if (!P || !Q || !R) ABORT;

	x = BN_new();
	y = BN_new();
	z = BN_new();
	if (!x || !y || !z) ABORT;

	// sm2 testing P256 Vetor
	// p��8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3
	// a��787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498
	// b��63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A
	// xG 421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D
	// yG 0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2
	// n: 8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7

	if (!BN_hex2bn(&x, "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D")) ABORT;
	if (!EC_POINT_set_compressed_coordinates_GFp(group, P, x, 0, ctx)) ABORT;
	if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT;
	if (!BN_hex2bn(&z, "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7")) ABORT;
	if (!EC_GROUP_set_generator(group, P, z, BN_value_one())) ABORT;
	
	if (!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT;
	fprintf(stdout, "\nChinese sm2 algorithm test -- Generator:\n     x = 0x");
	BNPrintf(x);
	fprintf(stdout, "\n     y = 0x");
	BNPrintf( y);
	fprintf(stdout, "\n");
	/* G_y value taken from the standard: */
	if (!BN_hex2bn(&z, "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2")) ABORT;
	if (0 != BN_cmp(y, z)) ABORT;
	
	fprintf(stdout, "verify degree ...");
	if (EC_GROUP_get_degree(group) != 256) ABORT;
	fprintf(stdout, " ok\n");
	
	fprintf(stdout, "verify group order ...");
	fflush(stdout);
	if (!EC_GROUP_get_order(group, z, ctx)) ABORT;
	if (!EC_GROUP_precompute_mult(group, ctx)) ABORT;
	if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
	if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
 	fflush(stdout);
	fprintf(stdout, " ok\n");

	//testing ECDSA for SM2
	/* create new ecdsa key */
	if ((eckey = EC_KEY_new()) == NULL)
		goto builtin_err;
	if (EC_KEY_set_group(eckey, group) == 0)
	{
		fprintf(stdout," failed\n");
		goto builtin_err;
	}
	/* create key */
	if (!EC_KEY_generate_key(eckey))
	{
		fprintf(stdout," failed\n");
		goto builtin_err;
	}
	/* check key */
	if (!EC_KEY_check_key(eckey))
	{
		fprintf(stdout," failed\n");
		goto builtin_err;
	}
	/* create signature */
	sig_len = ECDSA_size(eckey);
	fprintf(stdout,"Siglength is: %d \n",sig_len);
	if (!RAND_pseudo_bytes(digest, 20))
	{
		fprintf(stdout," failed\n");
		goto builtin_err;
	}
	if ((signature = OPENSSL_malloc(sig_len)) == NULL)
		goto builtin_err;
	if (!SM2_sign(0, digest, 20, signature, &sig_len, eckey))
	{
		fprintf(stdout, " failed\n");
		goto builtin_err;
	}
	fprintf(stdout, "ECSign OK\n");
	/* verify signature */
	if (SM2_verify(0, digest, 20, signature, sig_len, eckey) != 1)
	{
		fprintf(stdout, " failed\n");
		goto builtin_err;
	}
	fprintf(stdout, "ECVerify OK\n");
	/* cleanup */
	OPENSSL_free(signature);
	signature = NULL;
	EC_KEY_free(eckey);
	eckey = NULL;
	
builtin_err:	
	
	EC_POINT_free(P);
	EC_POINT_free(Q);
	EC_POINT_free(R);
	EC_GROUP_free(group);
	BN_CTX_free(ctx);
	return 0;

}

int SM2_Test_Vecotor2()
{
	BN_CTX *ctx = NULL;
	BIGNUM *p, *a, *b;
	EC_GROUP *group;
	EC_POINT *P, *Q, *R;
	BIGNUM *x, *y, *z;
	EC_KEY	*eckey = NULL;
	unsigned char	*signature;
	unsigned char	digest[32] = "\xB5\x24\xF5\x52\xCD\x82\xB8\xB0\x28\x47\x6E\x00\x5C\x37\x7F\xB1\x9A\x87\xE6\xFC\x68\x2D\x48\xBB\x5D\x42\xE3\xD9\xB9\xEF\xFE\x76"; 
	int	sig_len;
	BIGNUM *kinv, *rp,*order; 
	ECDSA_SIG *ecsig = ECDSA_SIG_new();
	EC_POINT * DHPoint = NULL;
// 	unsigned char *in="123456";
// 	size_t inlen = 6;
 	size_t outlen = 256;
	unsigned char outkey[256];
	size_t keylen = 256;

	size_t i;

	CRYPTO_set_mem_debug_functions(0, 0, 0, 0, 0);
	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
	ERR_load_crypto_strings();
	RAND_seed(rnd_seed, sizeof rnd_seed); /* or BN_generate_prime may fail */
	
	ctx = BN_CTX_new();
	if (!ctx) ABORT;

	/* Curve SM2 (Chinese National Algorithm) */
	//http://www.oscca.gov.cn/News/201012/News_1197.htm
	p = BN_new();
	a = BN_new();
	b = BN_new();
	if (!p || !a || !b) ABORT;
	group = EC_GROUP_new(EC_GFp_mont_method()); /* applications should use EC_GROUP_new_curve_GFp
 	                                             * so that the library gets to choose the EC_METHOD */
	if (!group) ABORT;
	
	if (!BN_hex2bn(&p, "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3")) ABORT;
	if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT;
	if (!BN_hex2bn(&a, "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498")) ABORT;
	if (!BN_hex2bn(&b, "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A")) ABORT;
	if (!EC_GROUP_set_curve_GFp(group, p, a, b, ctx)) ABORT;

	P = EC_POINT_new(group);
	Q = EC_POINT_new(group);
	R = EC_POINT_new(group);
	if (!P || !Q || !R) ABORT;

	x = BN_new();
	y = BN_new();
	z = BN_new();
	if (!x || !y || !z) ABORT;

	// sm2 testing P256 Vetor
	// p��8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3
	// a��787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498
	// b��63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A
	// xG 421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D
	// yG 0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2
	// n: 8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7

	if (!BN_hex2bn(&x, "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D")) ABORT;
	if (!EC_POINT_set_compressed_coordinates_GFp(group, P, x, 0, ctx)) ABORT;
	if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT;
	if (!BN_hex2bn(&z, "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7")) ABORT;
	if (!EC_GROUP_set_generator(group, P, z, BN_value_one())) ABORT;
	
	if (!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT;
	fprintf(stdout, "\nChinese sm2 algorithm test -- Generator:\n     x = 0x");
	BNPrintf(x);
	fprintf(stdout, "\n     y = 0x");
	BNPrintf( y);
	fprintf(stdout, "\n");
	/* G_y value taken from the standard: */
	if (!BN_hex2bn(&z, "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2")) ABORT;
	if (0 != BN_cmp(y, z)) ABORT;
	
	fprintf(stdout, "verify degree ...");
	if (EC_GROUP_get_degree(group) != 256) ABORT;
	fprintf(stdout, " ok\n");
	
	fprintf(stdout, "verify group order ...");
	fflush(stdout);
	if (!EC_GROUP_get_order(group, z, ctx)) ABORT;
	if (!EC_GROUP_precompute_mult(group, ctx)) ABORT;
	if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
	if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
 	fflush(stdout);
	fprintf(stdout, " ok\n");

	//testing ECDSA for SM2
	/* create new ecdsa key */
	if ((eckey = EC_KEY_new()) == NULL)
		goto builtin_err;
	if (EC_KEY_set_group(eckey, group) == 0)
	{
		fprintf(stdout," failed\n");
		goto builtin_err;
	}
	/* create key */
	if (!BN_hex2bn(&z, "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263")) ABORT;
	if (!EC_POINT_mul(group,P, z, NULL, NULL, ctx)) ABORT;
	if (!EC_POINT_get_affine_coordinates_GFp(group,P, x, y, ctx)) ABORT;
	fprintf(stdout, "\nTesting ECKey Point\n     x = 0x");
	BNPrintf(x);
	fprintf(stdout, "\n     y = 0x");
	BNPrintf( y);
	fprintf(stdout, "\n");
	EC_KEY_set_private_key(eckey,z);
	EC_KEY_set_public_key(eckey, P);

	/* check key */
	if (!EC_KEY_check_key(eckey))
	{
		fprintf(stdout," failed\n");
		goto builtin_err;
	}

	/* create signature */
	sig_len = ECDSA_size(eckey);
 	//fprintf(stdout,"Siglength is: %d \n",sig_len);
	if ((signature = OPENSSL_malloc(sig_len)) == NULL)
		goto builtin_err;

	rp    = BN_new();
	kinv  = BN_new();
	order = BN_new();

	if (!BN_hex2bn(&z, "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F")) ABORT;
	if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx))
	{
		fprintf(stdout, " failed\n");
		goto builtin_err;
	}
	if (!EC_POINT_get_affine_coordinates_GFp(group,Q, x, y, ctx))
	{
		fprintf(stdout, " failed\n");
		goto builtin_err;
	}
	fprintf(stdout, "\nTesting K Point\n     x = 0x");
	BNPrintf(x);
	fprintf(stdout, "\n     y = 0x");
	BNPrintf( y);
	fprintf(stdout, "\n");

	EC_GROUP_get_order(group, order, ctx);
	if (!BN_nnmod(rp, x, order, ctx))
	{
		fprintf(stdout, " failed\n");
		goto builtin_err;
	}
	if (!BN_copy(kinv, z ))
	{
		fprintf(stdout, " failed\n");
		goto builtin_err;
	}

// 	for(i=0;i<32;i++)
// 		printf("%02X",digest[i]);
// 	printf("\n");

	if (!SM2_sign_ex(1, digest, 32, signature, &sig_len, kinv, rp, eckey))
	{
		fprintf(stdout, " failed\n");
		goto builtin_err;
	}
	fprintf(stdout, "ECSign OK\n");

	/* verify signature */
	if (SM2_verify(1, digest, 32, signature, sig_len, eckey) != 1)
	{
		fprintf(stdout, " failed\n");
		goto builtin_err;
	}
	fprintf(stdout, "ECVerify OK\n     r = 0x");
	d2i_ECDSA_SIG(&ecsig, &signature, sig_len);
	BNPrintf(ecsig->r);
	fprintf(stdout,"\n     s = 0x");
	BNPrintf(ecsig->s);
	fprintf(stdout,"\n");

	//testing SM2DH vector
	/* create key */
	if (!BN_hex2bn(&z, "6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE")) ABORT;
	if (!EC_POINT_mul(group,P, z, NULL, NULL, ctx)) ABORT;
	if (!EC_POINT_get_affine_coordinates_GFp(group,P, x, y, ctx)) ABORT;
	fprintf(stdout, "\nTesting A Key Point\n     x = 0x");
	BNPrintf(x);
	fprintf(stdout, "\n     y = 0x");
	BNPrintf( y);
	fprintf(stdout, "\n");
	EC_KEY_set_private_key(eckey,z);
	EC_KEY_set_public_key(eckey, P);

	if (!BN_hex2bn(&z, "5E35D7D3F3C54DBAC72E61819E730B019A84208CA3A35E4C2E353DFCCB2A3B53")) ABORT;
	if (!EC_POINT_mul(group,Q, z, NULL, NULL, ctx)) ABORT;
	if (!EC_POINT_get_affine_coordinates_GFp(group,Q, x, y, ctx)) ABORT;
	fprintf(stdout, "\nTesting B Key Point\n     x = 0x");
	BNPrintf(x);
	fprintf(stdout, "\n     y = 0x");
	BNPrintf( y);
	fprintf(stdout, "\n");
	//EC_KEY_set_private_key(eckey,z);
	//EC_KEY_set_public_key(eckey, P);

	if (!BN_hex2bn(&z, "33FE21940342161C55619C4A0C060293D543C80AF19748CE176D83477DE71C80")) ABORT;
	if (!EC_POINT_mul(group,P, z, NULL, NULL, ctx)) ABORT;
	if (!EC_POINT_get_affine_coordinates_GFp(group,P, x, y, ctx)) ABORT;
	fprintf(stdout, "\nTesting Rb Key Point\n     x = 0x");
	BNPrintf(x);
	fprintf(stdout, "\n     y = 0x");
	BNPrintf( y);
	fprintf(stdout, "\n");

	if (!BN_hex2bn(&z, "83A2C9C8B96E5AF70BD480B472409A9A327257F1EBB73F5B073354B248668563")) ABORT;
	if (!EC_POINT_mul(group,R, z, NULL, NULL, ctx)) ABORT;
	if (!EC_POINT_get_affine_coordinates_GFp(group,R, x, y, ctx)) ABORT;
	fprintf(stdout, "\nTesting Ra Key Point\n     x = 0x");
	BNPrintf(x);
	fprintf(stdout, "\n     y = 0x");
	BNPrintf( y);
	fprintf(stdout, "\n");
    
	SM2_DH_key(group,P, Q, z,eckey,outkey,keylen);

	fprintf(stdout,"\nExchange key --KDF(Xv||Yv)--  :");
	for(i=0; i<outlen; i++)
		printf("%02X",outkey[i]);
	printf("\n");



builtin_err:	
	OPENSSL_free(signature);
	signature = NULL;
	EC_POINT_free(P);
	EC_POINT_free(Q);
	EC_POINT_free(R);
	EC_POINT_free(DHPoint);
	EC_KEY_free(eckey);
	eckey = NULL;
	EC_GROUP_free(group);
	BN_CTX_free(ctx);
	return 0;

}

int main()
{
	CRYPTO_set_mem_debug_functions(0, 0, 0, 0, 0);
	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
	ERR_load_crypto_strings();
	RAND_seed(rnd_seed, sizeof rnd_seed); 
	
	SM2_Test_Vecotor2();
	
	
	CRYPTO_cleanup_all_ex_data();
	ERR_free_strings();
	ERR_remove_state(0);
	CRYPTO_mem_leaks_fp(stderr);
	
	return 0;

}
  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值