java制作SM2证书
原文地址:Fight With Me!!!
制作SM2證書
前段時(shí)間將系統(tǒng)的RSA算法全部升級(jí)為SM2國密算法,密碼機(jī)和UKey硬件設(shè)備大都同時(shí)支持RSA和SM2算法,只是應(yīng)用系統(tǒng)的加解密簽名驗(yàn)證需要修改,這個(gè)更改底層調(diào)用的加密動(dòng)態(tài)庫來,原來RSA用的對(duì)稱加密算法DES(AES)和摘要MD5(SHA1)也相應(yīng)改變,分別對(duì)應(yīng)SM1、SM3算法,SM1算法基于硬件實(shí)現(xiàn),SM2、SM3算法已公開。
SM2簽名驗(yàn)證算法
SM2簽名同樣也是需要先摘要原文數(shù)據(jù),即先使用SM3密碼雜湊算法計(jì)算出32byte摘要。SM3需要摘要簽名方ID(默認(rèn)1234567812345678)、曲線參數(shù)a,b,Gx,Gy、共鑰坐標(biāo)(x,y)計(jì)算出Z值,然后再雜湊原文得出摘要數(shù)據(jù)。這個(gè)地方要注意曲線參數(shù)和坐標(biāo)點(diǎn)都是32byte,在轉(zhuǎn)換為BigInteger大數(shù)計(jì)算轉(zhuǎn)成字節(jié)流時(shí)要去掉空補(bǔ)位,否則可能會(huì)出現(xiàn)摘要計(jì)算不正確的問題。SM2簽名實(shí)現(xiàn)如下:
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);// eBigInteger e = new BigInteger(1, hashData);// kBigInteger 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;// rr = e.Add(kp.X.ToBigInteger());r = r.Mod(ecc_n);}while (r.Equals(BigInteger.Zero) || r.Add(k).Equals(ecc_n));// (1 + dA)~-1BigInteger da_1 = userD.Add(BigInteger.One);da_1 = da_1.ModInverse(ecc_n);// ss = 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個(gè)大數(shù),共64byte。由于原來RSA算法已很普遍支持,要實(shí)現(xiàn)RSA的簽名驗(yàn)簽都有標(biāo)準(zhǔn)庫的實(shí)現(xiàn),而SM2是國密算法在國際上還沒有標(biāo)準(zhǔn)通用,算法Oid標(biāo)識(shí)在X509標(biāo)準(zhǔn)中是沒定義的。在.Net或Java中可以基于使用BouncyCastle加密庫實(shí)現(xiàn),開源的也比較好學(xué)習(xí)擴(kuò)展。SM2算法驗(yàn)簽可以使用軟驗(yàn)簽,即可以不需要使用硬件設(shè)備,同樣使用原始數(shù)據(jù)、簽名、證書(公鑰)來實(shí)現(xiàn)對(duì)簽名方驗(yàn)證,保證數(shù)據(jù)完整性未被篡改。驗(yàn)證過程同樣需先摘要原文數(shù)據(jù),公鑰在證書中是以一個(gè)66byte的BitString,去掉前面標(biāo)記位即64byte為共鑰坐標(biāo)(x,y),中間分割截取再以Hex方式轉(zhuǎn)成BigInteger大數(shù)計(jì)算,驗(yàn)簽代碼如下:
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);// tBigInteger t = r.Add(s).Mod(ecc_n);if (t.Equals(BigInteger.Zero))return false;// x1y1ECPoint x1y1 = ecc_point_g.Multiply(s);x1y1 = x1y1.Add(userKey.Multiply(t));// RBigInteger R = e.Add(x1y1.X.ToBigInteger()).Mod(ecc_n);return r.Equals(R); }制作SM2證書
基于BouncyCastle開源庫,可以輕松制作X509證書、CRL、pkcs10、pkcs12,支持國際通用的RSA、ECC算法。制作SM2證書可以通過擴(kuò)展BouncyCastle庫來實(shí)現(xiàn),需加入SM2簽名算法DerObjectIdentifier標(biāo)識(shí)1.2.156.10197.1.501(基于SM3的SM2算法簽名),密鑰對(duì)的生成使用國密推薦曲線參數(shù),然后如上所示自行實(shí)現(xiàn)SM2簽名驗(yàn)證算法。X509證書由證書主體、證書簽名算法標(biāo)識(shí)、簽名組成,和RSA證書主要不同的是SM2證書的簽名算法標(biāo)識(shí)和簽名,及證書公鑰使用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語法進(jìn)行編碼,是用類型標(biāo)識(shí)、長度和值序列來描述數(shù)據(jù)結(jié)構(gòu)的。SM2證書在制作設(shè)置公鑰時(shí),默認(rèn)會(huì)帶ECKeyParameters參數(shù),并沒有SM2的公鑰參數(shù)1.2.156.10197.1.301,因此需要自己寫個(gè)SM2橢圓曲線密碼算法標(biāo)識(shí)對(duì)象,這樣在生成的證書中就可以看到公鑰參數(shù)字段,如下所示:
SM2證書公鑰標(biāo)識(shí)
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算法是國密局公布的公鑰密碼算法,在相當(dāng)強(qiáng)度下密鑰比RSA短,在使用智能卡有限空間存儲(chǔ)時(shí)非常可貴。目前國內(nèi)很多CA大都升級(jí)支持SM2算法證書,相信以后會(huì)慢慢地推廣更多應(yīng)用,也期望之后能與國際標(biāo)準(zhǔn)接軌。
附:
國密推薦256位曲線參數(shù)
- 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國密算法測試示例
總結(jié)
以上是生活随笔為你收集整理的java制作SM2证书的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 经典快速制作套打证书模板(doc)大全
- 下一篇: CA证书制作实战