前段时间将系统的RSA算法全部升级为SM2国密算法,密码机和UKey硬件设备大都同时支持RSA和SM2算法,只是应用系统的加解密签名验证需要修改,这个更改底层调用的加密动态库来,原来RSA用的对称加密算法DES(AES)和摘要MD5(SHA1)也相应改变,分别对应SM1、SM3算法,SM1算法基于硬件实现,SM2、SM3算法已公开。
SM2签名验证算法
SM2签名同样也是需要先摘要原文数据,即先使用SM3密码杂凑算法计算出32byte摘要。SM3需要摘要签名方ID(默认1234567812345678)、曲线参数a,b,Gx,Gy、共钥坐标(x,y)计算出Z值,然后再杂凑原文得出摘要数据。这个地方要注意曲线参数和坐标点都是32byte,在转换为BigInteger大数计算转成字节流时要去掉空补位,否则可能会出现摘要计算不正确的问题。SM2签名实现如下:
SM2签名
public static BigInteger[] Sm2Sign(byte[] md, AsymmetricCipherKeyPair keypair)

...{
SM3Digest sm3 = new SM3Digest();

ECPublicKeyParameters ecpub = (ECPublicKeyParameters)keypair.Public;

byte[] z = SM2CryptoServiceProvider.Sm2GetZ(Encoding.Default.GetBytes(SM2CryptoServiceProvider.userId), ecpub.Q);
sm3.BlockUpdate(z, 0, z.Length);

byte[] p = md;
sm3.BlockUpdate(p, 0, p.Length);

byte[] hashData = new byte[32];
sm3.DoFinal(hashData, 0);

// e
BigInteger e = new BigInteger(1, hashData);
// k
BigInteger k = null;
ECPoint kp = null;
BigInteger r = null;
BigInteger s = null;
BigInteger userD = null;

do

...{
do

...{

ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)keypair.Private;
k = ecpriv.D;
kp = ecpub.Q;

userD = ecpriv.D;

// r
r = e.Add(kp.X.ToBigInteger());
r = r.Mod(ecc_n);
}
while (r.Equals(BigInteger.Zero) || r.Add(k).Equals(ecc_n));

// (1 + dA)~-1
BigInteger da_1 = userD.Add(BigInteger.One);
da_1 = da_1.ModInverse(ecc_n);
// s
s = r.Multiply(userD);
s = k.Subtract(s).Mod(ecc_n);
s = da_1.Multiply(s).Mod(ecc_n);
}
while (s.Equals(BigInteger.Zero));

byte[] btRS = new byte[64];
byte[] btR = r.ToByteArray();
byte[] btS = s.ToByteArray();
Array.Copy(btR, btR.Length - 32, btRS, 0, 32);
Array.Copy(btS, btS.Length - 32, btRS, 32, 32);


return new BigInteger[] ...{ r, s };
}
SM2算法是基于ECC算法的,签名同样返回2个大数,共64byte。由于原来RSA算法已很普遍支持,要实现RSA的签名验签都有标准库的实现,而SM2是国密算法在国际上还没有标准通用,算法Oid标识在X509标准中是没定义的。在.Net或Java中可以基于使用BouncyCastle加密库实现,开源的也比较好学习扩展。SM2算法验签可以使用软验签,即可以不需要使用硬件设备,同样使用原始数据、签名、证书(公钥)来实现对签名方验证,保证数据完整性未被篡改。验证过程同样需先摘要原文数据,公钥在证书中是以一个66byte的BitString,去掉前面标记位即64byte为共钥坐标(x,y),中间分割截取再以Hex方式转成BigInteger大数计算,验签代码如下:
SM2验签
public static bool Verify(byte[] msg, byte[] signData, byte[] certData)

