java利用bouncycastle生成国密x509证书并将证书以pem格式存入文件,附golang对生成证书的验证

小白一枚,搞这个弄得心力交瘁,希望对你们有用…
参考了大牛的实现,https://github.com/ZZMarquis/gmhelper
感谢大牛的贡献,不然我等小白真的…

pom.xml



    4.0.0
    com.jinhongjian.testBCgm
    testBCgm-test
    1.0-SNAPSHOT
    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    6
                    6
                
            
        
    
    
        
            org.bouncycastle
            bcprov-jdk15on
            1.60
        
        
            org.bouncycastle
            bcpkix-jdk15on
            1.60
        
    

java程序

程序里面包含的功能有:sm2 公私钥对的生成,x509证书的生成,私钥以及证书转成pem格式保存到文件中
这里面是生成的自签发的CA证书。我也是新手,代码不规范请见谅…

import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;

import org.bouncycastle.crypto.params.*;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;

import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import org.bouncycastle.util.io.pem.PemObject;

import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.*;


public class x509Cert {

    private static X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
    private static ECParameterSpec ecParameterSpec = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
    public static final String SIGN_ALGO_SM3WITHSM2 = "SM3withSM2";


    static {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        }
    }

    public static KeyPair generateKeyPair(){
        try {
            KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
            kpGen.initialize(ecParameterSpec, new SecureRandom());
            KeyPair kp = kpGen.generateKeyPair();
            return kp;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static PKCS10CertificationRequest createCSR(X500Name subject, SM2PublicKey pubKey, PrivateKey priKey,String signAlgo)
            throws OperatorCreationException {
        PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(subject, pubKey);
        ContentSigner signerBuilder = new JcaContentSignerBuilder(signAlgo)
                .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(priKey);
        return csrBuilder.build(signerBuilder);
    }

    private static JcaContentSignerBuilder makeContentSignerBuilder(PublicKey issPub) throws Exception {
        if (issPub.getAlgorithm().equals("EC")) {
            JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(SIGN_ALGO_SM3WITHSM2);
            contentSignerBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME);
            return contentSignerBuilder;
        }
        throw new Exception("Unsupported PublicKey Algorithm:" + issPub.getAlgorithm());
    }

    //生成自签发ca证书
    public static X509Certificate caCertGen(KeyPair keypair)throws Exception {
        X500Name issuerDN = new X500Name("CN=My Application,O=My Organisation,L=My City,C=DE");

        SM2PublicKey sm2SubPub = new SM2PublicKey(keypair.getPublic().getAlgorithm(),
                (BCECPublicKey) keypair.getPublic());
        byte[] csr = createCSR(issuerDN, sm2SubPub, keypair.getPrivate(), "SM3withSM2").getEncoded();

        PKCS10CertificationRequest request = new PKCS10CertificationRequest(csr);
        PublicKey subPub = BCECUtil.createPublicKeyFromSubjectPublicKeyInfo(request.getSubjectPublicKeyInfo());
        PrivateKey issPriv = keypair.getPrivate();
        PublicKey issPub = keypair.getPublic();

        Calendar c = Calendar.getInstance();
        c.add(Calendar.YEAR,1);//日期加1年
        Date startDate = new Date();
        Date endDate = c.getTime();

        JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
        X509v3CertificateBuilder v3CertGen = new JcaX509v3CertificateBuilder(issuerDN, BigInteger.valueOf(System.currentTimeMillis()),
                startDate, endDate, request.getSubject(), subPub);

        v3CertGen.addExtension(Extension.subjectKeyIdentifier, false,
                extUtils.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(subPub.getEncoded())));

        v3CertGen.addExtension(Extension.authorityKeyIdentifier, false,
                extUtils.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(issPub.getEncoded())));

        v3CertGen.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));
        v3CertGen.addExtension(Extension.keyUsage, false, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.dataEncipherment
                | KeyUsage.keyCertSign | KeyUsage.cRLSign));

        JcaContentSignerBuilder contentSignerBuilder = makeContentSignerBuilder(issPub);
        X509Certificate cert = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME)
                .getCertificate(v3CertGen.build(contentSignerBuilder.build(issPriv)));
        cert.checkValidity(new Date());
        cert.verify(issPub);
        return cert;
    }

    public static String saveX509ToPemFile(X509Certificate x509Cert, String path) throws Exception {
        PemObject pemCSR = new PemObject("CERTIFICATE REQUEST", x509Cert.getEncoded());
        StringWriter str = new StringWriter();
        JcaPEMWriter pemWriter = new JcaPEMWriter(str);
        pemWriter.writeObject(pemCSR);
        pemWriter.close();
        str.close();
        FileOutputStream certOut = new FileOutputStream(path);
        certOut.write(str.toString().getBytes());

        return str.toString();
    }
    public static void savePrivateKey(PrivateKey priv, String keyFileName) throws IOException {
        // 保存private key
        try {
            FileOutputStream keyOut = new FileOutputStream(keyFileName);
            StringBuilder sb = new StringBuilder(300);
            sb.append("-----BEGIN PRIVATE KEY-----\n");
            String priKey = DatatypeConverter.printBase64Binary(priv.getEncoded());
            // 每64个字符输出一个换行
            int LEN = priKey.length();
            for (int ix = 0; ix < LEN; ++ix) {
                sb.append(priKey.charAt(ix));

                if ((ix + 1) % 64 == 0) {
                    sb.append('\n');
                }
            }

            sb.append("\n-----END PRIVATE KEY-----\n");
            keyOut.write(sb.toString().getBytes());

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) throws Exception {
        // 生成公私钥对 ---------------------
        KeyPair kp = generateKeyPair();
        X509Certificate cert  = caCertGen(kp);
        System.out.println(cert);
        savePrivateKey(kp.getPrivate(),"cert/privSm2.pri");
        String pemCertString = saveX509ToPemFile(cert,"cert/certSm2.crt");
        System.out.println(pemCertString);
    }
}

