PFX file analysis and read, write, delete related operations

For the analysis and operation of pfx files, the java standard library provides good support. It needs to be packaged to be more friendly to use. The following are some packages and core codes I made. Not much to say, just upload the code directly

This JDK version zulu-11

pfx custom encapsulation class: easy to use public and private key information

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;
}

Core tools for pfx parsing and read/write operations


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"));
    }
}

Guess you like

Origin blog.csdn.net/m0_37298500/article/details/126289677