参考《SM2椭圆曲线公钥密码算法第1部分:总则》(GM/T0003.1-2012),2012-03-21发布版本。
定义在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)的阶。
定义在F2m上的椭圆曲线方程为:
y2+xy = x3+ax2+b,a;b∈ F2m,且b ̸= 0。-------------------- (2)
椭圆曲线E(F2m )定义为:
E(F2m) = {(x;y)|x;y∈ F2m,且满足方程(2)}∪{O},其中O是无穷远点。
椭圆曲线E(F2m )上的点的数目用#E(F2m)表示,称为椭圆曲线E(F2m )的阶。
参考《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命名曲线有很多,下面略举2条Fp曲线:
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
参考《SM2密码算法使用规范》(GM/T0009-2012),2012-11-22发布版本。
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)
SM2公钥是SM2曲线上的一个点,由横坐标和纵坐标两个分量来表示,记为(x,y),简记为Q,长度为64字节。Q=kG,是私钥与曲线基点的乘积。
SM2PublicKey::=BIT STRING
SM2PublicKey为类型,内容为04||X||Y,其中X和Y分别标识公钥的X分量和Y分量。其长度各为256位。
《GMT0010SM2密码算法加密签名消息语法规范》中定义了和X9.62相同的主题公钥语法:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier{{ECPKAlgorithms}},
subjectPublicKey SM2PublicKey
}
AlgorithmIdentifier::= SEQUENCE {
algorithm OBJECTIDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
algorithm OID和X9.62相同:iso(1) member-body(2) us(840)ansi-x962(10045) keyType(2) ecPublicKey(1)
Parameters::= CHOICE {
ecParametersECParameters,
namedCurveObjectIdentifier,
implicitlyCA NULL
}
参数是命名曲线OID:iso(1) member-body(2) cn(156) ccstc(10197) 1.301,即SM2。公钥数据是SM2PublicKey::= BIT STRING,即04||X||Y
SM2EnvelopedKey::=SEQUENCE{
symAlgID AlgorithmIdentifier,--对称密码算法标识
symEncryptedKey SM2Cipher,--对称密钥密文,参见
Sm2PublicKey SM2PublicKey,--SM2公钥
Sm2EncryptedPrivateKey BITSTRING --SM2私钥密文(对称加密)
}
无特殊约定的情况下,用户标识ID的长度为16字节,其默认值从左至右依次为:
0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38。
设待签名的消息为M,为了获取消息M的数字签名(r,s),作为签名者的用户A应实现以下运算步骤:
A1:置M’=ZA∥M;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=0或r+k=n则返回A3;
A6:计算s = ((1 +dA)^−1 • (k − r • dA)) mod n,若s=0则返回A3;
A7:按规则将r、s的数据类型转换为字节串,消息M的签名为(r,s)。
注:按上面的曲线参数,则r和s分别为32字节,即签名值为64字节。但按照《SM2密码算法使用规范(GM/T 0009-2012)》,签名结果为ASN.1编码:
SM2Signature::= SEQUENCE {
R INTEGER, --签名值的第一部分
S INTEGER --签名值的第二部分
}
为了检验收到的消息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:计算椭圆曲线点(x′1; y′1)=[s′]G +[t]PA
B7:按规则将x′1的数据类型转换为整数,计算R = (e′ + x′1) 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
设需要发送的消息为比特串M,klen为M的比特长度。
为了对明文M进行加密,作为加密者的用户A应实现以下运算步骤:
A1:用随机数发生器产生随机数k∈[1,n-1];
A2:计算椭圆曲线点C1=[k]G=(x1,y1),按本文本第1部分4.2.8和4.2.4给出的细节,将C1的数据类型转换为比特串;
A3:计算椭圆曲线点S=[h]PB,若S是无穷远点,则报错并退出;
A4:计算椭圆曲线点[k]PB=(x2,y2),按本文本第1部分4.2.5和4.2.4给出的细节,将坐标x2、y2的数据类型转换为比特串;
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字节的X和Y,C3为32字节的Hash值,C2和明文长度相同。即加密结果是原文长度+97字节。但按照《SM2密码算法使用规范(GM/T 0009-2012)》,签名结果为ASN.1编码:
SM2Cipher::= SEQUENCE{
XCoordinate INTEGER, --x分量
YCoordinate INTEGER, --y分量
HASH OCTECTSTRING SIZE(32), --杂凑值
CipherTextOCTECTSTRING--密文
}
设klen为密文中C2的比特长度。
为了对密文C=C1∥ C3∥ C2进行解密,作为解密者的用户B应实现以下运算步骤:
B1:从C中取出比特串C1,按本文本第1部分4.2.3和4.2.9给出的细节,将C1的数据类型转换为椭圆曲线上的点,验证C1是否满足椭圆曲线方程,若不满足则报错并退出;
B2:计算椭圆曲线点S=[h]C1,若S是无穷远点,则报错并退出;
B3:计算[dB]C1=(x2,y2),按本文本第1部分4.2.5和4.2.4给出的细节,将坐标x2、y2的数据类型转换为比特串;
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′。
《SM2密码算法加密签名消息语法规范》(GM/T0010-2012)基本参照了PKCS#7的语法,然后再定义了一些国密算法的OID。令人奇怪的是,国密对data、signedData、envelopedData等还自定义了一套自己的OID,而不是沿用CMS已有的OID,实在看不出这样做有什么好处。
SM2密码算法加密签名消息语法规范:iso(1) member-body(2) cn(156) ccstc(10197) 6.1.4.2
PKCS#7 OID:iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7)
《基于SM2密码算法的数字证书格式规范》(GM/T0015-2012)定义的证书语法基本和RFC2459的X.509证书格式相同。
国密还定义了一些证书扩展如:个人身份标识码、个人社会保险号、企业工商注册号、企业组织机构代码、企业税号等。
算法OID为:1.2.156.10197.1.501。即SM3withSM2。
参数为:NULL
参见本文“3.2 SM2公钥”对主题公钥的说明。
是ASN.1编码的SM2Signature结构,见本文“4.1签名”
国密接口有3个标准:《GMT0016智能密码钥匙密码应用接口规范》、《GMT0018密码设备应用接口规范》、《GMT0019通用密码服务接口规范》。搞不清楚为什么要分这么多标准。
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
#define CKK_EC 0x00000003
自己扩展:
#define CKK_SM2 CKK_VENDOR_DEFINED+SM2_MYCA_DEFINED
#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
Cryptographic Service Provider
在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;
Cryptographic Next Generation
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发布版本