【PKI】5.自签SM2根证书

【PKI】5.自签SM2根证书

0.程序员专用开头:

1.项目结构:

2. 源码:

AlgSm2Demo.java  (签名验签)

package alg.sm2demo;
 
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
 
/**
 * SM2 算法 Demo
 *
 * @author Cliven
 * @date 2018-12-20 10:42:22
 */
public class AlgSm2Demo {
    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, SignatureException {
        // 获取SM2椭圆曲线的参数
        final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
        // 获取一个椭圆曲线类型的密钥对生成器
        final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
        // 使用SM2参数初始化生成器
        kpg.initialize(sm2Spec);
 
        // 获取密钥对
        KeyPair keyPair = kpg.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
 
        // ------------------------ SM2未压缩公钥 ----------------------------
        // 椭圆曲线公钥的点坐标
        ECPoint pubKeyPointQ = ((BCECPublicKey) publicKey).getQ();
        System.out.println("X: \n" + pubKeyPointQ.getXCoord());
        System.out.println("Y: \n" + pubKeyPointQ.getYCoord());
        // 将其表示为SM2未压缩的公钥为
        System.out.println("SM2 public key: \n"
                + "04"
                + pubKeyPointQ.getXCoord().toString()
                + pubKeyPointQ.getYCoord().toString()
        );
        // ------------------------ SM2未压缩公钥 -------------------------------
 
        System.out.println("Public key: \n" + Hex.toHexString(publicKey.getEncoded()));
        System.out.println("Private key: \n" + Hex.toHexString(privateKey.getEncoded()));
 
        // 生成SM2sign with sm3 签名验签算法实例
        Signature signature = Signature.getInstance("SM3withSm2", new BouncyCastleProvider());
 
        /*
         * 签名
         */
        // 签名需要使用私钥,使用私钥 初始化签名实例
        signature.initSign(privateKey);
        // 签名原文
        byte[] plainText = "你好".getBytes(StandardCharsets.UTF_8);
        // 写入签名原文到算法中
        signature.update(plainText);
        // 计算签名值
        byte[] signatureValue = signature.sign();
        System.out.println("signature: \n" + Hex.toHexString(signatureValue));
        /*
         * 验签
         */
        // 签名需要使用公钥,使用公钥 初始化签名实例
        signature.initVerify(publicKey);
        // 写入待验签的签名原文到算法中
        signature.update(plainText);
        // 验签
        System.out.println("Signature verify result: " + signature.verify(signatureValue));
    }
}

SM2CertDemo.java  (签发证书)

package alg.sm2demo;
 
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.PublicKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
 
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.misc.NetscapeCertType;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.X509KeyUsage;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.encoders.Base64;
 
/**
 * SM2 X.509签名制作Demo
 *
 * @author jy
 * @date 2018-12-21 14:04
 */
public class SM2CertDemo {
 
	/**
	 * BouncyCastle算法提供者
	 */
	private static final Provider BC = new BouncyCastleProvider();
 
	/**
	 * 获取扩展密钥用途
	 *
	 * @return 增强密钥用法ASN.1对象
	 * @author Cliven
	 * @date 2018-12-21 16:04:58
	 */
	public static DERSequence extendedKeyUsage() {
		// // 客户端身份认证
		// ASN1ObjectIdentifier clientAuth = new
		// ASN1ObjectIdentifier("1.3.6.1.5.5.7.3.2");
		// // 安全电子邮件
		// ASN1ObjectIdentifier emailProtection = new
		// ASN1ObjectIdentifier("1.3.6.1.5.5.7.3.4");
		// 构造容器对象
		ASN1EncodableVector vector = new ASN1EncodableVector();
		// 客户端身份认证
		vector.add(KeyPurposeId.id_kp_clientAuth);
		// 安全电子邮件
		vector.add(KeyPurposeId.id_kp_emailProtection);
		return new DERSequence(vector);
	}
 
	/**
	 * 生成证书文件
	 *
	 * @param x509Certificate
	 *            X.509格式证书
	 * @param savePath
	 *            证书保存路径
	 * @throws CertificateEncodingException
	 * @throws IOException
	 * @author Cliven
	 * @date 2018-12-21 17:21:50
	 */
	public static void makeCertFile(X509Certificate x509Certificate, Path savePath)
			throws CertificateEncodingException, IOException {
		if (Files.exists(savePath)) {
			// 删除已存在文件
			Files.deleteIfExists(savePath);
		}
		// 创建文件
		Files.createFile(savePath);
 
		// 获取ASN.1编码的证书字节码
		byte[] asn1BinCert = x509Certificate.getEncoded();
		// 编码为BASE64 便于传输
		byte[] base64EncodedCert = Base64.encode(asn1BinCert);
		// 写入文件
		Files.write(savePath, base64EncodedCert);
	}
 
