国密算法java源码_国密算法SM2证书制作

本文详细介绍了如何使用Java实现国密SM2算法,包括SM2签名验证算法的步骤,以及如何制作SM2证书。通过BouncyCastle库,实现了SM2签名、验签,并给出了自签名SM2证书的生成代码。文章还提到了国密推荐的256位曲线参数,指出SM2算法在安全性与密钥长度之间的优势。
摘要由CSDN通过智能技术生成

前段时间将系统的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签名实现如下:

293384dfdbebf4a68403c3e04d11e3a0.gifSM2签名

f82d653e25f5b2ae14305a4a7b95f6b2.gifpublicstaticBigInteger[] Sm2Sign(byte[] md, AsymmetricCipherKeyPair keypair)

58c3266e906d263a226ad7cb5f2738be.gif

293384dfdbebf4a68403c3e04d11e3a0.gif...{

31bf357972705fcb86ef56e26687bd02.gif SM3Digest sm3=newSM3Digest();

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif ECPublicKeyParameters ecpub=(ECPublicKeyParameters)keypair.Public;

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifbyte[] z=SM2CryptoServiceProvider.Sm2GetZ(Encoding.Default.GetBytes(SM2CryptoServiceProvider.userId), ecpub.Q);

31bf357972705fcb86ef56e26687bd02.gif sm3.BlockUpdate(z,0, z.Length);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifbyte[] p=md;

31bf357972705fcb86ef56e26687bd02.gif sm3.BlockUpdate(p,0, p.Length);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifbyte[] hashData=newbyte[32];

31bf357972705fcb86ef56e26687bd02.gif sm3.DoFinal(hashData,0);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif//e31bf357972705fcb86ef56e26687bd02.gifBigInteger e=newBigInteger(1, hashData);

31bf357972705fcb86ef56e26687bd02.gif//k31bf357972705fcb86ef56e26687bd02.gifBigInteger k=null;

31bf357972705fcb86ef56e26687bd02.gif ECPoint kp=null;

31bf357972705fcb86ef56e26687bd02.gif BigInteger r=null;

31bf357972705fcb86ef56e26687bd02.gif BigInteger s=null;

31bf357972705fcb86ef56e26687bd02.gif BigInteger userD=null;

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifdob8322e5cb9aa26914065dd81201a48a1.gif

388501a28159dc49db27bb8c20a49886.gif...{

31bf357972705fcb86ef56e26687bd02.gifdob8322e5cb9aa26914065dd81201a48a1.gif

388501a28159dc49db27bb8c20a49886.gif...{

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif ECPrivateKeyParameters ecpriv=(ECPrivateKeyParameters)keypair.Private;

31bf357972705fcb86ef56e26687bd02.gif k=ecpriv.D;

31bf357972705fcb86ef56e26687bd02.gif kp=ecpub.Q;

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif userD=ecpriv.D;

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif//r31bf357972705fcb86ef56e26687bd02.gifr=e.Add(kp.X.ToBigInteger());

31bf357972705fcb86ef56e26687bd02.gif r=r.Mod(ecc_n);

545ba3e5b443562604c78421e3b51725.gif }31bf357972705fcb86ef56e26687bd02.gifwhile(r.Equals(BigInteger.Zero)||r.Add(k).Equals(ecc_n));

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif//(1 + dA)~-131bf357972705fcb86ef56e26687bd02.gifBigInteger da_1=userD.Add(BigInteger.One);

31bf357972705fcb86ef56e26687bd02.gif da_1=da_1.ModInverse(ecc_n);

31bf357972705fcb86ef56e26687bd02.gif//s31bf357972705fcb86ef56e26687bd02.gifs=r.Multiply(userD);

31bf357972705fcb86ef56e26687bd02.gif s=k.Subtract(s).Mod(ecc_n);

31bf357972705fcb86ef56e26687bd02.gif s=da_1.Multiply(s).Mod(ecc_n);

545ba3e5b443562604c78421e3b51725.gif }31bf357972705fcb86ef56e26687bd02.gifwhile(s.Equals(BigInteger.Zero));

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifbyte[] btRS=newbyte[64];

31bf357972705fcb86ef56e26687bd02.gifbyte[] btR=r.ToByteArray();

31bf357972705fcb86ef56e26687bd02.gifbyte[] btS=s.ToByteArray();

31bf357972705fcb86ef56e26687bd02.gif Array.Copy(btR, btR.Length-32, btRS,0,32);

31bf357972705fcb86ef56e26687bd02.gif Array.Copy(btS, btS.Length-32, btRS,32,32);

31bf357972705fcb86ef56e26687bd02.gif

b8322e5cb9aa26914065dd81201a48a1.gif

388501a28159dc49db27bb8c20a49886.gifreturnnewBigInteger[]...{ r, s };

bcd1cc8e222888473e6048322d6df694.gif}

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

