国密算法SM2证书制作

国密算法sm2非对称算法椭圆曲线

原文:http://www.jonllen.cn/jonllen/work/162.aspx

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

[java] view plaincopy

  1. public static BigInteger[] Sm2Sign(byte[] md, AsymmetricCipherKeyPair keypair)
  2. {
  3. SM3Digest sm3 = new SM3Digest();
  4. ECPublicKeyParameters ecpub = (ECPublicKeyParameters)keypair.Public;
  5. byte[] z = SM2CryptoServiceProvider.Sm2GetZ(Encoding.Default.GetBytes(SM2CryptoServiceProvider.userId), ecpub.Q);
  6. sm3.BlockUpdate(z, 0, z.Length);
  7. byte[] p = md;
  8. sm3.BlockUpdate(p, 0, p.Length);
  9. byte[] hashData = new byte[32];
  10. sm3.DoFinal(hashData, 0);
  11. // e
  12. BigInteger e = new BigInteger(1, hashData);
  13. // k
  14. BigInteger k = null;
  15. ECPoint kp = null;
  16. BigInteger r = null;
  17. BigInteger s = null;
  18. BigInteger userD = null;
  19. do
  20. {
  21. do
  22. {
  23. ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)keypair.Private;
  24. k = ecpriv.D;
  25. kp = ecpub.Q;
  26. userD = ecpriv.D;
  27. // r
  28. r = e.Add(kp.X.ToBigInteger());
  29. r = r.Mod(ecc_n);
  30. }
  31. while (r.Equals(BigInteger.Zero) || r.Add(k).Equals(ecc_n));
  32. // (1 + dA)~-1
  33. BigInteger da_1 = userD.Add(BigInteger.One);
  34. da_1 = da_1.ModInverse(ecc_n);
  35. // s
  36. s = r.Multiply(userD);
  37. s = k.Subtract(s).Mod(ecc_n);
  38. s = da_1.Multiply(s).Mod(ecc_n);
  39. }
  40. while (s.Equals(BigInteger.Zero));
  41. byte[] btRS = new byte[64];
  42. byte[] btR = r.ToByteArray();
  43. byte[] btS = s.ToByteArray();
  44. Array.Copy(btR, btR.Length - 32, btRS, 0, 32);
  45. Array.Copy(btS, btS.Length - 32, btRS, 32, 32);
  46. return new BigInteger[] { r, s };
  47. }

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

[java] view plaincopy

  1. public static bool Verify(byte[] msg, byte[] signData, byte[] certData)
  2. {
  3. X509Certificate2 x5092 = new X509Certificate2(certData);
  4. byte[] certPK = x5092.GetPublicKey();
  5. certPK = SubByte(certPK, 1, 64);
  6. byte[] certPKX = SubByte(certPK, certPK.Length - 32 - 32, 32);
  7. byte[] certPKY = SubByte(certPK, certPK.Length - 32, 32);
  8. System.String strcertPKX = ByteToHexStr(certPKX);
  9. System.String strcertPKY = ByteToHexStr(certPKY);
  10. BigInteger biX = new BigInteger(strcertPKX, 16);
  11. BigInteger biY = new BigInteger(strcertPKY, 16);
  12. ECFieldElement x = new FpFieldElement(ecc_p, biX);
  13. ECFieldElement y = new FpFieldElement(ecc_p, biY);
  14. ECPoint userKey = new FpPoint(ecc_curve, x, y);
  15. SM3Digest sm3 = new SM3Digest();
  16. byte[] z = Sm2GetZ(Encoding.Default.GetBytes(userId), userKey);
  17. sm3.BlockUpdate(z, 0, z.Length);
  18. byte[] p = msg;
  19. sm3.BlockUpdate(p, 0, p.Length);
  20. byte[] md = new byte[32];
  21. sm3.DoFinal(md, 0);
  22. byte[] btR = SubByte(signData, 0, 32);
  23. byte[] btS = SubByte(signData, 32, 32);
  24. System.String strR = ByteToHexStr(btR);
  25. System.String strS = ByteToHexStr(btS);
  26. BigInteger r = new BigInteger(strR, 16);
  27. BigInteger s = new BigInteger(strS, 16);
  28. // e_
  29. BigInteger e = new BigInteger(1, md);
  30. // t
  31. BigInteger t = r.Add(s).Mod(ecc_n);
  32. if (t.Equals(BigInteger.Zero))
  33. return false;
  34. // x1y1
  35. ECPoint x1y1 = ecc_point_g.Multiply(s);
  36. x1y1 = x1y1.Add(userKey.Multiply(t));
  37. // R
  38. BigInteger R = e.Add(x1y1.X.ToBigInteger()).Mod(ecc_n);
  39. return r.Equals(R);
  40. }

