PFX文件解析及读取、写入、删除相关操作

针对pfx文件的解析及操作,java 标准库提供了很好的支持,需要做一定得封装,才能比较友好的使用,如下是我做的一些封装及核心代码,话不多说,直接上代码

本次JDK版本 zulu-11

pfx自定义封装类:方便使用公私钥信息

import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Date;

@Data
@NoArgsConstructor
public class PfxObj implements Serializable {
    // 私钥
    private PrivateKey privateKey;
    // 公钥数组 
    private Certificate[] certificateChain;
    // 核心公钥信息,包含公钥、过期日期等等
    private X509Certificate x509Certificate;
    // 证书公钥过期时间
    private Date expiredAt;
    
    private String commonName;
    //alias
    private String aliasName;
}

pfx解析及读写操作核心工具类


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.bindo.module.PfxObj;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class PfxTools {
    public final static String UPDATE_PFX_KEY="manual_update_pfx";
    public final static String JUST_ONE_TASK="JUST_ONE_TASK";
    public final static Map<String,Date> MANUAL_UPDATE_PFX = new ConcurrentHashMap<>();

    /**
     * 读取pfx文件,获取KeyStore对象
     * @param keyStorePath pfx文件
     * @param password pfx访问密码
     * @return
     */
    public static KeyStore loadKeyStore(String keyStorePath, String password) {
        KeyStore keyStore = null;
        FileInputStream fisFrom = null;
        try {
            keyStore = KeyStore.getInstance("PKCS12");
            fisFrom = new FileInputStream(keyStorePath);
            keyStore.load(fisFrom, password.toCharArray());
        } catch (Exception e) {
            log.error("加载pfx时异常,file" + keyStorePath, e);
        } finally {
            if (fisFrom != null) {
                try {
                    fisFrom.close();
                } catch (IOException e) {
                    log.error("关闭文件流异常.", e);
                }
            }
        }
        return keyStore;
    }

    /**
     * 保存KeyStore对象至pfx文件
     * @param ksFrom KeyStore对象
     * @param fromPw pfx访问密码
     * @param storePath pfx保存路径及文件
     * @return
     */
    public static boolean storeKeyStore(KeyStore ksFrom, String fromPw, String storePath) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(storePath);
            ksFrom.store(fileOutputStream, fromPw.toCharArray());
        } catch (Exception e) {
            log.error("保存pfx到文件异常.storePath=" + storePath, e);
            return false;
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    log.error("关闭文件流异常.", e);
                }
            }
        }
        return true;
    }

    /**
     * 读取pfx文件,生成pfx自定义对象(PfxObj)集合
     * @param pfxFileStr pfx文件
     * @param pfxPassword pfx访问密码
     * @return
     * @throws Exception
     */
    public static Map<String, PfxObj> readPfxFile(String pfxFileStr, String pfxPassword) throws Exception {
        Map<String, PfxObj> pfxObjMap = new HashMap<>();
        KeyStore ks = KeyStore.getInstance("PKCS12");
        FileInputStream fis = new FileInputStream(pfxFileStr);
        // If the keystore password is empty(""), then we have to set
        // to null, otherwise it won't work!!!
        char[] nPassword = null;
        if ((pfxPassword == null) || pfxPassword.trim().equals("")) {
            nPassword = null;
        } else {
            nPassword = pfxPassword.toCharArray();
        }
        ks.load(fis, nPassword);
        fis.close();
        // System.out.println("keystore type=" + ks.getType());
        // Now we loop all the aliases, we need the alias to get keys.
        // It seems that this value is the "Friendly name" field in the
        // detals tab <-- Certificate window <-- view <-- Certificate
        // Button <-- Content tab <-- Internet Options <-- Tools menu
        // In MS IE 6.
        Enumeration enumas = ks.aliases();
        String keyAlias = null;
        PrivateKey prikey = null;
        int times = 0;
        while (enumas.hasMoreElements())// we are readin just one certificate.
        {
            keyAlias = (String) enumas.nextElement();
            prikey = (PrivateKey) ks.getKey(keyAlias, nPassword);
            Certificate cert = ks.getCertificate(keyAlias);
            X509Certificate x509Certificate = (X509Certificate) ks.getCertificate(keyAlias);
            Certificate[] certificateChain = ks.getCertificateChain(keyAlias);
            PublicKey pubkey = cert.getPublicKey();
            times++;
            PfxObj pfxObj = new PfxObj();
            pfxObj.setCertificateChain(certificateChain);
            pfxObj.setPrivateKey(prikey);
            pfxObj.setX509Certificate(x509Certificate);
            pfxObj.setAliasName(keyAlias);
            pfxObj.setCommonName(((JSONObject) JSON.toJSON(x509Certificate)).getJSONObject("subjectDN").getString("commonName"));
            pfxObj.setExpiredAt(x509Certificate.getNotAfter());
            pfxObjMap.put(keyAlias, pfxObj);
        }
        // System.out.println("=============== 证书数量=" + times + " =============");
        return pfxObjMap;
    }

    /**
     * 以account为维度,获取pfx证书,多个证书时,取最新的过期时间
     *
     * @param pfxFileStr
     * @param pfxPassword
     * @return
     * @throws Exception
     */
    public static Map<String, PfxObj> getPfxToSpAccountMap(String pfxFileStr, String pfxPassword) throws Exception {
        Map<String, PfxObj> pfxObjMap = readPfxFile(pfxFileStr, pfxPassword);
        Map<String, PfxObj> spAccountPfxMap = new HashMap<>();
        if (CollectionUtils.isEmpty(pfxObjMap)) {
            return spAccountPfxMap;
        }
        Iterator<Map.Entry<String, PfxObj>> iterator = pfxObjMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, PfxObj> pfxCer = iterator.next();
            if (spAccountPfxMap.containsKey(pfxCer.getValue().getCommonName())) {
                if (spAccountPfxMap.get(pfxCer.getValue().getCommonName()).getExpiredAt().before(pfxCer.getValue().getExpiredAt())) {
                    spAccountPfxMap.replace(pfxCer.getValue().getCommonName(), pfxCer.getValue());
                }

            } else {
                spAccountPfxMap.put(pfxCer.getValue().getCommonName(), pfxCer.getValue());
            }
        }
        return spAccountPfxMap;
    }

    /**
     * pfx的A文件写入至B文件
     * 此处未保存到文件,只是存入B的KeyStore对象
     * @param toFile 接收pfx的文件
     * @param toPw 接收文件的访问密码
     * @param fromFile 被复制的
     * @param fromPw
     * @return
     * @throws Exception
     */
    public static KeyStore writePFX(String toFile, String toPw, String fromFile, String fromPw) throws Exception {
        KeyStore ksTo = KeyStore.getInstance("PKCS12");
        FileInputStream fisTo = new FileInputStream(toFile);
        ksTo.load(fisTo, toPw.toCharArray());

        KeyStore ksFrom = KeyStore.getInstance("PKCS12");
        FileInputStream fisFrom = new FileInputStream(fromFile);
        ksFrom.load(fisFrom, fromPw.toCharArray());
        Enumeration<String> aliases = ksFrom.aliases();
        while (aliases.hasMoreElements()) {
            String aliase = aliases.nextElement();
            if (!ksFrom.isKeyEntry(aliase)) {
                continue;
            }
            Key keyFrom = ksFrom.getKey(aliase, fromPw.toCharArray());
            Certificate[] certificateChainFrom = ksFrom.getCertificateChain(aliase);
            ksTo.setKeyEntry(aliase, keyFrom, toPw.toCharArray(), certificateChainFrom);
        }
        return ksTo;
    }

    /**
     * pfx的A文件写入至B文件
     * 只是写入到某个已存在的KeyStore对象,还未保存至文件
     * @param ksTo KeyStore接收公私钥
     * @param toPw 接收者的访问密码
     * @param fromFile 待读取的pfx文件
     * @param fromPw 访问密码
     * @return
     * @throws Exception
     */
    public static KeyStore writePFX(KeyStore ksTo, String toPw, String fromFile, String fromPw) throws Exception {
        KeyStore ksFrom = KeyStore.getInstance("PKCS12");
        FileInputStream fisFrom = new FileInputStream(fromFile);
        ksFrom.load(fisFrom, fromPw.toCharArray());
        Enumeration<String> aliases = ksFrom.aliases();
        while (aliases.hasMoreElements()) {
            String aliase = aliases.nextElement();
            if (!ksFrom.isKeyEntry(aliase)) {
                continue;
            }
            Key keyFrom = ksFrom.getKey(aliase, fromPw.toCharArray());
            Certificate[] certificateChainFrom = ksFrom.getCertificateChain(aliase);
            ksTo.setKeyEntry(aliase, keyFrom, toPw.toCharArray(), certificateChainFrom);
        }
        return ksTo;
    }

    /**
     * pfx的A文件写入至B文件
     * 将pfx自定义对象写入到KeyStore,未保存至文件
     * @param ksTo KeyStore接收公私钥
     * @param toPw 接收者的访问密码
     * @param pfxObj pfx自定义对象
     * @return
     * @throws Exception
     */
    public static KeyStore writePFX(KeyStore ksTo, String toPw, PfxObj pfxObj) throws Exception {
        ksTo.setKeyEntry(pfxObj.getCommonName(), pfxObj.getPrivateKey(), toPw.toCharArray(), pfxObj.getCertificateChain());
        return ksTo;
    }

    /**
     * 从pfx文件中删除某个alias的公私钥信息
     * 未保存至文件
     * @param fromFile
     * @param fromPw
     * @param aliaseRemove
     * @return
     * @throws Exception
     */
    public static KeyStore removePFX(String fromFile, String fromPw, String aliaseRemove) throws Exception {

        KeyStore ksFrom = KeyStore.getInstance("PKCS12");
        FileInputStream fisFrom = new FileInputStream(fromFile);
        ksFrom.load(fisFrom, fromPw.toCharArray());
        Enumeration<String> aliases = ksFrom.aliases();
        boolean removeFlag = false;
        while (aliases.hasMoreElements()) {
            String aliase = aliases.nextElement();
            if (aliase.equalsIgnoreCase(aliaseRemove)) {
                removeFlag = true;
            }
        }
        if (removeFlag) {
            ksFrom.deleteEntry(aliaseRemove);
        }
        return ksFrom;
    }

    /**
     * 从KeyStore删除某个公私钥对
     * @param ksFrom
     * @param fromPw
     * @param aliaseRemove
     * @return
     * @throws Exception
     */
    public static KeyStore removePFX(KeyStore ksFrom, String fromPw, String aliaseRemove) throws Exception {
        Enumeration<String> aliases = ksFrom.aliases();
        boolean removeFlag = false;
        while (aliases.hasMoreElements()) {
            String aliase = aliases.nextElement();
            if (aliase.equalsIgnoreCase(aliaseRemove)) {
                removeFlag = true;
            }
        }
        if (removeFlag) {
            ksFrom.deleteEntry(aliaseRemove);
        }
        return ksFrom;
    }

    /**
     * 下载pfx文件
     * @param fileUri
     * @param downloadedFile
     * @throws Exception
     */
    public static void downloadNetFile(String fileUri, String downloadedFile) throws Exception {
        // 下载网络文件
        int bytesum = 0;
        int byteread = 0;

        URL url = new URL(fileUri);
        InputStream inStream = null;
        FileOutputStream fs = null;
        try {
            URLConnection conn = url.openConnection();
            inStream = conn.getInputStream();
            fs = new FileOutputStream(downloadedFile);

            byte[] buffer = new byte[1204];
            int length;
            while ((byteread = inStream.read(buffer)) != -1) {
                bytesum += byteread;
                fs.write(buffer, 0, byteread);
            }
            fs.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            inStream.close();
            fs.close();
        }
    }

    /**
     * 执行shell命令
     * @param commands
     * @return
     */
    public static List<String> executeNewFlow(List<String> commands) {
        List<String> rspList = new ArrayList<String>();
        Runtime run = Runtime.getRuntime();
        try {
            Process proc = run.exec("/bin/bash", null, null);
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
            for (String line : commands) {
                out.println(line);
            }
            out.println("exit");// 这个命令必须执行,否则in流不结束。
            String rspLine = "";
            while ((rspLine = in.readLine()) != null) {
                System.out.println(rspLine);
                rspList.add(rspLine);
            }
            proc.waitFor();
            in.close();
            out.close();
            proc.destroy();
        } catch (IOException e1) {
            e1.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return rspList;
    }

    /**
     * 是否在有效期内
     *
     * @param expriedDate 过期时间
     * @param days        即将过期预警天数
     * @return
     */
    public static boolean isValidIn(Date expriedDate, int days) {
        int expiredInTimes = days * 24 * 60 * 60 * 1000;
        long gapTime = expriedDate.getTime() - new Date().getTime();
        return gapTime - expiredInTimes > 0 ? true : false;
    }

    public static Integer extractSpId(String str) {
        if (StringUtils.isBlank(str) || !str.startsWith("SP") || !str.contains("-")) {
            log.error("无效的sp身份ID=" + str);
            return null;
        }
        int index = str.indexOf("-");
        Integer spId = null;
        try {
            spId = Integer.valueOf(str.substring(2, index));
        } catch (NumberFormatException e) {
            log.error("无效的sp身份ID=" + str, e);
        }
        return spId;
    }

    public static void main(String[] args) throws Exception {
//        Map<String, PfxObj> pfxObjMap = readPfxFile("/Users/bindo/Downloads/ecert.pfx", "123456");
//        Iterator<String> iterator = pfxObjMap.keySet().iterator();
//        Map<String,Integer> commonNameMap = new HashMap<>();
//        while (iterator.hasNext()){
//            String key = iterator.next();
//            String commonName = pfxObjMap.get(key).getCommonName();
//            if (commonNameMap.containsKey(commonName)){
//                commonNameMap.put(commonName,commonNameMap.get(commonName)+1);
//            }else {
//                commonNameMap.put(commonName,1);
//            }
//            // System.out.println("证书的alias="+key+", commonName="+commonName+", 有效期="+pfxObjMap.get(key).getX509Certificate().getNotAfter()+", 是否失效="+pfxObjMap.get(key).getX509Certificate().getNotAfter().before(new Date()));
//
//        }
//        Iterator<String> iterator1 = commonNameMap.keySet().iterator();
//        // System.out.println("sip是否有同名:");
//        while (iterator1.hasNext()){
//            String next = iterator1.next();
//            // System.out.println(next+"="+commonNameMap.get(next));
//        }


//        downloadNetFile("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2020-07-23%2F5f195601471b5.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659774124&t=330917ba468613cc969d159e4a7d1a28","/Users/bindo/Downloads/OSDX-3/abc.gif");
        // System.out.println(extractSpId("SP59938s5t-_mop"));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值