...{

X509Certificate2 x5092 = new X509Certificate2(certData);
byte[] certPK = x5092.GetPublicKey();

certPK = SubByte(certPK, 1, 64);

byte[] certPKX = SubByte(certPK, certPK.Length - 32 - 32, 32);
byte[] certPKY = SubByte(certPK, certPK.Length - 32, 32);


System.String strcertPKX = ByteToHexStr(certPKX);
System.String strcertPKY = ByteToHexStr(certPKY);
BigInteger biX = new BigInteger(strcertPKX, 16);
BigInteger biY = new BigInteger(strcertPKY, 16);


ECFieldElement x = new FpFieldElement(ecc_p, biX);
ECFieldElement y = new FpFieldElement(ecc_p, biY);

ECPoint userKey = new FpPoint(ecc_curve, x, y);


SM3Digest sm3 = new SM3Digest();
byte[] z = Sm2GetZ(Encoding.Default.GetBytes(userId), userKey);
sm3.BlockUpdate(z, 0, z.Length);


byte[] p = msg;
sm3.BlockUpdate(p, 0, p.Length);

byte[] md = new byte[32];
sm3.DoFinal(md, 0);


byte[] btR = SubByte(signData, 0, 32);
byte[] btS = SubByte(signData, 32, 32);


System.String strR = ByteToHexStr(btR);
System.String strS = ByteToHexStr(btS);
BigInteger r = new BigInteger(strR, 16);
BigInteger s = new BigInteger(strS, 16);

// e_
BigInteger e = new BigInteger(1, md);
// t
BigInteger t = r.Add(s).Mod(ecc_n);

if (t.Equals(BigInteger.Zero))
return false;

// x1y1
ECPoint x1y1 = ecc_point_g.Multiply(s);
x1y1 = x1y1.Add(userKey.Multiply(t));

// R
BigInteger R = e.Add(x1y1.X.ToBigInteger()).Mod(ecc_n);

return r.Equals(R);
}
制作SM2证书
基于BouncyCastle开源库,可以轻松制作X509证书、CRL、pkcs10、pkcs12,支持国际通用的RSA、ECC算法。制作SM2证书可以通过扩展BouncyCastle库来实现,需加入SM2签名算法DerObjectIdentifier标识1.2.156.10197.1.501(基于SM3的SM2算法签名),密钥对的生成使用国密推荐曲线参数,然后如上所示自行实现SM2签名验证算法。X509证书由证书主体、证书签名算法标识、签名组成,和RSA证书主要不同的是SM2证书的签名算法标识和签名,及证书公钥使用ECKeyParameters。生成自签名SM2证书代码如下:
SM2证书生成
public static Org.BouncyCastle.X509.X509Certificate MakeRootCert(string filePath, IDictionary subjectNames)

...{
AsymmetricCipherKeyPair keypair = SM2CryptoServiceProvider.SM2KeyPairGenerator.GenerateKeyPair();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters)keypair.Public; //CA公钥
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters)keypair.Private; //CA私钥



X509Name issuerDN = new X509Name(GetDictionaryKeys(subjectNames), subjectNames);
X509Name subjectDN = issuerDN; //自签证书,两者一样

SM2X509V3CertificateGenerator sm2CertGen = new SM2X509V3CertificateGenerator();
//X509V3CertificateGenerator sm2CertGen = new X509V3CertificateGenerator();
sm2CertGen.SetSerialNumber(new BigInteger(128, new Random())); //128位
sm2CertGen.SetIssuerDN(issuerDN);
sm2CertGen.SetNotBefore(DateTime.UtcNow.AddDays(-1));
sm2CertGen.SetNotAfter(DateTime.UtcNow.AddDays(365 * 10));
sm2CertGen.SetSubjectDN(subjectDN);
sm2CertGen.SetPublicKey(pubKey); //公钥


sm2CertGen.SetSignatureAlgorithm("SM3WITHSM2");

sm2CertGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true));
sm2CertGen.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(pubKey));
sm2CertGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pubKey));
sm2CertGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(6));


Org.BouncyCastle.X509.X509Certificate sm2Cert = sm2CertGen.Generate(keypair);

sm2Cert.CheckValidity();
sm2Cert.Verify(pubKey);

