zoukankan      html  css  js  c++  java
  • 2020_1课程设计—基于BC的证书格式转换工具的设计与实现—第二周进展

    本周任务

    • 收集相关资料,学习BouncyCastle的使用方法
    • 使用BouncyCastle编程实现证书格式的转换

    完成情况

    BouncyCastle的配置

    • 将下载的两个jar包拷贝到$JAVA_HOME$jrelibext目录下面

    • 修改配置文件jrelibsecurityjava.security,在末尾添加security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider

    • 测试成功

    • 使用时需要在项目中导入jar包

    • 然后在代码中导入类
    import java.security.Security;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    • 在初始化密钥工厂、密钥生成器等引擎前调用如下代码
    Security.addProvider(new BouncyCastleProvider());
    

    使用BouncyCastle编程实现证书格式的转换

    PEM——>PFX

    • 因为PEM证书中无私钥,而PFX证书中有加密的公钥和私钥,所以这一步需要调用产生证书时保留的私钥

    整体思路

    • 使用BC提取PEM证书、私钥,再使用BC生成PFX证书

    编程思路

    • 先使用BouncyCastle的PemReader
      • 从PEM证书文件中提取出PemObject对象certPEM
      • 从PEM私钥文件中提取出PemObject对象keyPEM
    • 从certPEM中提取字节数组,并使用类java.security.cert.CertificateFactory,将提取出的的字节数组转化为X509Certificate对象
    • 从keyPEM中提取字节数组,并使用类KeyFactory,生成PrivateKey文件
    • 使用BouncyCastle的PKCS12KeyStore类,导入加密的密码,和之前生成的私钥、证书对象
    • 输出PFX证书

    初步代码(功能已实现)

    import java.io.*;
    import java.lang.*;
    import java.security.cert.*;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.*;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemReader;
    import sun.security.pkcs12.PKCS12KeyStore;
    public class PEMToPFX {
        public static void main(String[] args) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, InvalidKeySpecException {
            {
                Security.addProvider( new BouncyCastleProvider() );
                PemReader reader = new PemReader( new FileReader( "C:\Users\Administrator\eclipse-workspace\课程设计_1\src\ca.pem" ) );
                Object pemObject = reader.readPemObject();
                PemObject certPEM = (PemObject)pemObject;
                byte b[] = certPEM.getContent();
                X509Certificate cert=(X509Certificate)CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(b));
                System.out.println(cert);
                PemReader reader1 = new PemReader(new FileReader( "C:\Users\Administrator\eclipse-workspace\课程设计_1\src\pfx_pri.pem" ));
                Object keyPem =reader1.readPemObject();
                PemObject pm = (PemObject) keyPem;
                byte[] keyByte = pm.getContent();
                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyByte);
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
                char[] StorePasswd = "jinhuan888".toCharArray();
                PKCS12KeyStore store = new PKCS12KeyStore();
                X509Certificate[] chain = new X509Certificate[1];
                chain[0]= cert;
                store.engineSetCertificateEntry( "CA's Primary Certificate", cert );
                store.engineSetKeyEntry( "CA's Primary Certificate",privateKey, StorePasswd,chain);
                FileOutputStream out = new FileOutputStream( "C:\Users\Administrator\eclipse-workspace\课程设计_1\src\ca.pfx" );
                store.engineStore( out,StorePasswd );
                out.close();
            }
        }
    }
    

    PFX——>PEM

    整体思路

    • 使用BC提取PFX证书,经过Base64编码,然后使用BC生成PEM证书

    编程思路

    • 使用BouncyCastle的PKCS12KeyStore类,通过密码,加载PFX证书
    • 提取PKCS12KeyStore的别名alias
    • 通过别名alias访问其中的证书,并将其转换为X509Certificate对象
    • 使用X509Certificate类的getEncode()方法,获取PEM文件所需的Base64编码
    • 使用该Base64编码,生成PemObject对象
    • 使用BouncyCastle的PemWriter类,生成PEM证书

    初步代码(功能已实现)

    import java.io.*;
    import java.lang.*;
    import java.security.cert.*;
    import java.security.cert.Certificate;
    import java.security.*;
    import java.util.Enumeration;
    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemWriter;
    import sun.security.pkcs12.PKCS12KeyStore;
    
    public class PFXToPEM {
        public static void main(String[] args) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException {
            FileInputStream fs = new FileInputStream( "C:\Users\Administrator\eclipse-workspace\课程设计_1\src\ca.pfx" );
            char[] passwd = "jinhuan888".toCharArray();
            PKCS12KeyStore store = new PKCS12KeyStore();
            store.engineLoad(fs,passwd);
            fs.close();
            Enumeration enumas = store.engineAliases();
            String keyAlias = null;
            if (enumas.hasMoreElements())
            {
                keyAlias = (String)enumas.nextElement();
                System.out.println("alias=[" + keyAlias + "]");
            }
            Certificate cert = store.engineGetCertificate(keyAlias);
            X509Certificate certificate = (X509Certificate)cert;
            System.out.println(certificate);
            PemObject pemCSR = new PemObject("CERTIFICATE", certificate.getEncoded());
            StringWriter str = new StringWriter();
            PemWriter pemWriter = new PemWriter(str);
            pemWriter.writeObject(pemCSR);
            pemWriter.close();
            str.close();
            FileOutputStream certOut = new FileOutputStream("C:\Users\Administrator\eclipse-workspace\课程设计_1\src\pfx_ca.cer");
            certOut.write(str.toString().getBytes());
        }
    }
    

    PEM——>DER

    整体思路

    • 使用BC提取PEM证书,将其字节数组输出到DER文件

    编程思路

    • 使用BC的PemReader类提取PEM证书,获得PemObject对象
    • PemObject对象中提取字节数组
    • 将字节数组输出到DER文件,得到DER证书

    初步代码(功能已实现)

    import java.io.*;
    import java.lang.*;
    import java.security.cert.*;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.*;
    
    import org.bouncycastle.asn1.DEROutputStream;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemReader;
    import sun.security.pkcs12.PKCS12KeyStore;
    import sun.security.util.DerOutputStream;
    
    public class PEMToDER_2 {
        public static void main(String[] args) throws IOException {
            {
                Security.addProvider( new BouncyCastleProvider() );
                PemReader reader = new PemReader( new FileReader( "C:\Users\Administrator\eclipse-workspace\课程设计_1\src\ca.pem" ) );
                Object pemObject = reader.readPemObject();
                PemObject p = (PemObject)pemObject;
                byte b[] = p.getContent();
                File file=new File("C:\Users\Administrator\eclipse-workspace\课程设计_1\src\ca.der");
                if(!file.exists()){
                        file.createNewFile();
                }
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(b);
                fos.close();
            }
        }
    }
    

    DER——>PEM

    整体思路

    • 提取DER证书字节数组,使用BC生成PEM证书

    编程思路

    • 读取DER证书的字节数组
    • 使用该字节数组生成PemObject对象
    • 使用BC的PemWriter类,输出PEM文件

    初步代码(功能已实现)

    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemWriter;
    import java.io.*;
    
    public class DERToPEM {
        public static void main(String[] args) throws IOException {
            File src = new File("C:\Users\Administrator\eclipse-workspace\课程设计_1\src\ca.der");
            byte[] datas = null;
            try (InputStream is = new BufferedInputStream(new FileInputStream(src));
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();) {
                byte[] flush = new byte[1024];
                int len = -1;
                while ((len = is.read(flush)) != -1) {
                    baos.write(flush, 0, len);
                }
                baos.flush();
                datas = baos.toByteArray();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            PemObject pemCSR = new PemObject("CERTIFICATE", datas);
            StringWriter str = new StringWriter();
            PemWriter pemWriter = new PemWriter(str);
            pemWriter.writeObject(pemCSR);
            pemWriter.close();
            str.close();
            FileOutputStream certOut = new FileOutputStream("C:\Users\Administrator\eclipse-workspace\课程设计_1\src\der_ca.cer");
            certOut.write(str.toString().getBytes());
        }
    }
    

    P7B——>PEM

    整体思路

    • 读取P7B证书的证书链,从证书链中获取X509Certificate证书,再使用BC生成PEM证书

    编程思路

    • 读取P7B证书的字节数组
    • 从该字节数组中提取证书链
    • 使用BC的PemWriter类,输出PEM文件(方法同之前)、

    初步代码(功能已实现)

    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemWriter;
    import java.io.*;
    import java.security.Security;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateFactory;
    import java.security.cert.X509Certificate;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.List;
    
    public class P7BToPEM {
        public static void main(String[] args) throws Exception {
            Security.addProvider(new BouncyCastleProvider());
            X509Certificate cert;
            File file = new File("C:\Users\Administrator\eclipse-workspace\课程设计_1\src\ca.p7b");
            byte[] buffer = new byte[(int) file.length()];
            DataInputStream in = new DataInputStream(new FileInputStream(file));
            in.readFully(buffer);
            in.close();
            Certificate[] chain = readCertificatesFromPKCS7(buffer);
            cert = (X509Certificate) chain[0];
            System.out.println(cert);
            PemObject pemCSR = new PemObject("CERTIFICATE", cert.getEncoded());
            StringWriter str = new StringWriter();
            PemWriter pemWriter = new PemWriter(str);
            pemWriter.writeObject(pemCSR);
            pemWriter.close();
            str.close();
            FileOutputStream certOut = new FileOutputStream("C:\Users\Administrator\eclipse-workspace\课程设计_1\src\p7b_ca.cer");
            certOut.write(str.toString().getBytes());
        }
        public static final Certificate[] readCertificatesFromPKCS7(byte[] binaryPKCS7Store) throws Exception
        {
            try (ByteArrayInputStream bais = new ByteArrayInputStream(binaryPKCS7Store))
            {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                Collection<?> c = cf.generateCertificates(bais);
    
                List<Certificate> certList = new ArrayList<Certificate>();
    
                if (c.isEmpty())
                {
                    // If there are now certificates found, the p7b file is probably not in binary format.
                    // It may be in base64 format.
                    // The generateCertificates method only understands raw data.
                }
                else
                {
    
                    Iterator<?> i = c.iterator();
    
                    while (i.hasNext())
                    {
                        certList.add((Certificate) i.next());
                    }
                }
    
                Certificate[] certArr = new Certificate[certList.size()];
    
                return certList.toArray(certArr);
            }
        }
    }
    

    遇到的问题与解决过程

    问题1:在提取PEM文件到X509Certificate对象的过程中,尝试直接强转,报错

    解决1:先生成PemObject对象,提取字节数组,并使用CertificateFactory进行转换

    问题2:加载PKCS12KeyStore对象时,发现缺少私钥

    解决2:PEM文件中没有私钥,需要读入生成证书时保存的私钥文件中的私钥

    问题3:在读取DER文件时,刚开始直接进行读取,在转为字节数组,出现转换错误的问题

    解决3:使用ByteArrayInputStreamByteArrayOutputStream类读取字节数组

    问题4:无法将PEM证书转换为P7B证书

    尚未解决:因为证书链操作缺少方法,并且搜索不到相关资料

    未来展望

    • 探索更多的格式转换方式
    • 完善已有代码,将代码写的更整洁,更符合java代码规范
  • 相关阅读:
    c# winform DataGridView单击选中一整行,只能单选,不能选择多行,只能选择一行
    c# winform 子窗体向父窗体传值
    as中使用字体
    出现“正尝试安装的adobe flash player不是最新版本”的解决方法
    打印等腰三角形
    【Array数组】数组的浅复制和深复制
    AIR程序app.xml配置详解(转)
    【Array数组】使用slice返回数组中的元素
    creationComplete和applicationComplete区别
    【XML】遍历xml子节点
  • 原文地址:https://www.cnblogs.com/wyf20175217/p/12734524.html
Copyright © 2011-2022 走看看