293384dfdbebf4a68403c3e04d11e3a0.gifSM2验签

f82d653e25f5b2ae14305a4a7b95f6b2.gifpublicstaticboolVerify(byte[] msg,byte[] signData,byte[] certData)

58c3266e906d263a226ad7cb5f2738be.gif

293384dfdbebf4a68403c3e04d11e3a0.gif...{

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif X509Certificate2 x5092=newX509Certificate2(certData);

31bf357972705fcb86ef56e26687bd02.gifbyte[] certPK=x5092.GetPublicKey();

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif certPK=SubByte(certPK,1,64);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifbyte[] certPKX=SubByte(certPK, certPK.Length-32-32,32);

31bf357972705fcb86ef56e26687bd02.gifbyte[] certPKY=SubByte(certPK, certPK.Length-32,32);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif System.String strcertPKX=ByteToHexStr(certPKX);

31bf357972705fcb86ef56e26687bd02.gif System.String strcertPKY=ByteToHexStr(certPKY);

31bf357972705fcb86ef56e26687bd02.gif BigInteger biX=newBigInteger(strcertPKX,16);

31bf357972705fcb86ef56e26687bd02.gif BigInteger biY=newBigInteger(strcertPKY,16);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif ECFieldElement x=newFpFieldElement(ecc_p, biX);

31bf357972705fcb86ef56e26687bd02.gif ECFieldElement y=newFpFieldElement(ecc_p, biY);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif ECPoint userKey=newFpPoint(ecc_curve, x, y);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif SM3Digest sm3=newSM3Digest();

31bf357972705fcb86ef56e26687bd02.gifbyte[] z=Sm2GetZ(Encoding.Default.GetBytes(userId), userKey);

31bf357972705fcb86ef56e26687bd02.gif sm3.BlockUpdate(z,0, z.Length);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifbyte[] p=msg;

31bf357972705fcb86ef56e26687bd02.gif sm3.BlockUpdate(p,0, p.Length);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifbyte[] md=newbyte[32];

31bf357972705fcb86ef56e26687bd02.gif sm3.DoFinal(md,0);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifbyte[] btR=SubByte(signData,0,32);

31bf357972705fcb86ef56e26687bd02.gifbyte[] btS=SubByte(signData,32,32);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif System.String strR=ByteToHexStr(btR);

31bf357972705fcb86ef56e26687bd02.gif System.String strS=ByteToHexStr(btS);

31bf357972705fcb86ef56e26687bd02.gif BigInteger r=newBigInteger(strR,16);

31bf357972705fcb86ef56e26687bd02.gif BigInteger s=newBigInteger(strS,16);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif//e_31bf357972705fcb86ef56e26687bd02.gifBigInteger e=newBigInteger(1, md);

31bf357972705fcb86ef56e26687bd02.gif//t31bf357972705fcb86ef56e26687bd02.gifBigInteger t=r.Add(s).Mod(ecc_n);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifif(t.Equals(BigInteger.Zero))

31bf357972705fcb86ef56e26687bd02.gifreturnfalse;

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif//x1y131bf357972705fcb86ef56e26687bd02.gifECPoint x1y1=ecc_point_g.Multiply(s);

31bf357972705fcb86ef56e26687bd02.gif x1y1=x1y1.Add(userKey.Multiply(t));

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif//R31bf357972705fcb86ef56e26687bd02.gifBigInteger R=e.Add(x1y1.X.ToBigInteger()).Mod(ecc_n);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifreturnr.Equals(R);

bcd1cc8e222888473e6048322d6df694.gif}

