1. 程式人生 > >獲取數字證書相關資訊,證書鏈有效性驗證,RSA加密和解密功能之證書鏈有效性驗證

獲取數字證書相關資訊,證書鏈有效性驗證,RSA加密和解密功能之證書鏈有效性驗證

 /**
     * 證書有效性驗證,後臺將證書鏈以byte[]陣列集合的形式傳入
     * @param certChain 後臺傳入的證書鏈
     * @param cert2Verify 本地需要驗證的證書
     * @return
     */
    public int certificateValidate(List<byte[]> certChain, byte[] cert2Verify) {
        List<X509Certificate> certss = new ArrayList<>();
        CertificateFactory certificatefactory;
        X509Certificate cert;
        InputStream input;
        try {
            certificatefactory = CertificateFactory.getInstance("X.509");
//轉換為inputstream,並將此inputstream轉為X509Certificate的型別加入到list集合中,用於後續的
//排序
            input = new ByteArrayInputStream(cert2Verify);
            cert = (X509Certificate) certificatefactory.generateCertificate(input);
            certss.add(cert);
//將證書鏈中的每一層節點轉換為X509Certificate型別並加入到集合中
            for (byte[] b : certChain) {
                input = new ByteArrayInputStream(b);
                cert = (X509Certificate) certificatefactory.generateCertificate(input);
                certss.add(cert);
            }
            //排序,為什麼需要排序?因為後臺傳入過來的證書鏈並不一定是按照驗證順序進行排序的,
//所以需要進行排序後驗證
            List<X509Certificate> certs = order(certss);
//進行長度判斷,如果驗證證書鏈排序過程中,出現問題直接驗證失敗
            if (certs.size() != certss.size()) {
                Log.e("123", "證書鏈校驗失敗");
                return 1;
            }
            //驗證
            verifyCerts(certs);
            Log.e("123", "證書驗證成功");
            return 0;
        } catch (CertificateException e) {
            e.printStackTrace();
            Log.e("123", "證書無效");
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("123", "證書無效");
            return 0;
        }

    }

    /**
     * 找到證書父節點
     * @param parents
     * @param child
     * @return
     */
    private X509Certificate findParent(List<X509Certificate> parents, X509Certificate child) {
//獲取到需要找到父節點證書的頒佈者
        Principal p = child.getIssuerDN();
        Principal subjectDN = child.getSubjectDN();
//如果證書的頒發者與頒發給是一樣的,說明此證書沒有父節點,為最外層證書
        if (p.equals(subjectDN)) {
            return null;
        }


        for (int i = 0; i < parents.size(); i++) {
            X509Certificate parent = parents.get(i);
            if (p.equals(parent.getSubjectDN())) {
                return parent;
            }
        }
        return null;
    }

    /**
     * 排序
     * @param certss
     * @return
     */
    private List<X509Certificate> order(List<X509Certificate> certss) {
        List<X509Certificate> certInOder = new ArrayList<>();
        X509Certificate cert2Verify = certss.get(0);
        certInOder.add(cert2Verify);
        for (int i = 0; i < certss.size(); i++) {
//找到父節點
            X509Certificate parent = findParent(certss, cert2Verify);
            if (parent == null) {
                break;
            } else {
//找到父節點證書後加入到集合中,並把找到的證書作為子證書,去尋找它的父節點
                certInOder.add(parent);
                cert2Verify = parent;
            }
        }
        return certInOder;
    }

    /**
     * 證書有效性驗證
     * @param certs
     * @throws Exception
     */
    private static void verifyCerts(List<X509Certificate> certs) throws Exception {
        int n = certs.size();
        for (int i = 0; i < n - 1; i++) {
            X509Certificate cert = certs.get(i);
            X509Certificate issuer = (X509Certificate) certs.get(i + 1);
//驗證,這裡的驗證需要是排序好的
            cert.verify(issuer.getPublicKey());
        }
//自己驗證自己,此步可以不要
        X509Certificate last = (X509Certificate) certs.get(n - 1);
        last.verify(last.getPublicKey());
    }

驗證程式碼示例:

  private String getKeyFromCRT() {
        Log.e("===========PublicKey", "getKeyFromCRT()");
        String key = "";
//        String key1 = "";
        CertificateFactory certificatefactory;
        X509Certificate Cert;
        InputStream bais;
        InputStream bais1;
        InputStream bais2;

        PublicKey pk1;
        try {
           
            certificatefactory = CertificateFactory.getInstance("X.509");
            //讀取放在專案中assets資料夾下的.crt檔案;你可以讀取絕對路徑檔案下的crt,返回一個InputStream(或其子類)。
//證書鏈
            bais = getAssets().open("2.cer");
            bais1 = getAssets().open("1.cer");
//需要驗證的證書
            bais2 = getAssets().open("cn.crt");
//將inputstream轉換為byte陣列
            List<byte[]> bytes = new ArrayList<>();
            ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
            byte[] buff = new byte[100];
            int rc = 0;
            while ((rc = bais.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
            byte[] b = swapStream.toByteArray();
//新增到集合
            bytes.add(b);


            ByteArrayOutputStream swapStre = new ByteArrayOutputStream();
            byte[] buff1 = new byte[100];
            int rc1 = 0;
            while ((rc1 = bais1.read(buff1, 0, 100)) > 0) {
                swapStre.write(buff1, 0, rc1);
            }
            byte[] b1 = swapStre.toByteArray();
            bytes.add(b1);


            ByteArrayOutputStream swapStre2 = new ByteArrayOutputStream();
            byte[] buff2 = new byte[100];
            int rc3 = 0;
            while ((rc3 = bais2.read(buff2, 0, 100)) > 0) {
                swapStre2.write(buff2, 0, rc3);
            }
            byte[] b3 = swapStre2.toByteArray();

            certificate.getCertificateInfo(b3);
//驗證
            certificate.certificateValidate(bytes,b3);