栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java OpenSsl 证书相关

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java OpenSsl 证书相关

学习整理了一个Java OpenSsl X509证书相关的工具类

环境:

JDK:11

加密解密算法:SM2

package com.lighting.iap.cert;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.openssl.PEMParser;
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.jcajce.JcaPKCS10CertificationRequestBuilder;
import org.bouncycastle.util.encoders.Hex;
import java.io.*;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.security.spec.*;
import java.util.*;


public class X509CertUtil {

    //定义使用的常量信息
    //要生成的EC的标准名称
    private static final String PRIME256V1 = "prime256v1";
    //密钥算法的名称 密钥基于椭圆曲线
    private static final String KEY_PAIR_ALGORITHM = "EC";

    //签名算法是带有 ECDSA 的 SHA256 
    private static final String SIG_ALG = "SHA256withECDSA";
    //证书类型
    public static final String X509 = "X.509";
    //密钥存储库的类型
    public static final String KEY_STORE_TYPE = "PKCS12";

    
    static {
        //系统统添加BC加密算法 以后系统中调用的算法都是BC的算法,其实不注册也行
        Security.addProvider(new BouncyCastleProvider());
    }

    
    public static KeyPair getKeyPair() throws Exception {
        //指定用于的参数集生成椭圆曲线(EC)域参数。入参为:要生成的EC的标准名称
        //prime256v1 带有NISTP-256算法的椭圆曲线
        ECGenParameterSpec ecSpec = new ECGenParameterSpec(PRIME256V1);
        //返回一个生成public/private的KeyPairGenerator对象。入参为算法的标准字符串名称。
        KeyPairGenerator kf = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
        //初始化密钥对生成器随机性的设置和来源。
        kf.initialize(ecSpec, new SecureRandom());
        //kf.initialize(ecSpec); 也可使用系统的随机数来源
        //生成密钥对
        KeyPair keyPair = kf.generateKeyPair();

        return keyPair;
    }

    
    public static PrivateKey toPrivateKey(String privateKey) throws Exception {
        //将Base64编码的String解码为新分配的字节数组
        byte[] keyBytes =Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(keyBytes);
        //键工厂用于转换键。入参:请求的密钥算法的名称。 提供程序的名称。
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR_ALGORITHM);
        //根据提供的密钥规范生成一个私钥对象
        return keyFactory.generatePrivate(pkcs8);
    }

    
    public static PublicKey toPublicKey(String publicKey) throws Exception {
        //将Base64编码的String解码为新分配的字节数组
        byte[] bytes = Base64.getDecoder().decode(publicKey);
        return getPublicKey(bytes);
    }

    
    public static PublicKey getPublicKey(byte[] bytes) throws Exception {
        //这个类表示公钥的ASN.1编码
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
        //键工厂用于转换键。入参:请求的密钥算法的名称。 提供程序的名称。
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR_ALGORITHM);
        //根据提供的密钥规范生成一个公钥对象
        return keyFactory.generatePublic(keySpec);
    }

    
    public static String encrypt(PublicKey publicKey, String data) {
        //加密模式
        SM2Engine.Mode mode = SM2Engine.Mode.C1C3C2;

        //通过公钥对象获取公钥的基本域参数。
        //椭圆曲线(EC)公钥的接口
        BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey;
        //椭圆曲线加密(ECC)一起使用的域参数集
        ECParameterSpec spec = bcecPublicKey.getParameters();
        ECDomainParameters ecDomainParameters = new ECDomainParameters(spec.getCurve(),spec.getG(), spec.getN());
        //通过公钥值和公钥基本参数创建公钥参数对象
        ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(), ecDomainParameters);

        //根据加密模式实例化SM2公钥加密引擎
        SM2Engine sm2Engine = new SM2Engine(mode);
        //初始化加密引擎
        sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
        byte[] arrayOfBytes = null;
        try {
            //将明文字符串转换为指定编码的字节串
            byte[] in = data.getBytes("utf-8");
            //通过加密引擎对字节数串行加密
            arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
        } catch (Exception e) {
            System.out.println("SM2加密时出现异常:" + e.getMessage());
            e.printStackTrace();
        }
        //将加密后的字节串转换为十六进制字符串
        return Hex.toHexString(arrayOfBytes);
    }

    
    public static String decrypt(PrivateKey privateKey, String data) {
        //解密模式
        SM2Engine.Mode mode = SM2Engine.Mode.C1C3C2;
        BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey;

        //通过私钥对象获取私钥的基本域参数。
        ECParameterSpec spec = bcecPrivateKey.getParameters();
        ECDomainParameters ecDomainParameters = new ECDomainParameters(spec.getCurve(),spec.getG(), spec.getN());
        //通过私钥值和私钥钥基本参数创建私钥参数对象
        ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(),ecDomainParameters);

        //通过解密模式创建解密引擎并初始化
        SM2Engine sm2Engine = new SM2Engine(mode);
        sm2Engine.init(false, ecPrivateKeyParameters);
        String result = null;
        try {
            //将十六进制字符串密文转换为字节数组(需要与加密一致,加密是:加密后的字节数组转换为了十六进制字符串)
            byte[] cipherDataByte = Hex.decode(data);
            //通过解密引擎对密文字节串进行解密
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
            //将解密后的字节串转换为utf8字符编码的字符串(需要与明文加密时字符串转换成字节串所指定的字符编码保持一致)
            result = new String(arrayOfBytes, "utf-8");
        } catch (Exception e) {
            System.out.println("SM2解密时出现异常" + e.getMessage());
        }
        return result;
    }

    
    public static String signECDSA(PrivateKey privateKey, String data) {
        String resultSign = "";
        try {
            //Signature类用于为应用程序提供该功能的数字签名算法。入参:算法
            Signature signal = Signature.getInstance(SIG_ALG);
            //初始化此对象以进行签名
            signal.initSign(privateKey);
            //更新要签名或验证的数据
            signal.update(data.getBytes(StandardCharsets.UTF_8));
            //返回所有已更新数据的签名字节。
            byte[] sign = signal.sign();
            return Base64.getEncoder().encodeToString(sign);
        }catch (NoSuchAlgorithmException ne){
            System.out.println("算法异常:");
            ne.printStackTrace();
        }catch (InvalidKeyException ke){
            System.out.println("秘钥:");
            ke.printStackTrace();
        }catch (SignatureException se){
            System.out.println("签名异常:");
            se.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }
        return resultSign;
    }

    
    public static boolean verifyECDSA(PublicKey publicKey, String signedData, String data) {
        try {
            //Signature类用于为应用程序提供该功能的数字签名算法。入参:算法
            Signature signature = Signature.getInstance(SIG_ALG);
            //初始化该对象以供验证。
            signature.initVerify(publicKey);
            //更新要签名或验证的数据
            signature.update(data.getBytes(StandardCharsets.UTF_8));
            //将Base64编码的String解码为新分配的字节数组
            byte[] signed = Base64.getDecoder().decode(signedData);
            //验证传入的签名。如果签名被验证,则为True,否则为false。
            boolean bool = signature.verify(signed);
            return bool;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    
    public static X509Certificate readX509CertificateByPath(String crtPath)throws CertificateException, IOException {
        //根据路径创建输入流
        InputStream inStream = new FileInputStream(crtPath);
        //定义证书工厂类。入参:请求的证书类型的名称。
        CertificateFactory cf = CertificateFactory.getInstance(X509);
        //生成一个证书对象,并从输入流读取的数据。入参:包含证书数据的输入流。
        X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
        inStream.close();
        return cert;
    }

    
    public static void showX509Certificate(X509Certificate x509) {
        // JAVA程序中显示证书指定信息
        System.out.println("输出证书信息:"+x509.toString());
        System.out.println("版本号:"+x509.getVersion());
        System.out.println("序列号:"+x509.getSerialNumber().toString(16));
        System.out.println("主体名:"+x509.getSubjectDN());
        System.out.println("签发者:"+x509.getIssuerDN());
        System.out.println("有效起始日期:"+x509.getNotBefore());
        System.out.println("有效终止日期:"+x509.getNotAfter());
        System.out.println("签名算法:"+x509.getSigAlgName());
        byte [] sig=x509.getSignature();//签名值
        PublicKey pk=x509.getPublicKey();

        byte [] pkenc=pk.getEncoded();
        System.out.println("公钥");
        for (int i = 0; i < pkenc.length; i++) {
            System.out.print(pkenc[i] + ",");
        }
    }

    
    private static byte[] readFile(String path) throws Exception {
        ByteArrayOutputStream baos;
        try (FileInputStream fis = new FileInputStream(path)) {
            baos = new ByteArrayOutputStream();
            int b = -1;
            while ((b = fis.read()) != -1) {
                baos.write(b);
            }
            fis.close();
        }
        byte[] contents = baos.toByteArray();
        baos.close();
        return contents;
    }

    
    private static String readFileToString(String filePath) throws IOException {
        String res ="";
        BufferedReader br = new BufferedReader(new FileReader(filePath));
        String line;
        while ((line = br.readLine()) != null) {
            res += line;
        }
        br.close();
        return res;
    }

    
    public static PrivateKey getPrivateKeyByPath(String path) throws Exception {
        String strKeyPEM = readFileToString(path);
        System.out.println(strKeyPEM);
        strKeyPEM = strKeyPEM.replace("-----BEGIN EC PRIVATE KEY-----","");
        strKeyPEM = strKeyPEM.replace("-----END EC PRIVATE KEY-----","");
        System.out.println(strKeyPEM);
        return toPrivateKey(strKeyPEM);
    }

    
    public static PublicKey getPublicKeyByPath(String path) throws Exception {
        byte[] b = readFile(path);
        String strKeyPEM =  new String(b);
        strKeyPEM = strKeyPEM.replace("-----BEGIN PUBLIC KEY-----","");
        strKeyPEM = strKeyPEM.replace("-----END PUBLIC KEY-----","");
        strKeyPEM = strKeyPEM.replaceAll("[tnr]", "");
        return toPublicKey(strKeyPEM);
    }

    
    public static PublicKey readX509CertificatePublicKey(String crtPath)throws Exception{
        X509Certificate x509Certificate = readX509CertificateByPath(crtPath);
        PublicKey publicKey = x509Certificate.getPublicKey();
        return publicKey;
    }

    
    private static void writeFile(String path, byte[] content) throws Exception {
        //如果存在则删除逻辑不考虑了,自行扩展
        FileOutputStream fos = new FileOutputStream(path);
        fos.write(content);
        fos.close();
    }

    
    private static void writeObject(String path, Object object) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
        oos.writeObject(object);
        oos.close();
    }

    
    public static boolean verifyCertificate(String certificatePath) {
        return verifyCertificate(new Date(), certificatePath);
    }

    
    public static boolean verifyCertificate(Date date, String certificatePath) {
        boolean status = true;
        try {
            // 取得证书
            X509Certificate x509Certificate = readX509CertificateByPath(certificatePath);
            // 验证证书是否过期或无效
            status = verifyCertificate(date, x509Certificate);
        } catch (Exception e) {
            status = false;
        }
        return status;
    }

    
    private static boolean verifyCertificate(Date date, X509Certificate x509Certificate) {
        boolean status = true;
        try {
            //检查给定的日期是否在证书的日期内有效期
            x509Certificate.checkValidity(date);
        } catch (Exception e) {
            status = false;
        }
        return status;
    }

    
    private static X500NameBuilder userCreateStdBuilder() {
        X500NameBuilder x500Nb = new X500NameBuilder(BCStyle.INSTANCE);
        x500Nb.addRDN(BCStyle.SERIALNUMBER, "证书序列号");
        x500Nb.addRDN(BCStyle.EmailAddress, "邮箱");
        x500Nb.addRDN(BCStyle.E, "电子邮箱");
        x500Nb.addRDN(BCStyle.UID, "UID");
        x500Nb.addRDN(BCStyle.CN, "名字");
        x500Nb.addRDN(BCStyle.T, "标题");
        x500Nb.addRDN(BCStyle.OU, "组织单位名称");
        x500Nb.addRDN(BCStyle.DC, "领域(机构)");
        x500Nb.addRDN(BCStyle.O, "组织名称");
        x500Nb.addRDN(BCStyle.STREET, "街道");
        x500Nb.addRDN(BCStyle.L, "地方名");
        x500Nb.addRDN(BCStyle.ST, "省份");
        x500Nb.addRDN(BCStyle.C, "国家");
        x500Nb.addRDN(BCStyle.UnstructuredName, "主机名称");
        x500Nb.addRDN(BCStyle.UnstructuredAddress, "IP");
        //BCStyle 详见
        return x500Nb;
    }

    
    private static X500NameBuilder rootCreateStdBuilder() {
        X500NameBuilder x500Nb = new X500NameBuilder(BCStyle.INSTANCE);
        x500Nb.addRDN(BCStyle.SERIALNUMBER, "证书序列号");
        x500Nb.addRDN(BCStyle.EmailAddress, "邮箱");
        x500Nb.addRDN(BCStyle.E, "电子邮箱");
        x500Nb.addRDN(BCStyle.UID, "UID");
        x500Nb.addRDN(BCStyle.CN, "名字");
        x500Nb.addRDN(BCStyle.T, "标题");
        x500Nb.addRDN(BCStyle.OU, "组织单位名称");
        x500Nb.addRDN(BCStyle.DC, "领域(机构)");
        x500Nb.addRDN(BCStyle.O, "组织名称");
        x500Nb.addRDN(BCStyle.STREET, "街道");
        x500Nb.addRDN(BCStyle.L, "地方名");
        x500Nb.addRDN(BCStyle.ST, "省份");
        x500Nb.addRDN(BCStyle.C, "国家");
        x500Nb.addRDN(BCStyle.UnstructuredName, "主机名称");
        x500Nb.addRDN(BCStyle.UnstructuredAddress, "IP");
        //BCStyle 详见
        return x500Nb;
    }

    
    public static PKCS10CertificationRequest createScr(PublicKey publicKeyA,PrivateKey privateKeyA) throws OperatorCreationException {
        //申请者DN信息构造
        // X500Name 通过传递通用名称,组织单位,组织,位置,州和国家/地区来创建X500Name对象
        //X500Name x500Name = userCreateStdBuilder().build();
        X500Name x500Name = new X500Name("CN=zhangsan,L=shanghai,ST=Shang Hai,O=个人,OU=个人专用,C=China,STREET=街道");
        //使用Dn和PublicKey初始化PKCS10。(组装信息)
        JcaPKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(x500Name, publicKeyA);

        //使用标准算法获取签名实例。(私钥加密)
        JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder(SIG_ALG);
        //使用私钥对CertificationRequestInfo进行数字签名得到签名值;
        ContentSigner signer = csBuilder.build(privateKeyA);

        //组合CertificationRequestInfo信息和签名得到最终的CSR文件
        PKCS10CertificationRequest csr = p10Builder.build(signer);// PKCS10的请求
        return csr;
    }

    
    public static byte[] createScrToByte(PublicKey publicKeyA,PrivateKey privateKeyA) throws OperatorCreationException, IOException {
        PKCS10CertificationRequest csr = createScr(publicKeyA, privateKeyA);
        String csrStr = "-----BEGIN CERTIFICATE REQUEST-----n" +
                org.apache.commons.codec.binary.Base64.encodeBase64String(csr.getEncoded())
                + "n-----END CERTIFICATE REQUEST-----n";
        return csrStr.getBytes();
    }

    
    public static PKCS10CertificationRequest readCsr(InputStream in) throws Exception {
        //readAllBytes 适合读取小文件,大文件可能会出现内存不足,导致堆溢出
        byte[] bytes = in.readAllBytes();
        in.close();
        String contents = new String(bytes, StandardCharsets.UTF_8);
        //一个内部缓冲区 流的来源或目的地并不一定是文件,也可以是内存中的一块空间,将字节数组当作流输入来源、输出目的地的类
        ByteArrayInputStream pemStream = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
        //转换字符串是为了防止乱码
        //ByteArrayInputStream pemStream2 = new ByteArrayInputStream(bytes);
        //用于读取字符流
        Reader pemReader = new BufferedReader(new InputStreamReader(pemStream));
        PEMParser pemParser = new PEMParser(pemReader);
        Object parsedObj = pemParser.readObject();
        pemStream.close();
        pemReader.close();
        pemParser.close();
        //使用PKCS10CertificationRequestBuilder来构造CSR
        if (parsedObj instanceof PKCS10CertificationRequest) {
            return (PKCS10CertificationRequest) parsedObj;
        }else{
            throw new Exception("无法读取csr");
        }
    }

    
    public static X509Certificate createRootCert(PublicKey publicKeyCA,PrivateKey privateKeyCA) throws IOException, OperatorCreationException, CertificateException {
        //定义颁布者DN(根证书是自己颁布给自己的)
        //X500Name issuerDn = rootCreateStdBuilder().build();
        X500Name issuerDn = new X500Name("CN=CA,L=shanghai,ST=Shang Hai,O=CA组织,OU=ca单位,C=China,STREET=街道");

        //serial 证书序列号
        BigInteger serial=BigInteger.valueOf(System.currentTimeMillis());

        //组装公钥信息
        SubjectPublicKeyInfo subjectPublicKeyInfo =
                SubjectPublicKeyInfo.getInstance(new ASN1InputStream(publicKeyCA.getEncoded()).readObject());

        //定义证书有效期
        long year = 360 * 24 * 60 * 60 * 1000;
        Date notBefore = new Date();
        Date notAfter = new Date(notBefore.getTime() + year);

        //构造X.509 第3版的证书构建者  设置证书的基本参数。X509V3是数字证书的一种通用规范标准
        X509v3CertificateBuilder builder = new X509v3CertificateBuilder(issuerDn, //颁发者信息
                serial, //证书序列号
                notBefore, //证书生效日期
                notAfter, //证书失效日期
                issuerDn, //使用者信息(PS:由于是自签证书,所以颁发者和使用者DN都相同)
                subjectPublicKeyInfo);//公钥
        //基础约束,标识是否是CA证书,这里true标识为CA证书
        builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));

        // 设置密钥用法
       

        
        //证书的签名数据 用于为应用程序提供该功能的数字签名算法。使用数字签名数字数据的认证和完整性保证


        //使用标准算法获取签名实例。
        JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder(SIG_ALG);
        //进行数字签名得到签名值;(私钥用于签名)
        ContentSigner signer = csBuilder.build(privateKeyCA);

        //绑定算法,给证书签名
        X509CertificateHolder holder = builder.build(signer);
        X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(holder);;

        return certificate;
    }

    
    public static void createRootCertSaveToFile(PublicKey publicKeyCA,PrivateKey privateKeyCA, String path){
        try {
            X509Certificate rootCert = createRootCert(publicKeyCA, privateKeyCA);
            writeFile(path, rootCert.getEncoded());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    
    public static X509Certificate createIssueCert(PKCS10CertificationRequest pkc10,X509Certificate rootCert,PrivateKey privateKeyCA)
            throws Exception {
        //获取证书请求中信息
        //X500Name subjectDn = pkc10.getSubject();

        //证书公钥相关信息
        

        //获取公钥(如果获取不到或异常使用上面方法试试)
        byte[] bytes = pkc10.getSubjectPublicKeyInfo().toASN1Primitive().getEncoded("UTF-8");
        PublicKey publicKeyA = getPublicKey(bytes);

        //定义证书有效期
        long year = 360 * 24 * 60 * 60 * 1000;
        Date notBefore = new Date();
        Date notAfter = new Date(notBefore.getTime() + year);

        //serial 证书序列号
        BigInteger serial=BigInteger.valueOf(System.currentTimeMillis());

        //X509Certificate var1, BigInteger var2, Date var3, Date var4, X500Name var5, PublicKey var6
        //构造X.509 第3版的证书构建者  设置证书的基本参数。X509V3是数字证书的一种通用规范标准
        X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(rootCert, //颁发者
                serial, //证书序列号
                notBefore, //证书生效日期
                notAfter, //证书失效日期
                pkc10.getSubject(), //使用者信息
                publicKeyA);//使用者公钥(构造信息)
        //基础约束,标识是否是CA证书,这里false标识为实体证书
        builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(false));

        //使用标准算法获取签名实例。
        JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder(SIG_ALG);
        //进行数字签名得到签名值;(CA私钥。私钥用于签名)
        ContentSigner signer = csBuilder.build(privateKeyCA);

        //绑定算法,给证书签名
        X509CertificateHolder holder = builder.build(signer);
        X509Certificate issueCert = new JcaX509CertificateConverter().getCertificate(holder);;
        return issueCert;
    }

    
    public static void createIssueCertSaveToFile(PKCS10CertificationRequest pkc10,X509Certificate rootCert,PrivateKey privateKeyCA, String path){
        try {
            X509Certificate issueCert = createIssueCert(pkc10, rootCert, privateKeyCA);
            writeFile(path, issueCert.getEncoded());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    
    public static boolean verifyRootCertSign(X509Certificate rootCert)
            throws NoSuchAlgorithmException, InvalidKeyException, CertificateEncodingException, SignatureException {
        //Signature类用于为应用程序提供该功能的数字签名算法。入参:算法
        Signature signature = Signature.getInstance(rootCert.getSigAlgName());
        //初始化该对象以供验证。入参:—要验证其签名的身份的证书。
        signature.initVerify(rootCert);
        //更新或验证数据
        signature.update(rootCert.getTBSCertificate()); //从该证书获取der编码的证书信息,即tbcertificate。这可以用来独立地验证签名。
        //验证传入的签名。入参:需要验证的签名字节数。
        boolean verifySign = signature.verify(rootCert.getSignature());
        return verifySign;
    }

    
    public static boolean verifyIssueCertSign(X509Certificate issueCert,PublicKey publicKeyCA)
            throws NoSuchAlgorithmException, InvalidKeyException, CertificateEncodingException, SignatureException {
        //Signature类用于为应用程序提供该功能的数字签名算法。入参:算法
        Signature signature = Signature.getInstance(issueCert.getSigAlgName());
        //初始化该对象以供验证。入参:—待验证身份的公钥。
        signature.initVerify(publicKeyCA);
        //更新或验证数据
        signature.update(issueCert.getTBSCertificate());//从该证书获取der编码的证书信息,即tbcertificate。这可以用来独立地验证签名。
        //验证传入的签名。入参:需要验证的签名字节数。
        boolean verifySign = signature.verify(issueCert.getSignature());
        return verifySign;
    }

    
    public static boolean verify(X509Certificate X509certificateRoot,
                                 Collection collectionX509CertificateChain,
                                 X509CRL X509crl,
                                 String stringTarget) {
        //获取证书链长度
        int nSize = collectionX509CertificateChain.size();
        //将证书链转化为数组
        X509Certificate[] arX509certificate = new X509Certificate[nSize];
        collectionX509CertificateChain.toArray(arX509certificate);
        //声明list,存储证书链中证书主体信息
        ArrayList list = new ArrayList();
        //沿证书链自上而下,验证证书的所有者是下一个证书的颁布者
        Principal principalLast = null;
        for (int i = 0; i < nSize; i++) {//遍历arX509certificate
            X509Certificate x509Certificate = arX509certificate[i];
            //获取发布者标识
            Principal principalIssuer = x509Certificate.getIssuerDN();
            //获取证书的主体标识
            Principal principalSubject = x509Certificate.getSubjectDN();
            //保存证书的序列号
            list.add(x509Certificate.getSerialNumber());

            if (principalLast != null) {
                //验证证书的颁布者是上一个证书的所有者
                if (principalIssuer.equals(principalLast)) {
                    try {
                            //获取上个证书的公钥
                        PublicKey publickey = arX509certificate[i - 1].getPublicKey();
                        //验证是否已使用与指定公钥相应的私钥签署了此证书
                        arX509certificate[i].verify(publickey);
                    } catch (Exception e) {
                        return false;
                    }
                } else {
                    return false;
                }
            }
            principalLast = principalSubject;

        }

        //验证根证书是否在撤销列表中
        try {
            if (!X509crl.getIssuerDN().equals(X509certificateRoot.getSubjectDN())) return false;
            X509crl.verify(X509certificateRoot.getPublicKey());
        } catch (Exception e) {
            return false;
        }

        //在当前时间下,验证证书链中每个证书是否存在撤销列表中
        if (X509crl != null) {
            try {
                //获取CRL中所有的项
                Set setEntries = X509crl.getRevokedCertificates();

                if (setEntries == null && setEntries.isEmpty() == false) {
                    Iterator iterator = setEntries.iterator();
                    while (iterator.hasNext()) {
                        X509CRLEntry X509crlentry = (X509CRLEntry) iterator.next();

                        if (list.contains(X509crlentry.getSerialNumber())) return false;
                    }
                }
            } catch (Exception e) {
                return false;
            }
        }

        //证明证书链中的第一个证书由用户所信任的CA颁布
        try {
            PublicKey publickey = X509certificateRoot.getPublicKey();
            arX509certificate[0].verify(publickey);
        } catch (Exception e) {
            return false;
        }

        //证明证书链中的最后一个证书的所有者正是现在通信对象
        Principal principalSubject = arX509certificate[nSize - 1].getSubjectDN();
        if (!stringTarget.equals(principalSubject.getName())) return false;
        //验证证书链里每个证书是否在有效期里
        Date date = new Date();
        for (int i = 0; i < nSize; i++) {
            try {
                arX509certificate[i].checkValidity(date);
            } catch (Exception e) {
                return false;
            }
        }
        return true;
    }


    //------------------------------KeyStore---------------------------------------------

    
    
    public static KeyStore createKeyStore(String storePass)throws Exception {
        //Keytool是一个Java数据证书的管理工具 单理解为一个存放应用签名的文件 入参:密钥存储库的类型。PKCS12/JKS
        KeyStore ks = KeyStore.getInstance(KEY_STORE_TYPE);
        //从给定的输入流加载这个KeyStore。
        //入参1:从其中加载密钥存储库的输入流。如果新建,则为NULL
        //入参2:用于解锁密钥存储库的密码
        ks.load(null, storePass.toCharArray());
        return ks;
    }

    
    public static void saveKeyStoreByPath(KeyStore ks, String path,String pwd)throws Exception{
        //定义文件输出对象,将修改后的keyStore存储
        FileOutputStream output = new  FileOutputStream(path);
        //将此密钥存储到给定的输出流,并用密码保护
        //入参1:将此密钥存储库写入其中的输出流。
        //入参2:生成密钥存储库完整性检查的密码
        ks.store(output,pwd.toCharArray());
        output.close();
    }

    
    public static KeyStore loadKeyStore(String path, String storePass) throws Exception{
        //读取文件
        FileInputStream fin = new FileInputStream(path);
        //Keytool是一个Java数据证书的管理工具 单理解为一个存放应用签名的文件 入参:密钥存储库的类型。PKCS12/JKS
        KeyStore ks = KeyStore.getInstance(KEY_STORE_TYPE);
        //从给定的输入流加载这个KeyStore。
        //入参1:从其中加载密钥存储库的输入流。如果新建,则为NULL
        //入参2:用于解锁密钥存储库的密码
        ks.load(fin, storePass.toCharArray());
        fin.close();
        return ks;
    }

    
    public static X509Certificate getCertificateByStore(String keyStorePath,String alias, String stroePwd) throws Exception {
        //获得keyStroe
        KeyStore ks = loadKeyStore(keyStorePath, stroePwd);
        //返回与给定别名关联的证书。
        X509Certificate certificate = (X509Certificate) ks.getCertificate(alias);
        return certificate;
    }

    
    public static PrivateKey readPrivateKey(String alias, String pfxPath,String storePwd,String certPwd) throws Exception {
        KeyStore keyStore = loadKeyStore(pfxPath, storePwd);
        //返回与给定别名关联的键,使用给定的密码恢复它。
        //创建证书时,放入证书的私钥,对应别名(ca的私钥)
        PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, certPwd.toCharArray());
        return privateKey;
    }

    
    public static void listKeyAndCertificate(KeyStore ks, String storePass,String priKeyPass) throws Exception {
        //列出此密钥存储库的所有别名。
        Enumeration enum1 = ks.aliases();
        //测试此枚举是否包含更多元素。
        while (enum1.hasMoreElements()) {
            //获取别名
            String alias = (String) enum1.nextElement();
            //返回与给定别名关联的证书。
            java.security.cert.Certificate c = ks.getCertificate(alias);
            //读取并打印证书
            showX509Certificate((X509Certificate) c);
            //列出store中私钥和证书链信息
            readPriKey(ks, alias, priKeyPass);
        }
    }

    
    public static void readPriKey(KeyStore ks, String alias, String pass)throws Exception {
        //返回与给定别名关联的键,使用给定的密码恢复它。
        Key key;
        key = ks.getKey(alias, pass.toCharArray());
        if (null == key) {
            return;
        }
        System.out.println("key :" + key);
        System.out.println("Key的算法=" + key.getAlgorithm());
        System.out.println("Key的编码格式=" + key.getFormat());
        //列出store中证书链信息
        readCertChain(ks, alias);
    }

    
    public static void readCertChain(KeyStore ks, String alias) throws Exception {
        //返回与给定别名关联的证书链
        Certificate[] certChain = ks.getCertificateChain(alias);
        if (null == certChain) {
            return;
        }
        for (Certificate c : certChain) {
            //读取并打印证书信息
            showX509Certificate((X509Certificate) c);
        }
    }

    
    public static void changePassword(String storePath,String oldPwd,String newPwd) throws Exception{
        //获得keyStore
        KeyStore ks = loadKeyStore(storePath, oldPwd);
        saveKeyStoreByPath(ks, storePath, newPwd);
    }

    
    public static void deleteAlias(String certPath,String password,String alias,String entry) throws Exception{
        //获得keyStore
        KeyStore ks = loadKeyStore(certPath, password);
        //验证是否存在此别名
        if(ks.containsAlias(alias)){
            //从这个密钥存储库中删除由给定别名标识的条目。 入参:别名
            ks.deleteEntry(entry);

            //删除后重新存储
            saveKeyStoreByPath(ks, certPath, password);
        }else{
            throw new Exception("该证书未包含别名--->"+alias);
        }
    }

    public static void testKeyStore(){
        try {
            
            String keyStroeFielPath = "E:/CertTest/testKeyStore.pfx";
            String newKsPwd = "666666";

            //存储根证书的别名
            String caAlias = "caCert";
            //存储根证书的密码
            String caPwd = "111222";

            //创建一个KeyStore
            String keyStroePwd = "112233";
            KeyStore keyStore = createKeyStore(keyStroePwd);
            System.out.println("创建KeyStore:" + keyStore.toString());
            //将KeyStore存储到指定路径
            saveKeyStoreByPath(keyStore, keyStroeFielPath, keyStroePwd);
            System.out.println("存储到本地完成");
            //修改密码
            changePassword(keyStroeFielPath, keyStroePwd, newKsPwd);
            System.out.println("修改密码完成,新密码为:" + newKsPwd);

            //加载本地KeyStore
            KeyStore loadKeyStore = loadKeyStore(keyStroeFielPath, newKsPwd);
            System.out.println("读取本地KeyStore:n" + loadKeyStore);

            //创建根证书并存储到KeyStore中
            KeyPair caKeypair = getKeyPair();
            PublicKey caPublicKey = caKeypair.getPublic();
            PrivateKey caPrivateKey = caKeypair.getPrivate();
            X509Certificate rootCert = createRootCert(caPublicKey, caPrivateKey);

            //存储
            loadKeyStore.setKeyEntry(caAlias,//证书别名
                    caPrivateKey,//私钥
                    caPwd.toCharArray(), //密码
                    new Certificate[]{rootCert} //证书链
            );
            //切记在存储一次,不然keyStore没存进去
            saveKeyStoreByPath(loadKeyStore, keyStroeFielPath, newKsPwd);

            //读取证书并打印
            X509Certificate caRootCert = getCertificateByStore(keyStroeFielPath, caAlias, newKsPwd);
            System.out.println(caRootCert);
            showX509Certificate(caRootCert);
            System.out.println("n");

            PrivateKey privateKey = readPrivateKey(caAlias, keyStroeFielPath, newKsPwd, caPwd);
            String caPk = Base64.getEncoder().encodeToString(privateKey.getEncoded());
            System.out.println("读取的Base64公钥:" + caPk);
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("KeyStore测试中出现问题");
        }
    }

    
    public static void main(String[] args) {
        try {
            //初始化获取公钥和私钥
           

            

            

            

            

            

            

            

            

            //生成csr(证书请求文件)
           

            

            

            

            

            

            //testKeyStore();
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("出现异常");
        }
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1024953.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号