制作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证书代码如下:

293384dfdbebf4a68403c3e04d11e3a0.gifSM2证书生成

f82d653e25f5b2ae14305a4a7b95f6b2.gifpublicstaticOrg.BouncyCastle.X509.X509Certificate MakeRootCert(stringfilePath, IDictionary subjectNames)

58c3266e906d263a226ad7cb5f2738be.gif

293384dfdbebf4a68403c3e04d11e3a0.gif...{

31bf357972705fcb86ef56e26687bd02.gif AsymmetricCipherKeyPair keypair=SM2CryptoServiceProvider.SM2KeyPairGenerator.GenerateKeyPair();

31bf357972705fcb86ef56e26687bd02.gif ECPublicKeyParameters pubKey=(ECPublicKeyParameters)keypair.Public;//CA公钥31bf357972705fcb86ef56e26687bd02.gifECPrivateKeyParameters priKey=(ECPrivateKeyParameters)keypair.Private;//CA私钥31bf357972705fcb86ef56e26687bd02.gif31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif X509Name issuerDN=newX509Name(GetDictionaryKeys(subjectNames), subjectNames);

31bf357972705fcb86ef56e26687bd02.gif X509Name subjectDN=issuerDN;//自签证书,两者一样31bf357972705fcb86ef56e26687bd02.gif31bf357972705fcb86ef56e26687bd02.gif SM2X509V3CertificateGenerator sm2CertGen=newSM2X509V3CertificateGenerator();

31bf357972705fcb86ef56e26687bd02.gif//X509V3CertificateGenerator sm2CertGen = new X509V3CertificateGenerator();31bf357972705fcb86ef56e26687bd02.gifsm2CertGen.SetSerialNumber(newBigInteger(128,newRandom()));//128位31bf357972705fcb86ef56e26687bd02.gifsm2CertGen.SetIssuerDN(issuerDN);

31bf357972705fcb86ef56e26687bd02.gif sm2CertGen.SetNotBefore(DateTime.UtcNow.AddDays(-1));

31bf357972705fcb86ef56e26687bd02.gif sm2CertGen.SetNotAfter(DateTime.UtcNow.AddDays(365*10));

31bf357972705fcb86ef56e26687bd02.gif sm2CertGen.SetSubjectDN(subjectDN);

31bf357972705fcb86ef56e26687bd02.gif sm2CertGen.SetPublicKey(pubKey);//公钥31bf357972705fcb86ef56e26687bd02.gif31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif sm2CertGen.SetSignatureAlgorithm("SM3WITHSM2");

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif sm2CertGen.AddExtension(X509Extensions.BasicConstraints,true,newBasicConstraints(true));

31bf357972705fcb86ef56e26687bd02.gif sm2CertGen.AddExtension(X509Extensions.SubjectKeyIdentifier,false,newSubjectKeyIdentifierStructure(pubKey));

31bf357972705fcb86ef56e26687bd02.gif sm2CertGen.AddExtension(X509Extensions.AuthorityKeyIdentifier,false,newAuthorityKeyIdentifierStructure(pubKey));

31bf357972705fcb86ef56e26687bd02.gif sm2CertGen.AddExtension(X509Extensions.KeyUsage,true,newKeyUsage(6));

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif

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

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif sm2Cert.CheckValidity();

31bf357972705fcb86ef56e26687bd02.gif sm2Cert.Verify(pubKey);

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifreturnsm2Cert;

bcd1cc8e222888473e6048322d6df694.gif}

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

