【SM2证书】签发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. 效果:

 

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android SM2、SM3、SM4 算法支持 Service Provider 及证书制作软件包 国密算法 JCAJCE Service Provider,适应版本 Android 4.2.2~7.0 支持 SM2 的 KeyFactory、KeyPairGenerator、Cipher、Signature、X.509 CertificateFactory 接口 支持 SM3 的 MessageDigest 接口、SM3withSM2 混合算法 支持 SM4 的 Cipher、KeyFactory、KeyGenerator、SecretKey 接口、相关算法 CMAC-SM4、Poly1305-SM4 增加 java.security.PublicKey 的子类 SM2PublicKey 增加 java.security.PrivateKey 的子类 SM2PrivateKey 全功能支持 SM3withSM2 算法的 X.509 证书结构体解释与密码运算 支持 BKS、PKCS#12 KeyStore 生成、解释、验算 X.509v1/v3 证书,签名算法支持 SM3withSM2、主流 RSA、DSA、ECDSA.... 生成、解释、验算 PKCS#10 证书申请,签名算法支持 SM3withSM2、主流 RSA、DSA、ECDSA.... *** 无须打包 BouncyCastle 支持库,体积小、节约内存 *** 请参阅 testSM.java、testCERT.java 文件列表: 1、AndroidSM.jar -- SM2、SM3、SM4 算法/证书支持的 JCA/JCE Service Provider 类库 2、AndroidCRT.jar -- X.509 数字证书/PKCS#10 证书申请相关类库 3、bc422.jar -- BouncyCastle 加密库,Android 4.2.2 内置版本(由真机导出dex文件转换而得,仅用于编译时选用,勿打包到apk文件中) 4、testSM.java -- SM2、SM3、SM4 算法相关类引用范例 5、testCERT.java -- X.509 数字证书/PKCS#10 证书申请相关类引用范例 6、readme.txt -- 本文 因条件及精力限制,各类、方法的实现未经严格彻底的测试,不宜用于商业用途软件的开发。 如欲将本开发包发布、上传、拷贝、共享等,务必保持其内容完整性(包括本文) 如有需要帮助或者索取源码,请联系 suntongo@qq.com, suntongo@hotmail.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值