return sm2Cert;
}
X509证书使用ASN1语法进行编码,是用类型标识、长度和值序列来描述数据结构的。SM2证书在制作设置公钥时,默认会带ECKeyParameters参数,并没有SM2的公钥参数1.2.156.10197.1.301,因此需要自己写个SM2椭圆曲线密码算法标识对象,这样在生成的证书中就可以看到公钥参数字段,如下所示:
SM2证书公钥标识
using System;

using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Asn1;


namespace Common.Security

...{
public class SM2AlgorithmIdentifier
: AlgorithmIdentifier

...{

private readonly bool parametersDefined;

public SM2AlgorithmIdentifier(
DerObjectIdentifier objectID):base(objectID)

...{

}


public SM2AlgorithmIdentifier(
DerObjectIdentifier objectID,
Asn1Encodable parameters)
: base(objectID, parameters)

...{
this.parametersDefined = true;
}


/**//**
* Produce an object suitable for an Asn1OutputStream.
* * AlgorithmIdentifier ::= Sequence {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL }
*
*/
public override Asn1Object ToAsn1Object()

...{
DerObjectIdentifier sm2Identifier = new DerObjectIdentifier("1.2.156.10197.1.301");
Asn1EncodableVector v = new Asn1EncodableVector(base.ObjectID, sm2Identifier);
return new DerSequence(v);
}

}
}
SM2算法是国密局公布的公钥密码算法,在相当强度下密钥比RSA短,在使用智能卡有限空间存储时非常可贵。目前国内很多CA大都升级支持SM2算法证书,相信以后会慢慢地推广更多应用,也期望之后能与国际标准接轨。
附:
国密推荐256位曲线参数
- p=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF
- a=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC
- b=28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93
- n=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123
- Gx=32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7
- Gy=BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0
SM2国密算法测试示例
- 引用
1楼 wahely 2013-10-09 10:11:55- 引用
2楼 wahely 2013-10-10 15:01:27SM3Digest类中主要是SM3杂凑摘要算法;
已发送至你邮箱了。(2013-10-11 22:43:13)
- 引用
3楼 grace 2013-11-18 15:43:23- 引用
4楼 grace 2013-11-18 15:43:25- 引用
5楼 xiaop 2014-03-05 17:12:27- 引用
6楼 xiaop 2014-03-12 14:04:06感谢博主
- 引用
7楼 etta 2014-03-25 11:04:13- 引用
8楼 etta 2014-03-28 09:26:42- 引用
9楼 wstxdyjk 2014-03-31 16:12:16- 引用
10楼 TKljx 2014-07-02 13:56:58279622644@qq.com
- 引用
11楼 TKljx 2014-07-02 13:57:01- 引用
12楼 TKljx 2014-07-02 13:57:02- 引用
13楼 treasure 2014-07-05 17:16:26- 引用
14楼 wuwei 2014-08-07 10:27:4553514512@qq.com[/quote]
- 引用
15楼 zzh 2014-08-07 10:29:26- 引用
16楼 fenggaowei 2014-09-03 16:54:58http://www.jonllen.com/Demo/SM3WithSM2.aspx
- 引用
17楼 liyh 2014-09-16 16:21:08- 引用
18楼 yyhakusu 2014-10-21 10:07:33这个论坛上发的这个问题应该和我遇到的是一样的,怎么解决的呢?谢谢
- 引用
19楼 yyhakusu 2014-10-22 08:40:37- 引用
20楼 yyhakusu 2014-10-23 09:56:59- 引用
21楼 kevin 2014-10-27 08:51:39谢谢!
- 引用
22楼 spacetime123 2014-11-18 12:05:17可以发我一份吗?sm2算法实现(签名+加解密+协商实现)
另外请问由自己实现的Provider吗?经过sun签名吗?
- 引用
23楼 spacetime123 2014-11-18 13:00:57我的邮箱spacetime123@126.com
谢谢
- 引用
24楼 spacetime123 2014-11-19 14:27:14- 引用
25楼 operamasks 2014-12-25 16:32:46- 引用
26楼 demonboa 2015-03-17 16:59:43- 引用
27楼 Stephen 2015-05-07 15:03:23- 引用
28楼 Stephen 2015-05-07 15:03:57743574255@qq.com
- 引用
29楼 justin 2016-01-26 14:48:24- 引用
30楼 明明 2016-03-20 21:48:47- 引用
31楼 明明 2016-03-20 21:48:49- 引用
32楼 openssl 2016-04-01 14:34:03- 引用
33楼 小李 2016-04-05 00:51:26- 引用
34楼 lhb 2016-04-25 20:07:17- 引用
35楼 小白 2016-05-09 16:28:06- 引用
36楼 xiaonan 2016-05-16 17:18:39- 引用
37楼 筱楠 2016-05-17 18:03:17- 引用
38楼 黑色的云 2016-05-20 16:34:31- 引用
39楼 feng 2016-05-22 15:48:41- 引用
40楼 安迪 2016-05-22 15:51:11- 引用
41楼 安迪 2016-05-22 15:51:14- 引用
42楼 小张 2016-05-23 15:54:43- 引用
43楼 天津 2016-05-25 20:37:55- 引用
44楼 qianlicao1046 2016-06-06 15:41:19- 引用
45楼 qianlicao1046 2016-06-06 15:41:20- 引用
46楼 qianlicao1046 2016-06-06 15:44:05- 引用
47楼 qianlicao1046 2016-06-08 15:27:49- 引用
48楼 千里草 2016-06-08 15:34:10- 引用
49楼 john 2016-07-26 14:38:17- 引用
50楼 terryliu 2016-09-03 11:51:46- 引用
51楼 terry 2016-09-03 17:05:01- 引用
52楼 terry 2016-09-03 17:06:23- 引用
53楼 Sophia 2016-09-26 21:27:46- 引用
54楼 epc 2016-10-15 21:15:23- 引用
55楼 wenQX 2016-10-19 19:28:37- 引用
56楼 2016-10-27 12:57:39- 引用
57楼 87392930 2016-10-28 08:16:44- 引用
58楼 hy 2016-11-12 00:05:47- 引用
59楼 TanXF 2016-12-06 09:47:31- 引用
60楼 TanXF 2016-12-06 09:47:32- 引用
61楼 TanXF 2016-12-10 09:26:26- 引用
62楼 1123 2017-01-18 12:23:57- 引用
63楼 1206679965 2017-01-20 16:35:58- 引用
64楼 你好 2017-01-24 11:13:19- 引用
65楼 你好 2017-01-24 11:15:53- 引用
66楼 宁 2017-06-19 12:00:15- 引用
67楼 john1 2017-07-25 17:16:06- 引用
68楼 zhuzhu 2017-08-23 16:48:31- 引用
69楼 zhuzhu 2017-08-23 16:50:26- 引用
70楼 or111 2017-09-12 21:59:18- 引用
71楼 baby 2017-10-20 15:05:59- 引用
72楼 ghost_520 2018-01-08 16:50:47- 引用
73楼 ckxf@qq.com 2018-01-27 16:48:43- 引用
74楼 ckxf@qq.com 2018-01-27 18:33:23- 引用
75楼 陈楠 2018-04-20 10:00:20- 引用
76楼 陈楠 2018-04-20 10:00:22- 引用
77楼 陈楠 2018-04-20 10:02:51- 引用
78楼 是深V 2018-06-04 09:49:01- 引用
79楼 是深V 2018-06-04 09:49:01- 引用
80楼 是深V 2018-06-04 09:49:03- 引用
81楼 是深V 2018-06-04 09:56:33- 引用
82楼 黄安琪 2018-07-04 20:52:28- 引用
83楼 huang 2018-07-06 11:22:13- 引用
84楼 huang 2018-07-06 11:23:46- 引用
85楼 我就是我 2018-08-05 22:18:11- 引用
86楼 pkk 2018-09-05 10:55:52- 引用
87楼 pkk 2018-09-05 10:55:52- 引用
88楼 pkk 2018-09-05 10:55:56- 引用
89楼 hjc 2020-04-16 14:56:27- 引用
90楼 hjc 2020-04-16 14:57:07- 引用
91楼 HellowWorld 2021-02-01 11:12:32- 引用
92楼 HellowWorld 2021-02-01 11:12:33- 引用
93楼 HellowWorld 2021-02-01 11:12:34- 引用
94楼 HellowWorld 2021-02-01 11:12:35- 引用
95楼 HellowWorld 2021-02-01 11:12:35- 引用
96楼 HellowWorld 2021-02-01 11:12:36- 引用
97楼 情比纸薄 2021-06-24 07:29:33- 引用
98楼 情比纸薄 2021-06-24 07:29:41- 引用
99楼 情比纸薄 2021-06-24 07:30:07- 引用
100楼 情比纸薄 2021-06-24 07:30:08- 引用
101楼 情比纸薄 2021-06-24 07:30:12- 引用
102楼 情比纸薄 2021-06-24 07:30:12- 引用
103楼 情比纸薄 2021-06-24 07:30:12- 引用
104楼 情比纸薄 2021-06-24 07:30:12- 引用
105楼 情比纸薄 2021-06-24 07:30:38- 引用
106楼 情比纸薄 2021-06-24 07:30:38- 引用
107楼 情比纸薄 2021-06-24 07:30:42- 引用
108楼 情比纸薄 2021-06-24 07:30:42- 引用
109楼 情比纸薄 2021-06-24 07:30:43- 引用
110楼 情比纸薄 2021-06-24 07:30:43- 引用
111楼 情比纸薄 2021-06-24 07:31:08- 引用
112楼 情比纸薄 2021-06-24 07:31:09- 引用
113楼 情比纸薄 2021-06-24 07:31:12- 引用
114楼 情比纸薄 2021-06-24 07:31:12- 引用
115楼 情比纸薄 2021-06-24 07:31:13- 引用
116楼 情比纸薄 2021-06-24 07:31:38- 引用
117楼 情比纸薄 2021-06-24 07:31:39- 引用
118楼 情比纸薄 2021-06-24 07:31:42- 引用
119楼 情比纸薄 2021-06-24 07:31:43- 引用
120楼 情比纸薄 2021-06-24 07:31:43- 引用
121楼 情比纸薄 2021-06-24 07:31:43- 引用
122楼 情比纸薄 2021-06-24 07:33:46- 引用
123楼 情比纸薄 2021-06-24 07:33:46- 引用
124楼 情比纸薄 2021-06-24 07:33:50- 引用
125楼 情比纸薄 2021-06-24 07:33:50- 引用
126楼 情比纸薄 2021-06-24 07:33:50- 引用
127楼 情比纸薄 2021-06-24 07:33:50- 引用
128楼 情比纸薄 2021-06-24 07:34:16- 引用
129楼 情比纸薄 2021-06-24 07:34:20- 引用
130楼 情比纸薄 2021-06-24 07:34:20- 引用
131楼 情比纸薄 2021-06-24 07:34:21- 引用
132楼 情比纸薄 2021-06-24 07:34:21- 引用
133楼 390620652 2022-06-08 11:08:20- 引用
134楼 390620652 2022-06-08 11:08:21- 引用
135楼 390620652 2022-06-08 11:08:21- 引用
136楼 390620652 2022-06-08 11:08:22- 引用
137楼 390620652 2022-06-08 11:08:22- 引用
138楼 390620652 2022-06-08 11:08:22- 引用
139楼 yufeng 2023-02-09 19:04:21- 引用
140楼 yufeng 2023-02-09 19:04:25- 引用
141楼 yufeng 2023-02-09 19:04:28- 引用
142楼 yufeng 2023-02-09 19:04:30- 引用
143楼 yufeng 2023-02-09 19:04:32- 引用
144楼 yufeng 2023-02-09 19:04:38- 引用
145楼 yufeng 2023-02-09 19:06:28- 引用
146楼 yufeng 2023-02-09 19:06:33- 引用
147楼 yufeng 2023-02-09 19:06:36- 引用
148楼 yufeng 2023-02-09 19:06:38- 引用
149楼 yufeng 2023-02-09 19:06:40- 引用
150楼 yufeng 2023-02-09 19:06:45- 引用
151楼 yufeng 2023-02-09 19:08:36