293384dfdbebf4a68403c3e04d11e3a0.gifSM2证书公钥标识

f82d653e25f5b2ae14305a4a7b95f6b2.gifusingSystem;

f82d653e25f5b2ae14305a4a7b95f6b2.gif

f82d653e25f5b2ae14305a4a7b95f6b2.gifusingOrg.BouncyCastle.Asn1.X509;

f82d653e25f5b2ae14305a4a7b95f6b2.gifusingOrg.BouncyCastle.Asn1;

f82d653e25f5b2ae14305a4a7b95f6b2.gif

f82d653e25f5b2ae14305a4a7b95f6b2.gif

f82d653e25f5b2ae14305a4a7b95f6b2.gifnamespaceCommon.Security

58c3266e906d263a226ad7cb5f2738be.gif

293384dfdbebf4a68403c3e04d11e3a0.gif...{

31bf357972705fcb86ef56e26687bd02.gifpublicclassSM2AlgorithmIdentifier

31bf357972705fcb86ef56e26687bd02.gif : AlgorithmIdentifier

b8322e5cb9aa26914065dd81201a48a1.gif

388501a28159dc49db27bb8c20a49886.gif...{

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifprivatereadonlyboolparametersDefined;

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifpublicSM2AlgorithmIdentifier(

31bf357972705fcb86ef56e26687bd02.gif DerObjectIdentifier objectID):base(objectID)

b8322e5cb9aa26914065dd81201a48a1.gif

388501a28159dc49db27bb8c20a49886.gif...{

31bf357972705fcb86ef56e26687bd02.gif

545ba3e5b443562604c78421e3b51725.gif }31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gif

31bf357972705fcb86ef56e26687bd02.gifpublicSM2AlgorithmIdentifier(

31bf357972705fcb86ef56e26687bd02.gif DerObjectIdentifier objectID,

31bf357972705fcb86ef56e26687bd02.gif Asn1Encodable parameters)

31bf357972705fcb86ef56e26687bd02.gif :base(objectID, parameters)

b8322e5cb9aa26914065dd81201a48a1.gif

388501a28159dc49db27bb8c20a49886.gif...{

31bf357972705fcb86ef56e26687bd02.gifthis.parametersDefined=true;

545ba3e5b443562604c78421e3b51725.gif }31bf357972705fcb86ef56e26687bd02.gif

b8322e5cb9aa26914065dd81201a48a1.gif

388501a28159dc49db27bb8c20a49886.gif/**//**

31bf357972705fcb86ef56e26687bd02.gif * Produce an object suitable for an Asn1OutputStream.

31bf357972705fcb86ef56e26687bd02.gif * * AlgorithmIdentifier ::= Sequence {

31bf357972705fcb86ef56e26687bd02.gif * algorithm OBJECT IDENTIFIER,

31bf357972705fcb86ef56e26687bd02.gif * parameters ANY DEFINED BY algorithm OPTIONAL }

31bf357972705fcb86ef56e26687bd02.gif *

545ba3e5b443562604c78421e3b51725.gif*/31bf357972705fcb86ef56e26687bd02.gifpublicoverrideAsn1Object ToAsn1Object()

b8322e5cb9aa26914065dd81201a48a1.gif

388501a28159dc49db27bb8c20a49886.gif...{

31bf357972705fcb86ef56e26687bd02.gif DerObjectIdentifier sm2Identifier=newDerObjectIdentifier("1.2.156.10197.1.301");

31bf357972705fcb86ef56e26687bd02.gif Asn1EncodableVector v=newAsn1EncodableVector(base.ObjectID, sm2Identifier);

31bf357972705fcb86ef56e26687bd02.gifreturnnewDerSequence(v);

545ba3e5b443562604c78421e3b51725.gif }31bf357972705fcb86ef56e26687bd02.gif

545ba3e5b443562604c78421e3b51725.gif }bcd1cc8e222888473e6048322d6df694.gif}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值