课设第三周
一、证书签名
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());
浙公网安备 33010602011771号