SM2密码算法应用分析

1 曲线

参考《SM2椭圆曲线公钥密码算法第1部分:总则》(GM/T0003.1-2012),2012-03-21发布版本。

1.1  Fp上的椭圆曲线

定义在Fp(p是大于3的素数)上的椭圆曲线方程为:

y2 = x3+ax+b a;b Fp,且(4a3+27b2) modp ̸= 0--------------------(1)

椭圆曲线E(Fp)定义为:

E(Fq) = {(x;y)|x;y Fp,且满足方程(1)}{O},其中O是无穷远点。

椭圆曲线E(Fp)上的点的数目用#E(Fq)表示,称为椭圆曲线E(Fp)的阶。

1.2  F2m上的椭圆曲线

定义在F2m上的椭圆曲线方程为:

y2+xy = x3+ax2+ba;b F2m,且b ̸= 0-------------------- (2)

椭圆曲线E(F2m )定义为:

E(F2m) = {(x;y)|x;y F2m,且满足方程(2)}{O},其中O是无穷远点。

椭圆曲线E(F2m )上的点的数目用#E(F2m)表示,称为椭圆曲线E(F2m )的阶。

2 曲线参数

参考《SM2椭圆曲线公钥密码算法第5部分:参数定义》(GM/T0003.5-2012),2012-03-21发布版本。

SM2只有Fp上的椭圆曲线的推荐参数

推荐使用素数域256位椭圆曲线。

椭圆曲线方程:y2 = x3 + ax + b

曲线参数:

p=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFFFFFFFFFF 00000000 FFFFFFFF FFFFFFFF

a=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFFFFFFFFFF 00000000 FFFFFFFF FFFFFFFC

b=28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7F39789F5 15AB8F92 DDBCBD41 4D940E93

n=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF7203DF6B 21C6052B 53BBF409 39D54123

Gx=32C4AE2C 1F198119 5F990446 6A39C9948FE30BBF F2660BE1 715A4589 334C74C7

Gy=BC3736A2 F4F6779C 59BDCEE3 6B692153D0A9877C C62A4740 02DF32E5 2139F0A0

 

国际通用的X9.62命名曲线有很多,下面略举2Fp曲线:

256bits:

p=FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF

a=FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC

b=5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B

n=FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551

Gx=6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296

Gy=4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5

h=1

192bits:

p=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF

a=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC

b=64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1

n=FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831

Gx=188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012

Gy=7192B95FFC8DA78631011ED6B24CDD573F977A11E794811

h=1

3 密钥语法

参考《SM2密码算法使用规范》(GM/T0009-2012),2012-11-22发布版本。

3.1  SM2私钥

SM2私钥是一个大于等于1并且小于n-1的整数,记为k,长度为32字节。

SM2PrivateKey ::= INTEGER

GMT0010SM2密码算法加密签名消息语法规范》中定义了和X9.62相同的私钥语法:

ECPrivateKey{CURVES:IOSet}::= SEQUENCE {
  version INTEGER {ecPrivkeyVer1(1)}(ecPrivkeyVer1),
  privateKey SM2PrivateKey,(其实X9.62中,这里是OCTETSTRING,而不是上面的INTEGER)
  parameters[0] Parameters{{IOSet}}OPTIONAL,
  publicKey [1] SM2PublicKey
}

其实上面的定义还不够完善,真正要实现私钥交换的话,还要封装成PKCS#8格式:
PrivateKeyInfo ::=SEQUENCE {
 version Version,
 privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
 privateKey PrivateKey,
 attributes [0] IMPLICIT Attributes OPTIONAL
}
Version ::=INTEGER (目前取0)
PrivateKeyAlgorithmIdentifier ::=AlgorithmIdentifier(和公钥定义相同)
PrivateKey ::=OCTET STRING(即是ECPrivateKey)

3.2  SM2公钥