制作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证书生成

[java] view plaincopy

  1. public static Org.BouncyCastle.X509.X509Certificate MakeRootCert(string filePath, IDictionary subjectNames)
  2. {
  3. AsymmetricCipherKeyPair keypair = SM2CryptoServiceProvider.SM2KeyPairGenerator.GenerateKeyPair();
  4. ECPublicKeyParameters pubKey = (ECPublicKeyParameters)keypair.Public; //CA公钥
  5. ECPrivateKeyParameters priKey = (ECPrivateKeyParameters)keypair.Private;    //CA私钥
  6. X509Name issuerDN = new X509Name(GetDictionaryKeys(subjectNames), subjectNames);
  7. X509Name subjectDN = issuerDN;  //自签证书,两者一样
  8. SM2X509V3CertificateGenerator sm2CertGen = new SM2X509V3CertificateGenerator();
  9. //X509V3CertificateGenerator sm2CertGen = new X509V3CertificateGenerator();
  10. sm2CertGen.SetSerialNumber(new BigInteger(128, new Random()));   //128位
  11. sm2CertGen.SetIssuerDN(issuerDN);
  12. sm2CertGen.SetNotBefore(DateTime.UtcNow.AddDays(-1));
  13. sm2CertGen.SetNotAfter(DateTime.UtcNow.AddDays(365 * 10));
  14. sm2CertGen.SetSubjectDN(subjectDN);
  15. sm2CertGen.SetPublicKey(pubKey); //公钥
  16. sm2CertGen.SetSignatureAlgorithm("SM3WITHSM2");
  17. sm2CertGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true));
  18. sm2CertGen.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(pubKey));
  19. sm2CertGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pubKey));
  20. sm2CertGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(6));
  21. Org.BouncyCastle.X509.X509Certificate sm2Cert = sm2CertGen.Generate(keypair);
  22. sm2Cert.CheckValidity();
  23. sm2Cert.Verify(pubKey);
  24. return sm2Cert;
  25. }

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

SM2证书公钥标识

[java] view plaincopy

  1. using System;
  2. using Org.BouncyCastle.Asn1.X509;
  3. using Org.BouncyCastle.Asn1;
  4. namespace Common.Security
  5. {
  6. public class SM2AlgorithmIdentifier
  7. : AlgorithmIdentifier
  8. {
  9. private readonly bool parametersDefined;
  10. public SM2AlgorithmIdentifier(
  11. DerObjectIdentifier objectID):base(objectID)
  12. {
  13. }
  14. public SM2AlgorithmIdentifier(
  15. DerObjectIdentifier    objectID,
  16. Asn1Encodable parameters)
  17. : base(objectID, parameters)
  18. {
  19. this.parametersDefined = true;
  20. }
  21. /**
  22. * Produce an object suitable for an Asn1OutputStream.
  23. *          *      AlgorithmIdentifier ::= Sequence {
  24. *                            algorithm OBJECT IDENTIFIER,
  25. *                            parameters ANY DEFINED BY algorithm OPTIONAL }
  26. *
  27. */
  28. public override Asn1Object ToAsn1Object()
  29. {
  30. DerObjectIdentifier sm2Identifier = new DerObjectIdentifier("1.2.156.10197.1.301");
  31. Asn1EncodableVector v = new Asn1EncodableVector(base.ObjectID, sm2Identifier);
  32. return new DerSequence(v);
  33. }
  34. }
  35. }

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
时间: 2024-11-05 11:27:37

国密算法SM2证书制作的相关文章

嵌入式设备中支持国密算法的方法

