制作SM2证书
前段时间将系统的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签名实现如下:
- 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大数计算,验签代码如下:
- 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证书代码如下:

- 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椭圆曲线密码算法标识对象,这样在生成的证书中就可以看到公钥参数字段,如下所示:

- 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证书的更多相关文章
- 国密算法SM2证书制作
国密算法sm2非对称算法椭圆曲线 原文:http://www.jonllen.cn/jonllen/work/162.aspx 前段时间将系统的RSA算法全部升级为SM2国密算法,密码机和UKey硬件 ...
- highestAvailable比较灵活,毕竟大多数功能不需要系统最高权限(四种方法:屏蔽UAC,右键以管理员身份运行,增加manisfest,制作数字证书)
打开VS2005.VS2008.VS2010工程,查看工程文件夹中的Properties文件夹下是否有app.manifest这个文件:如没有,按如下方式创建:鼠标右击工程在菜单中选择“属性”,点击工 ...
- 制作SSL证书
上一节介绍了OpenSSL的目录结构,本节介绍一下SSL证书的制作. OpenSSL安装后建议把其中的bin目录添加到系统环境变量中,方便以后操作. 建立一个新的目录SSL专门用来制作证书. 建立证书 ...
- OPENSSL 制作 Ikev2证书
OPENSSL 制作 Ikev2证书 在一个 VPS 上配置 IKEV2 VPN 服务器时,用 OPENSSL 制作了所需的数字证书,奇怪的怎么弄都无法连接服务器,一直提示 "IKE_SA ...
- openssl 自己制作ssl证书:自己签发免费ssl证书,为nginx生成自签名ssl证书
server { listen 80; listen 443 ssl; server_name ~^((cloud)|(demo-cloud)|(demo2-cloud)|(approval1))(( ...
- PS批量制作获奖证书并导出PNG
其实方法和"使用PS批量制作视频字幕"的方法类似.区别在于制作视频字幕时导出成psd格式就可以直接导入Premiere中使用了,而获奖证书考虑到打印设备有无PS的不确定性,可能需要 ...
- makecert 制作数字证书 给DLL加一个数字签名
声明:文章整理自互联网 我仅需要给dll添加(替换)一个签名,所以我只看了第一步和第三步,其余的部分我没有测试,不能保证内容的是否正确. 看了很多关于DLL加签名的教程 大多是错误的 完全无法正常走下 ...
- 在macOS平台下制作SSL证书,免费域名通配符证、单域名证书、多域名证书教程
1.安装 home-brew 2.安装 certbot 在终端执行下面命令 brew install certbot 3.制作SSL证书 第一步: 在终端执行下面命令 sudo certbot cer ...
- 简单的制作ssl证书,并在nginx和IIS中使用
2020年最后一篇博文收官,提前祝各位园友新年快乐 现在的后端开发,动不动就是需要https,或者说是需要ssl证书,既然没有正版的证书,那么我们只能自己制作ssl的证书了. 说明:证书的制作采用的是 ...
随机推荐
- Java 基础学习1 -- 基础语法
1.变量
- WinForm中Component Class、User Control及Custom Control的区别和使用-转
转http://www.cnblogs.com/jhtchina/archive/2010/11/28/1028591.html NET Framework 为您提供了开发和实现新控件的能力.除了常见 ...
- c++ memset 函数 及 坑
#include <string.h> #include <stdio.h> typedef struct ss{ int num; ][]; }tent; tent a; i ...
- python 函数默认值的小坑啊
import datetime import time def test(day=datetime.datetime.now()): print day while True: test() time ...
- Asp.Net修改上传文件大小限制(修改web.config)
i. Configuration节点下 <system.webServer> <security> <requestFiltering> <!--单位为字节 ...
- 【BestCoder】【Round#29】
T1 啊……a^b 与 c^d比较大小,我们可以两边取对数,转化成 log(a^b)=b*log(a) 和d*log(c) 这样就能直接算了……然后稍微搞一下精度什么的就A了=.= //BC #29 ...
- oracle——DDL
一.一些概念 定义: 主键--唯一标识一条记录,不能有重复的,不允许为空 外键--表的外键是另一表的主键, 外键可以有重复的, 可以是空值 索引--该字段没有重复值,但可以有一个空值 作用: 主键-- ...
- 【设计模式六大原则4】接口隔离原则(Interface Segregation Principle)
定义:客户端不应该依赖它不需要的接口:一个类对另一个类的依赖应该建立在最小的接口上. 问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类 ...
- 一个Java程序员应该掌握的10项技能
1.语法:必须比较熟悉,在写代码的时候IDE的编辑器对某一行报错应该能够根据报错信息知道是什么样的语法错误并且知道任何修正. 2.命令:必须熟悉JDK带的一些常用命令及其常用选项,命令至少需要熟悉:a ...
- POJ 2253 Frogger (求某两点之间所有路径中最大边的最小值)
题意:有两只青蛙,a在第一个石头,b在第二个石头,a要到b那里去,每种a到b的路径中都有最大边,求所有这些最大边的最小值.思路:将所有边长存起来,排好序后,二分枚举答案. 时间复杂度比较高,344ms ...