SM2公钥是SM2曲线上的一个点,由横坐标和纵坐标两个分量来表示,记为(xy,简记为Q,长度为64字节。Q=kG,是私钥与曲线基点的乘积

SM2PublicKey::=BIT STRING

SM2PublicKey为类型,内容为04||X||Y,其中XY分别标识公钥的X分量和Y分量。其长度各为256位。

GMT0010SM2密码算法加密签名消息语法规范》中定义了和X9.62相同的主题公钥语法:

SubjectPublicKeyInfo ::= SEQUENCE {

 algorithm AlgorithmIdentifier{{ECPKAlgorithms}},

 subjectPublicKey SM2PublicKey

}

AlgorithmIdentifier::= SEQUENCE {

 algorithm OBJECTIDENTIFIER,

 parameters ANY DEFINED BY algorithm OPTIONAL

}

algorithm OIDX9.62相同:iso(1) member-body(2) us(840)ansi-x962(10045) keyType(2) ecPublicKey(1)

Parameters::= CHOICE {

  ecParametersECParameters,

  namedCurveObjectIdentifier,

  implicitlyCA NULL

}

参数是命名曲线OIDiso(1) member-body(2) cn(156) ccstc(10197) 1.301,即SM2。公钥数据是SM2PublicKey::= BIT STRING,即04||X||Y

3.3  加密后的SM2密钥对

SM2EnvelopedKey::=SEQUENCE{

symAlgID  AlgorithmIdentifier,--对称密码算法标识

symEncryptedKey  SM2Cipher,--对称密钥密文,参见

Sm2PublicKey SM2PublicKey,--SM2公钥

Sm2EncryptedPrivateKey BITSTRING  --SM2私钥密文(对称加密)

}

3.4  用户标识ID的默认值

无特殊约定的情况下,用户标识ID的长度为16字节,其默认值从左至右依次为:

0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38

4 运算过程

4.1  签名

设待签名的消息为M,为了获取消息M的数字签名(r,s),作为签名者的用户A应实现以下运算步骤:

A1:置M=ZAM;ZA= Hv(ENTLA||IDA||a||b||Gx||Gy||Ax||Ay);ENTLA为IDA的比特长度,2字节;IDA用户标识默认值见上节;a,b,Gx,Gy见曲线参数;Ax,Ay为公钥坐标

A2:计算e = Hv(M),按规则将e的数据类型转换为整数;

A3:用随机数发生器产生随机数k[1,n-1]

A4:计算椭圆曲线点(x1,y1)=[k]G,按规则将x1的数据类型转换为整数;

A5:计算r=(e+x1) modn,若r=0r+k=n则返回A3

A6:计算s = ((1 +dA)^−1 • (k − r • dA)) mod n,若s=0则返回A3

A7:按规则将rs的数据类型转换为字节串,消息M的签名为(r,s)

注:按上面的曲线参数,则rs分别为32字节,即签名值为64字节。但按照《SM2密码算法使用规范(GM/T 0009-2012)》,签名结果为ASN.1编码:

SM2Signature::= SEQUENCE {

R  INTEGER,  --签名值的第一部分

S  INTEGER      --签名值的第二部分

}

4.2  验证

为了检验收到的消息M′及其数字签名(r, s),作为验证者的用户B应实现以下运算步骤:

B1:检验r′ ∈[1,n-1]是否成立,若不成立则验证不通过;

B2:检验s′ ∈[1,n-1]是否成立,若不成立则验证不通过;

B3:置M=ZA M′;

B4:计算e = Hv(M),按规则将e′的数据类型转换为整数;

B5:按规则将r′、s′的数据类型转换为整数,计算t = (r + s) modn,若t = 0,则验证不通过;

B6:计算椭圆曲线点(x1; y1)=[s]G +[t]PA

B7:按规则将x1的数据类型转换为整数,计算R = (e + x1) modn,检验R=r′是否成立,若成立则验证通过;否则验证不通过。

 

X9.62 ECDSA的签名与验证过程:

签名:

1. Select a random or pseudorandom integerk, 1<=k<=n-1.

2. Compute [k]G = (x1,y1) and convert x1 toan integer x1`.

3. Compute r= x1 mod n. If r=0 then go tostep 1.

4. Compute k^-1 mod n.

5. Compute SHA-1(m) and convert this bitstring to an integer e.

6. Compute s = k^-1(e+dA*r) mod n. If s=0then go to step 1.

7. A's signature for the message m is(r,s).

验证:

1. Verify that r and s are integers in theinterval [1,n-1].

2. Compute SHA-1(m) and convert this bit stringto an integer e.

3. Compute w = s^-1 mod n€.

4. Compute u1= e*w mod n and u2= r*w modn€.

5. Compute X= [u1]G+[u2]PA.

6. If X=O, then reject the signature.

  Otherwise, convert the x-coordinate x1

4.3  加密

设需要发送的消息为比特串MklenM的比特长度。

为了对明文M进行加密,作为加密者的用户A应实现以下运算步骤:

A1:用随机数发生器产生随机数k[1,n-1]

A2:计算椭圆曲线点C1=[k]G=(x1,y1),按本文本第1部分4.2.84.2.4给出的细节,将C1的数据类型转换为比特串;

A3:计算椭圆曲线点S=[h]PB,若S是无穷远点,则报错并退出;

A4:计算椭圆曲线点[k]PB=(x2,y2),按本文本第1部分4.2.54.2.4给出的细节,将坐标x2y2的数据类型转换为比特串;

A5:计算t=KDF(x2 y2, klen),若t为全0比特串,则返回A1

A6:计算C2 = M t

A7:计算C3 = Hash(x2 M y2)

A8:输出密文C = C1 C3 C2

注:C1为‘04’开头,再加64字节的XYC332字节的Hash值,C2和明文长度相同。即加密结果是原文长度+97字节。但按照《SM2密码算法使用规范(GM/T 0009-2012)》,签名结果为ASN.1编码:

SM2Cipher::= SEQUENCE{

XCoordinate  INTEGER,  --x分量

YCoordinate  INTEGER,  --y分量

HASH      OCTECTSTRING SIZE(32), --杂凑值

CipherTextOCTECTSTRING--密文

}

4.4  解密

klen为密文中C2的比特长度。

为了对密文C=C1 C3 C2进行解密,作为解密者的用户B应实现以下运算步骤:

B1:从C中取出比特串C1,按本文本第1部分4.2.34.2.9给出的细节,将C1的数据类型转换为椭圆曲线上的点,验证C1是否满足椭圆曲线方程,若不满足则报错并退出;

B2:计算椭圆曲线点S=[h]C1,若S是无穷远点,则报错并退出;

B3:计算[dB]C1=(x2,y2),按本文本第1部分4.2.54.2.4给出的细节,将坐标x2y2的数据类型转换为比特串;

B4:计算t=KDF(x2 y2, klen),若t为全0比特串,则报错并退出;

B5:从C中取出比特串C2,计算M = C2 t

B6:计算u = Hash(x2 M′ ∥ y2),从C中取出比特串C3,若u ̸= C3,则报错并退出;

B7:输出明文M′。

5 加密消息语法

SM2密码算法加密签名消息语法规范》(GM/T0010-2012)基本参照了PKCS#7的语法,然后再定义了一些国密算法的OID。令人奇怪的是,国密对datasignedDataenvelopedData等还自定义了一套自己的OID,而不是沿用CMS已有的OID,实在看不出这样做有什么好处。

SM2密码算法加密签名消息语法规范:iso(1) member-body(2) cn(156) ccstc(10197) 6.1.4.2

PKCS#7 OIDiso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7)

6 数字证书

《基于SM2密码算法的数字证书格式规范》(GM/T0015-2012)定义的证书语法基本和RFC2459X.509证书格式相同。

国密还定义了一些证书扩展如:个人身份标识码、个人社会保险号、企业工商注册号、企业组织机构代码、企业税号等。

6.1  签名算法

算法OID为:1.2.156.10197.1.501。即SM3withSM2

参数为:NULL

6.2  主题公钥语法

参见本文“3.2 SM2公钥”对主题公钥的说明。


6.3  CA签名值

ASN.1编码的SM2Signature结构,见本文“4.1签名”

7 开发接口

7.1  国密接口

国密接口有3个标准:《GMT0016智能密码钥匙密码应用接口规范》、《GMT0018密码设备应用接口规范》、《GMT0019通用密码服务接口规范》。搞不清楚为什么要分这么多标准。

7.2  PKCS#11

7.2.1 算法类型


pkcs11t.h已定义的ECC宏有:
#define CKM_EC_KEY_PAIR_GEN            0x00001040
#define CKM_ECDSA                      0x00001041
……

自己扩展:
#define SM2_MYCA_DEFINED 0x92ca04
SM2密钥对产生
#define CKM_SM2_KEY_PAIR_GEN CKM_VENDOR_DEFINED+SM2_NETCA_DEFINED
SM2签名(传SM3 HASH值)
#define CKM_SM2DSA  CKM_SM2_KEY_PAIR_GEN+1
SM2加密
#define CKM_SM2IES  CKM_SM2_KEY_PAIR_GEN+2


7.2.2 密钥类型


#define CKK_EC              0x00000003
自己扩展:
#define CKK_SM2  CKK_VENDOR_DEFINED+SM2_MYCA_DEFINED


7.2.3 密钥模板


#define CKA_EC_PARAMS 0x00000180 (DER-encoding of an ANSI X9.62 Parameters value)
#define CKA_EC_POINT  0x00000181 (DER-encoding of ANSI X9.62 ECPoint value Q)
dA-->CKA_VALUE: (Biginteger)ANSI X9.62 private value d
PA(x,y)-->CKA_EC_POINT

7.3  CSP

Cryptographic Service Provider

CSP类型

在wincrypt.h有定义宏:
#define PROV_EC_ECDSA_FULL      16
#define PROV_EC_ECNRA_FULL      17


算法标识

在wincrypt.h有定义宏:
#define CALG_ECDH               (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH)
#define CALG_ECMQV              (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV)
#define CALG_ECDSA              (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA)


密钥结构

按《GMT0018密码设备应用接口规范》

#define ECCref_MAX_BITS 512
#define ECCref_MAX_LEN ((ECCref_MAX_BITS+7)/8)
typedefstruct ECCrefPublicKey_st
{
  unsigned int bits;
  unsigned char x[ECCref_MAX_LEN];
  unsigned char y[ECCref_MAX_LEN];
}ECCrefPublicKey;
typedefstruct ECCrefPrivateKey_st
{
  unsigned int bits;
  unsigned char K[ECCref_MAX_LEN];
}ECCrefPrivateKey;

7.4  CNG

Cryptographic Next Generation

7.5  JCE

SunEC提供者只能支持X6.92的命名曲线,如果ECParameterSpec传递SM2的曲线参数,最终将报异常:“java.security.InvalidAlgorithmParameterException:Unsupported curve”。如果用bouncycastle(“BC”), ECParameterSpec可以正常传递SM2的曲线参数,但由于SM2的签名与加密步骤都和X9.62/X9.63不同,所以出来的结果也不相同。需要自己在EC数学库的基础上实现SM2算法。


 

参考资料

  • SM2椭圆曲线公钥密码算法1部分:总则》(GM/T0003.1-2012),2012-03-21发布版本

  • SM2椭圆曲线公钥密码算法2部分:数字签名算法》(GM/T0003.2-2012),2012-03-21发布版本

  • SM2椭圆曲线公钥密码算法4部分:公钥加密算法》(GM/T0003.4-2012),2012-03-21发布版本

  • SM2椭圆曲线公钥密码算法5部分:参数定义》(GM/T0003.5-2012),2012-03-21发布版本

  • SM2密码算法使用规范》(GM/T0009-2012),2012-11-22发布版本

  • SM2密码算法加密签名消息语法规范》(GM/T0010-2012),2012-11-22发布版本

  • 《基于SM2密码算法的数字证书格式规范》(GM/T0015-2012),2012-11-22发布版本












你可能感兴趣的:(PKI/CA)