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+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 )的階。
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命名曲線有很多,下面略舉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
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曲線上的一個點,由橫座標和縱座標兩個分量來表示,記爲(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
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’=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 --簽名值的第二部分
}
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:計算橢圓曲線點(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
4.3 加密
設需要發送的消息爲比特串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--密文
}
4.4 解密
設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′。
5 加密消息語法
《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)
6 數字證書
《基於SM2密碼算法的數字證書格式規範》(GM/T0015-2012)定義的證書語法基本和RFC2459的X.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發佈版本