生成的证书在Windows下查看是这样的:
java利用bouncycastle生成国密x509证书并将证书以pem格式存入文件,附golang对生成证书的验证_第1张图片java利用bouncycastle生成国密x509证书并将证书以pem格式存入文件,附golang对生成证书的验证_第2张图片

使用golang的 tjfoc 国密实现对证书及密钥进行验证

package main

import (
	"github.com/tjfoc/gmsm/sm2"
	"fmt"
	"log"
	"reflect"
	"encoding/asn1"
	"math/big"
	"crypto/ecdsa"
)

type dsaSignature struct {
	R, S *big.Int
}

type ecdsaSignature dsaSignature

func main(){
	privKey, err := sm2.ReadPrivateKeyFromPem("cert/privSm2.pri", nil) // 读取密钥
	if err != nil {
		log.Fatal(err)
	}
	pubkey1 := privKey.Public()
	fmt.Println(reflect.TypeOf(pubkey1))

	r,s,err :=	sm2.Sm2Sign(privKey,[]byte("qwe"),nil)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(pubkey1)
	cert, err := sm2.ReadCertificateFromPem("cert/certSm2.crt")
	if err != nil {
		fmt.Printf("failed to read cert file")
	}
	pubkey2 := cert.PublicKey.(*ecdsa.PublicKey)

	fmt.Println(reflect.TypeOf(pubkey2))
	sm2pubkey := sm2.PublicKey{
		pubkey2.Curve,
		pubkey2.X,
		pubkey2.Y,
	}
	fmt.Println("###########################")
	fmt.Println(sm2.Sm2Verify(&sm2pubkey,[]byte("qwe"),nil,r,s))
	fmt.Println(pubkey2)

	ecdsaSig := new(ecdsaSignature)
	if _, err := asn1.Unmarshal(cert.Signature, ecdsaSig); err != nil {
		log.Fatal(err)
	}
	//直接验证证书里的签名
	fmt.Println(sm2.Sm2Verify(&sm2pubkey,cert.RawTBSCertificate,nil,ecdsaSig.R,ecdsaSig.S))
	err = cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature)
	if err != nil {
		log.Fatal(err)
	} else {
		fmt.Printf("CheckSignature ok\n")
	}
}

这一步的目的就是看看这证书到底生成的对不对了…目前验证的是私钥中提出的公钥可以验证证书里的签名成功,证书自己验证也可以成功

你可能感兴趣的:(java,java,x509,国密)