	public static void main(String[] args) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException,
			OperatorCreationException, IOException, CertificateException {
		// 生成密钥生成器, 产生密钥对
		KeyPairGenerator keyPairGenerator = SM2KeyGenerateFactory.generator();
		KeyPair keyPair = keyPairGenerator.generateKeyPair();
 
		// 证书签名实现类 附加了 SM3WITHSM2 和 PrivateKey
		JcaContentSignerBuilder jcaContentSB = new JcaContentSignerBuilder("SM3withSM2");
		jcaContentSB.setProvider(new BouncyCastleProvider());
		ContentSigner sigGen = jcaContentSB.build(keyPair.getPrivate());
 
		// 准备证书信息
		BigInteger sn = BigInteger.valueOf(System.currentTimeMillis());
		X500Name issuer = createX500Name("yan");
		X500Name subject = createX500Name("yan");
		Date notBefore = new Date();
		Date notAfter = new Date(System.currentTimeMillis() + 50 * 1000);
		PublicKey publickey = keyPair.getPublic();
 
		// 构造证书信息
		JcaX509v3CertificateBuilder jcaX509v3Cert = new JcaX509v3CertificateBuilder(issuer, sn, notBefore, notAfter,
				subject, publickey);
		jcaX509v3Cert.addExtension(Extension.keyUsage, false,
				new X509KeyUsage(X509KeyUsage.digitalSignature | X509KeyUsage.nonRepudiation));
		jcaX509v3Cert.addExtension(Extension.extendedKeyUsage, false, extendedKeyUsage());
		jcaX509v3Cert.addExtension(MiscObjectIdentifiers.netscapeCertType, false,
				new NetscapeCertType(NetscapeCertType.sslClient));
 
		// 构造X.509 第3版的证书构建者
		X509v3CertificateBuilder x509v3Cert = jcaX509v3Cert;
 
		// 将证书构造参数装换为X.509证书对象
		X509Certificate certificate = new JcaX509CertificateConverter().setProvider(BC)
				.getCertificate(x509v3Cert.build(sigGen));
 
		// 保存为证书文件
		makeCertFile(certificate, Paths.get("sm2_jy.cer"));
		System.out.println("gen cert succ!");
	}
 
	// 构造 主题名称
	public static X500Name createX500Name(String cn) {
		X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
		// 国家代码
		builder.addRDN(BCStyle.C, "CN");
		// 组织
		builder.addRDN(BCStyle.O, "info");
		// 省份
		builder.addRDN(BCStyle.ST, "beijing");
		// 地区
		builder.addRDN(BCStyle.L, "beijing");
		// 身份
		builder.addRDN(BCStyle.CN, cn);
 
		X500Name subject = builder.build();
 
		return subject;
	}
 
}

SM2KeyGenerateFactory.java (产生SM2 密钥对)

package alg.sm2demo;
 
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.spec.ECGenParameterSpec;
 
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
/**
 * SM2密钥对生成器
 *
 * @author Cliven
 * @date 2018-12-21 14:05
 */
public class SM2KeyGenerateFactory {
    /**
     * 获取SM2密钥对生成器
     *
     * @return SM2密钥对生成器
     * @throws NoSuchAlgorithmException
     * @author Cliven
     * @date 2019-6-10 15:56:36
     */
    public static KeyPairGenerator generator() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
/*
        // 获取SM2 椭圆曲线推荐参数
        X9ECParameters ecParameters = GMNamedCurves.getByName("sm2p256v1");
       // 构造EC 算法参数
        ECNamedCurveParameterSpec sm2Spec = new ECNamedCurveParameterSpec(
                // 设置SM2 算法的 OID
                GMObjectIdentifiers.sm2p256v1.toString()
                // 设置曲线方程
                , ecParameters.getCurve()
                // 椭圆曲线G点
                , ecParameters.getG()
                // 大整数N
                , ecParameters.getN());
        // 创建 密钥对生成器
        final KeyPairGenerator gen = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
        // 使用SM2的算法区域初始化密钥生成器
        kpg.initialize(sm2Spec, new SecureRandom());
        return gen;
*/
        /*
         * 上面过程为原始构造过程参考,BC已经为我们封装好了
         * 只需要下面三行代码即可
         */
        // 获取SM2椭圆曲线的参数
        final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
        // 获取一个椭圆曲线类型的密钥对生成器
        final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
        // 使用SM2参数初始化生成器
        kpg.initialize(sm2Spec);
        return kpg;
    }
}

执行 SM2CertDemo 的 main 方法即可,产生 SM2 证书。

3. 效果:

over…

0 0 vote
Article Rating
Subscribe
提醒
guest
0 评论
Inline Feedbacks
View all comments