java实现sm2证书基于BouncyCastle

来源:互联网 发布:node.js webpack vue 编辑:程序博客网 时间:2024/06/05 08:30

SM2签名同样也是需要先摘要原文数据,即先使用SM3密码杂凑算法计算出32byte摘要。SM3需要摘要签名方ID(默认1234567812345678)、曲线参数a,b,Gx,Gy、共钥坐标(x,y)计算出Z值,然后再杂凑原文得出摘要数据。这个地方要注意曲线参数和坐标点都是32byte,在转换为BigInteger大数计算转成字节流时要去掉空补位,否则可能会出现摘要计算不正确的问题。SM2签名实现如下:

java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客SM2签名
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客public static BigInteger[] Sm2Sign(byte[] md, AsymmetricCipherKeyPair keypair)java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客{java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 SM3Digest sm3 = new SM3Digest();java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 ECPublicKeyParameters ecpub = (ECPublicKeyParameters)keypair.Public;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 byte[] z = SM2CryptoServiceProvider.Sm2GetZ(Encoding.Default.GetBytes(SM2CryptoServiceProvider.userId), ecpub.Q);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm3.BlockUpdate(z, 0, z.Length);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 byte[] p = md;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm3.BlockUpdate(p, 0, p.Length);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 byte[] hashData = new byte[32];java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm3.DoFinal(hashData, 0);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 // ejava实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 BigInteger e = new BigInteger(1, hashData);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 // kjava实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 BigInteger k = null;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 ECPoint kp = null;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 BigInteger r = null;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 BigInteger s = null;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 BigInteger userD = null;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 dojava实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 {java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 dojava实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 {java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)keypair.Private;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 k = ecpriv.D;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 kp = ecpub.Q;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 userD = ecpriv.D;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 // rjava实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 r = e.Add(kp.X.ToBigInteger());java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 r = r.Mod(ecc_n);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 }java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 while (r.Equals(BigInteger.Zero) || r.Add(k).Equals(ecc_n));java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 // (1 + dA)~-1java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 BigInteger da_1 = userD.Add(BigInteger.One);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 da_1 = da_1.ModInverse(ecc_n);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 // sjava实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 s = r.Multiply(userD);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 s = k.Subtract(s).Mod(ecc_n);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 s = da_1.Multiply(s).Mod(ecc_n);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 }java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 while (s.Equals(BigInteger.Zero));java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 byte[] btRS = new byte[64];java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 byte[] btR = r.ToByteArray();java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 byte[] btS = s.ToByteArray();java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 Array.Copy(btR, btR.Length - 32, btRS, 0, 32);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 Array.Copy(btS, btS.Length - 32, btRS, 32, 32);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 return new BigInteger[] { r, s };java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客}

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

java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客SM2验签
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客publicstatic bool Verify(byte[] msg,byte[] signData,byte[] certData)
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
{
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            X509Certificate2 x5092
= new X509Certificate2(certData);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
byte[] certPK= x5092.GetPublicKey();
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            certPK
= SubByte(certPK,1, 64);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
byte[] certPKX= SubByte(certPK, certPK.Length- 32- 32,32);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
byte[] certPKY= SubByte(certPK, certPK.Length- 32,32);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            System.String strcertPKX
= ByteToHexStr(certPKX);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            System.String strcertPKY
= ByteToHexStr(certPKY);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            BigInteger biX
= new BigInteger(strcertPKX,16);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            BigInteger biY
= new BigInteger(strcertPKY,16);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            ECFieldElement x
= new FpFieldElement(ecc_p, biX);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            ECFieldElement y
= new FpFieldElement(ecc_p, biY);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            ECPoint userKey
= new FpPoint(ecc_curve, x, y);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            SM3Digest sm3
= new SM3Digest();
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
byte[] z = Sm2GetZ(Encoding.Default.GetBytes(userId), userKey);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            sm3.BlockUpdate(z,
0, z.Length);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
byte[] p = msg;
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            sm3.BlockUpdate(p,
0, p.Length);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
byte[] md = newbyte[32];
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            sm3.DoFinal(md,
0);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
byte[] btR = SubByte(signData,0, 32);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
byte[] btS = SubByte(signData,32, 32);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            System.String strR
= ByteToHexStr(btR);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            System.String strS
= ByteToHexStr(btS);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            BigInteger r
= new BigInteger(strR,16);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            BigInteger s
= new BigInteger(strS,16);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
// e_
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
            BigInteger e= new BigInteger(1, md);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
// t
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
            BigInteger t= r.Add(s).Mod(ecc_n);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
if (t.Equals(BigInteger.Zero))
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客               
return false;
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
// x1y1
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
            ECPoint x1y1= ecc_point_g.Multiply(s);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客            x1y1
= x1y1.Add(userKey.Multiply(t));
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
// R
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
            BigInteger R= e.Add(x1y1.X.ToBigInteger()).Mod(ecc_n);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客           
return r.Equals(R);
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客}

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

java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客SM2证书生成
java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客public static Org.BouncyCastle.X509.X509Certificate MakeRootCert(string filePath, IDictionary subjectNames)java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客{java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 AsymmetricCipherKeyPair keypair = SM2CryptoServiceProvider.SM2KeyPairGenerator.GenerateKeyPair();java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 ECPublicKeyParameters pubKey = (ECPublicKeyParameters)keypair.Public; //CA公钥 java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 ECPrivateKeyParameters priKey = (ECPrivateKeyParameters)keypair.Private; //CA私钥 java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 X509Name issuerDN = new X509Name(GetDictionaryKeys(subjectNames), subjectNames);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 X509Name subjectDN = issuerDN; //自签证书,两者一样java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 SM2X509V3CertificateGenerator sm2CertGen = new SM2X509V3CertificateGenerator();java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 //X509V3CertificateGenerator sm2CertGen = new X509V3CertificateGenerator();java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.SetSerialNumber(new BigInteger(128, new Random())); //128位 java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.SetIssuerDN(issuerDN);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.SetNotBefore(DateTime.UtcNow.AddDays(-1));java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.SetNotAfter(DateTime.UtcNow.AddDays(365 * 10));java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.SetSubjectDN(subjectDN);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.SetPublicKey(pubKey); //公钥java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.SetSignatureAlgorithm("SM3WITHSM2");java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true));java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(pubKey));java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pubKey));java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2CertGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(6));java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 Org.BouncyCastle.X509.X509Certificate sm2Cert = sm2CertGen.Generate(keypair);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2Cert.CheckValidity();java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 sm2Cert.Verify(pubKey);java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客 return sm2Cert;java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客}

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

java实现sm2证书基于BouncyCastle - 崔江威 - 崔江威的博客SM2证书公钥标识

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
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 sim卡显示无服务怎么办 华为麦芒进水无限开关机怎么办 华为麦芒5进水黑屏怎么办 华为麦芒6进水了怎么办 4g手机开不开机怎么办 全屏钢化膜总是翘边怎么办 华为麦芒屏幕触屏失灵怎么办 华为麦芒5运行慢怎么办 手机屏保密码忘记了怎么办 麦芒5密码锁忘了怎么办 超薄手机壳松了怎么办 华为麦芒5声音小怎么办 笔记本外壳a面裂了怎么办 苹果手机外壳摔坏了怎么办 挂衣服肩膀出包怎么办 摩拜单车手机号注销了怎么办 摩拜单车手机号码换了怎么办 摩拜单车换手机号码打不开怎么办 摩拜单车丢了怎么办 摩拜单车忘锁了怎么办 透明手机壳粘指纹怎么办 tpu手机壳变黄了怎么办 0pp0手机声音小怎么办 橡胶皮套晒坏了怎么办 宝宝晚上吹空调发烧怎么办 玩手机手指尖疼怎么办 手机型号不支持微信运动怎么办 手腕向下压会疼怎么办 手腕韧带拉伤怎么办恢复快 华为手机用车载充电慢怎么办 华为麦芒6充电慢怎么办 oppo手机压弯了怎么办 麦芒5电池不耐用怎么办 华为7x照相模糊怎么办 华为麦芒6照相虚怎么办 荣耀8gps信号弱怎么办 华为麦芒4手机卡顿怎么办 华为麦芒4玩游戏卡怎么办 sim卡换卡通讯录丢了怎么办 换sim卡通讯录怎么办 麦芒4开不了机怎么办