如今国密系列算法的应用已不仅仅局限于金融和电信等领域,诸如车载设备,消费类电子设备等越来越多的产品开始要求有国密算法的支持.但是国密算法的开源资料和应用案例少之又少,如何快速高效的在自己的设备中加入国密算法已经成为众多开发者必须要面对的难题.现在为大家准备了一个系列文章,介绍嵌入式设备中移植国密算法的方法.简单来说,分为三种方法:1.移植Miracl库2.移植Openssl库3.使用加密芯片下面进行简介:1.移植Miracl库MIRACL(Multiprecision Integer and R

国密算法的ekey的使用--简述

一.龙脉GMTools的使用 1.产品介绍 mToken GM3000 国密身份认证锁是龙脉科技自主研发设计支持国密算法.完全遵照国家密码管理局颁布的<智能IC卡及智能密码钥匙密码应用接口规范>要求设计的USB Key,采用国产高性能智能卡芯片,内置SSF33.SM1.SM2.SM3.SM4等国产算法,支持高速数据国密算法加解密,提供CSP以及PKCS11和国密接口,完全符合国家密码管理局关于"密钥不落地"的技术规范要求,是电子政务.电子军务.CA厂商首选的USB Key产

国密算法的ekey基本使用的说明

概述 本次需要进行的实验研究是国密算法的ekey的使用.对于一个或者多个应用来说,每个应用可以包含一个或多个容器(Container),每个容器中可以存放两对分别用于加密和签名的密钥对,以及两个相应的证书或证书链.每一个容器只能为ECC或RSA一种类型,一个容器中不能混用ECC密钥和RSA密钥.根据个人的理解,ekey的作用就是生成容器,将需要加密的消息或文件利用相应的加密算法加密后,生成证书,将证书导入ekey的容器中.这样以便于在其他终端上用到该文件时,使用ekey,其容器中的对应的证书可以

嵌入式设备中支持国密算法的方法(二)

上一篇文章中我们为大家介绍了嵌入式设备中支持国密算法的几种方法.本篇我们详细的介绍一下第一种方法:移植Miracl库的具体操作步骤.第一步 获取源码MIRACL密码库是开源软件,可以直接到官网下载,也可在csdn等论坛中获取.第二步 利用MIRACL库函数实现SM2算法实现sm2的功能需要用到MIRACL库中的36个源文件,例如mraes.c.mrec2.c.mrarth0.c.mrcore.c.mrshs.c.mezzn2.c.mrxgcd.c.mrgcm.c.mrio1.c等.然后需要新建一

嵌入式设备中支持国密算法的方法(三)

本篇文章是介绍国密算法在嵌入式设备中应用方法系列文章的第三篇,介绍移植openssl库到嵌入式设备中的具体方法,当然最终的目的还是使我们的设备能支持国密算法.同上一篇文章中介绍的miracl密码库相比,openssl库的应用更加广泛,资料支持度更好,但是代码体量要大于miracl库.需要再次说明的是,同miracl库一样,openssl的库也并不能直接提供国密算法的接口,我们是利用库中相应的API接口(如椭圆曲线等)来构建自己的国密算法,下面我们具体介绍移植的步骤.第一步 获取库作为应用广泛的开

SM2证书的鉴定方法——续上文国密算法

上问说到了国家有自己的加密算法,那么本文就描述了如何鉴别SM2的证书算法是什么样的.. 国密局规定,SM2证书中签名算法OID为1.2.156.10197.1.501,公钥算法的OID为1.2.840.10045. 2.1.目前大部分的厂商都还不识别这两个算法,能识别的系统直接显示的是SM2算法. Windows鉴定 SM2证书在Windows系统上,可以通过查看证书属性中的签名算法和公钥算法来判断是否为SM2的证书.直接双击证书,安装到IE中,查看证书信息,XP系统2003 server以下的

2017-2018-2 20179204《网络攻防实践》第十三周学习总结 python实现国密算法

国密商用算法是指国密SM系列算法,包括基于椭圆曲线的非对称公钥密码SM2算法.密码杂凑SM3算法.分组密码SM4算法,还有只以IP核形式提供的非公开算法流程的对称密码SM1算法等. 第1节 SM2非对称密码算法原理 国密SM2算法是商用的ECC椭圆曲线公钥密码算法,其具有公钥加密.密钥交换以及数字签名的功能.椭圆曲线参数并没有给出推荐的曲线,曲线参数的产生需要利用一定的算法产生.但在实际使用中,国密局推荐使用素数域256 位椭圆曲线,其曲线方程为y^2= x^3+ax+b.参数如下: 其中p是大

国密算法

算法分类 国密即国家密码局认定的国产密码算法.主要有SM1,SM2,SM3,SM4.密钥长度和分组长度均为128位. SM1 为对称加密.其加密强度与AES相当.该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用. SM2为非对称加密,基于ECC.该算法已公开.由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA.ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA. SM3 消息摘要.可以用MD5作为对比理解.该算法已公

自己封装的openssl+国密算法的C++接口

Digest #ifndef _DIGESTCALC_H #define _DIGESTCALC_H /********************************** /* 使用示例:(sm3算法) /* DigestCalc hashcl; /* hashcl.Init(DigestCalc::alg_id::sm3); /* hashcl.Update(in,inl); /* vector<unsigned int> out(hashcl.GetHashLength()); /* h