课设第三周

一、证书签名

1、SM2

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

2、ECDSA

ECDSA是ECC与DSA的结合,目前ECC签名就是ECDSA,没有单纯的只用ECC的签名。整个签名过程与DSA类似,所不一样的是签名中采取的算法为ECC,最后签名出来的值也是分为r,s。

  • 签名过程如下:
   1、选择一条椭圆曲线Ep(a,b),和基点G;

   2、选择私有密钥k(k<n,n为G的阶),利用基点G计算公开密钥K=kG;

   3、产生一个随机整数r(r<n),计算点R=rG;

   4、将原数据和点R的坐标值x,y作为参数,计算SHA1做为hash,即Hash=SHA1(原数据,x,y);

   5、计算s≡r - Hash * k (mod n)

   6、r和s做为签名值,如果r和s其中一个为0,重新从第3步开始执行
  • 签名代码如下:
public static byte[] ECDSASign(byte[] inData,PrivateKey privateKey) throws Exception{
        Signature signer = Signature.getInstance("SHA256WITHECDSA",BC);
        signer.initSign(privateKey);
        signer.update(inData);
        return signer.sign();
    }
  • 验证过程如下:
   1、接受方在收到消息(m)和签名值(r,s)后,进行以下运算

   2、计算:sG+H(m)P=(x1,y1), r1≡ x1 mod p。

   3、验证等式:r1 ≡ r mod p。

   4、如果等式成立,接受签名,否则签名无效。
  • 验签代码如下:
 public static boolean ECDSAVerifySign(byte[] inData, byte[] signature, PublicKey publicKey) throws Exception{
        Signature signer = Signature.getInstance("SHA256WITHECDSA",BC);
        signer.initVerify(publicKey);
        signer.update(inData);
        return signer.verify(signature);
    }

3、RSA

  • 私钥和公钥都可以加密和解密消息,且公钥加密的文本只有对应的私钥才能解密,私钥加密的文本也只有对应的公钥才能解密。
  • 基于RSA的消息传递机制(A向B发送消息MSG)
    • 发送方 A
1. 对MSG使用周知的Hash函数计算出数字签名得到SIG
2. 使用私钥对SIG进行加密得到CrypSIG
3. 由于RSA加密算法复杂,因此使用简单的加密算法(密码为PWD)对MSG+CrypSIG进行加密得到CrypMSG
4. 使用B的公钥对PWD加密得到CrypPWD
5. 将CrypPWD, CrypMSG发送给B
  • 接收方 B
1. 使用私钥解密CrypPWD,的搭配PWD1
2. 用PWD1解密CrypMSG得到MSG1+CrypSIG1
3. 计算MSG1的数字签名SIG1
4. 用私钥解密CrypSIG1得到SIG2,若SIG1==SIG2则接受消息,否者丢弃消息
  • 签名代码
  public static byte[] RSASign(byte[] inData,PrivateKey privateKey) throws Exception{
        Signature signer = Signature.getInstance("SHA256WITHRSA",BC);
        signer.initSign(privateKey);
        signer.update(inData);
        return signer.sign();
    }
  • 验签代码
public static boolean RSAVerifySign(byte[] inData, byte[] signature, PublicKey publicKey) throws Exception{
        Signature signer = Signature.getInstance("SHA256WITHRSA",BC);
        signer.initVerify(publicKey);
        signer.update(inData);
        return signer.verify(signature);
    }

二、生成证书

基于BouncyCastle开源库,可以轻松制作X509证书、CRL、pkcs10、pkcs12,支持国际通用的RSA、ECC算法。

分为自签名根证书和根证书签发生成实体证书

1、SM2

  • X509证书由证书主体、证书签名算法标识、签名组成,和RSA证书主要不同的是SM2证书的签名算法标识和签名,及证书公钥使用ECKeyParameters。
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;
        }

          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短,在使用智能卡有限空间存储时非常可贵

2、RSA

  • 调用CertUils,Certificate rsaEntityCert = CertUtils.certGen(rsaCsr,rsarootcakey.getPrivate(),rsaCaCert.getEncoded(),notBefore,notAfter);

3、ECC

  • ECC作为证书加密算法的优势
    • 密钥更短,意味着ECC将占用更少的资源却有更高的性能
    • 更易扩展,随着RSA密钥更长只会让SSL/TLS面临更多麻烦
    • ECC不太容易收到量子计算机的安全威胁
  • 代码
        Certificate eccEntityCert = CertUtils.certGen(eccCsr,eccrootcakey.getPrivate(),eccCaCert.getEncoded(),notBefore,notAfter);

三、证书申请

传入使用者身份信息(Subject),使用者公钥,组装证书请求信息对象(CertificateRequestInfo),并使用传入的使用者私钥进行签名,最终生成P10格式的证书请求。

1、SM2

  • 证书申请
        PKCS10CertificationRequest sm2Csr = CertUtils.generateCSR(new X500Name("C=CN,CN=SM2request,ST=Beijing,L=Beijing,O=DKY,OU=IS,T=sm2"),sm2key.getPublic(),sm2key.getPrivate());

2、RSA

  • 证书申请
        PKCS10CertificationRequest rsaCsr = CertUtils.generateCSR(new X500Name("C=CN,CN=RSArequest,ST=Beijing,L=Beijing,O=DKY,OU=IS,T=rsa"),rsakey.getPublic(),rsakey.getPrivate());

3、ECC

  • 证书申请
        PKCS10CertificationRequest eccCsr = CertUtils.generateCSR(new X500Name("C=CN,CN=ECCrequest,ST=Beijing,L=Beijing,O=DKY,OU=IS,T=ecc"),ecckey.getPublic(),ecckey.getPrivate());
posted on 2019-05-26 17:08  musea  阅读(415)  评论(0)    收藏  举报