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公钥
- 用随机数发生器产生整数 d ∈ [ 1 , n − 2 ] \displaystyle d\in[1,n-2]d∈[1,n−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应实现以下运算步骤: - 置 M ‾ = Z A ∣ ∣ M \displaystyle \overline{M}=Z_A||MM=ZA∣∣M ;
- 计算 e = H v ( M ‾ ) \displaystyle e=H_v(\overline{M})e=Hv(M) ,将 e ee 的数据类型转化为整数;
- 用随机数发生器产生随机数 k ∈ [ 1 , n − 1 ] \displaystyle k\in[1,n-1]k∈[1,n−1] ;
- 计算椭圆曲线点 ( x 1 , y 1 ) = [ k ] G \displaystyle (x_1,y_1)=[k]G(x1,y1)=[k]G ,将 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 = 0 r = 0r=0 或 r + k = n r + k = nr+k=n 则返回第3步;
- 计算 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步;
- 将 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应实现以下运算步骤: - 检验 r ∈ [ 1 , n − 1 ] \displaystyle r\in[1,n-1]r∈[1,n−1] 是否成立,若不成立则验证不通过;
- 检验 s ∈ [ 1 , n − 1 ] \displaystyle s\in[1,n-1]s∈[1,n−1] 是否成立,若不成立则验证不通过;
- 置 M ‾ = Z A ∣ ∣ M \displaystyle \overline{M}=Z_A||MM=ZA∣∣M ;
- 计算 e = H v ( M ‾ ) \displaystyle e=H_v(\overline{M})e=Hv(M) ,将e ee的数据类型转化为整数;
- 将 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,则验证不通过;
- 计算椭圆曲线点 ( 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 ;
- 将 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)
- 国密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算法。 - 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;
}