java pkcs7格式簽名工具


package com.xxx.util;

import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;

/**
 * PKCS7Tool.java pkcs7格式簽名工具,讀取證書密鑰進行加密
 *
 * @version 1.0
 * @author  Written Date: 2020-01-03
 *         JDK
 */
public class PKCS7Tool {
    /** 簽名證書鏈 */
    static X509Certificate[] certificates = null;
    /** 簽名私鑰 */
    static PrivateKey privateKey = null;
    /** 根證書 */
    //private Certificate rootCertificate = null;
    /** 證書存放路徑 */
    static String keyStorePath = "C:\\upload\\cert.pfx";
    /** 證書密碼 */
    static String keyStorePassword = "..";
    /** JVM 提供商 */
    private static char jvm = 0;
    private static Class algorithmId = null;
    private static Class derValue = null;
    private static Class objectIdentifier = null;
    private static Class x500Name = null;
    private static boolean debug = false;
    private static BouncyCastleProvider bouncyCastleProvider = null;

    static {
        try {
            //如果是PKCS7Padding填充方式,則必須加上下面這行
            if (bouncyCastleProvider == null) {
                bouncyCastleProvider = new BouncyCastleProvider();
            }
            Security.addProvider(bouncyCastleProvider);
            init();
            // 加載證書庫
            KeyStore keyStore = null;
            if (keyStorePath.toLowerCase().endsWith(".pfx"))
                keyStore = KeyStore.getInstance("PKCS12");
            else
                keyStore = KeyStore.getInstance("JKS");
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(keyStorePath);
                keyStore.load(fis, keyStorePassword.toCharArray());
            } finally {
                if (fis != null)
                    fis.close();
            }
            // 在證書庫中找到簽名私鑰
            Enumeration aliases = keyStore.aliases();
            String keyAlias = null;
            if (aliases != null) {
                while (aliases.hasMoreElements()) {
                    keyAlias = (String) aliases.nextElement();
                    Certificate[] certs = keyStore.getCertificateChain(keyAlias);
                    if (certs == null || certs.length == 0)
                        continue;
                    X509Certificate cert = (X509Certificate) certs[0];
                    if (matchUsage(cert.getKeyUsage(), 1)) {
                        try {
                            cert.checkValidity();
                        } catch (CertificateException e) {
                            continue;
                        }
                        break;
                    }
                }
            }
            // 沒有找到可用簽名私鑰
            if (keyAlias == null)
                throw new GeneralSecurityException(
                        "None certificate for sign in this keystore");
            if (debug)
                System.out.println(keyAlias);
            if (keyStore.isKeyEntry(keyAlias)) {
                // 檢查證書鏈
                Certificate[] certs = keyStore.getCertificateChain(keyAlias);
                for (int i = 0; i < certs.length; i++) {
                    if (!(certs[i] instanceof X509Certificate))
                        throw new GeneralSecurityException("Certificate[" + i
                                + "] in chain '" + keyAlias
                                + "' is not a X509Certificate.");
                }
                // 轉換證書鏈
                certificates = new X509Certificate[certs.length];
                for (int i = 0; i < certs.length; i++)
                    certificates[i] = (X509Certificate) certs[i];
            } else if (keyStore.isCertificateEntry(keyAlias)) {
                // 只有單張證書
                Certificate cert = keyStore.getCertificate(keyAlias);
                if (cert instanceof X509Certificate) {
                    certificates = new X509Certificate[ { (X509Certificate) cert }];
                }
            } else {
                throw new GeneralSecurityException(keyAlias
                        + " is unknown to this keystore");
            }
            privateKey = (PrivateKey) keyStore.getKey(keyAlias,
                    keyStorePassword.toCharArray());
            // 沒有私鑰拋異常
            if (privateKey == null) {
                throw new GeneralSecurityException(keyAlias
                        + " could not be accessed");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 簽名
     *
     * @param data
     *            數據
     * @return signature 簽名結果
     * @throws GeneralSecurityException
     * @throws IOException
     * @throws IllegalArgumentException
     */
    public static String sign(byte[] data) throws Exception {
        X509Certificate cerx509 = certificates[0];
        List<X509Certificate> certList = new ArrayList<X509Certificate>();
        certList.add(cerx509);
        Store certs = new JcaCertStore(certList);
        ContentSigner contentSigner = new JcaContentSignerBuilder(cerx509.getSigAlgName()).setProvider("BC").build(privateKey);
        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
        gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
                new JcaDigestCalculatorProviderBuilder().setProvider("BC")
                        .build()).setDirectSignature(true).build(contentSigner, cerx509));
        gen.addCertificates(certs);
        CMSTypedData msg = new CMSProcessableByteArray(data);
        CMSSignedData sigData = gen.generate(msg, false);
        org.bouncycastle.asn1.cms.ContentInfo a = sigData.toASN1Structure();
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        try{
            DEROutputStream dOut = new DEROutputStream(bOut);
            dOut.writeObject(a);
            return  Base64.encodeBase64String(bOut.toByteArray());
        }finally{
            IOUtils.closeQuietly(bOut);
        }
    }

    /**
     * 驗證簽名(無CRL)
     *
     * @param data
     *            被簽名數據
     * @param signature
     *            簽名簽名結果
     * @throws Exception
     */
    public static boolean verify(byte[] data, byte[] signature) throws Exception {
        CMSProcessable content = new CMSProcessableByteArray(data);
        //新建PKCS#7簽名數據處理對象
        CMSSignedData s = new CMSSignedData(content, signature);
        Store certStore = s.getCertificates();
        //獲得簽名者信息
        SignerInformationStore signers = s.getSignerInfos();
        Iterator<?> it = signers.getSigners().iterator();
        int verified = 0, size = 0;
        //當有多個簽名者信息時需要全部驗證
        while (it.hasNext()) {
            size++;
            SignerInformation signer = (SignerInformation) it.next();
            //證書鏈
            Collection<?> certCollection = certStore.getMatches(signer.getSID());
            Iterator<?> certIt = certCollection.iterator();
            X509CertificateHolder cert = (X509CertificateHolder) certIt.next();
            //驗證數字簽名
            if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
                verified++;
            }
        }
        if (verified >0 && size == verified) {
            return true;
        }
        return false;
    }


    /**
     * 匹配私鑰用法
     *
     * @param keyUsage
     * @param usage
     * @return
     */
    private static boolean matchUsage(boolean[] keyUsage, int usage) {
        if (usage == 0 || keyUsage == null)
            return true;
        for (int i = 0; i < Math.min(keyUsage.length, 32); i++) {
            if ((usage & (1 << i)) != 0 && !keyUsage[i])
                return false;
        }
        return true;
    }


    private static void init() {
        if (jvm != 0)
            return;
        String vendor = System.getProperty("java.vm.vendor");
        if (vendor == null)
            vendor = "";
        String vendorUC = vendor.toUpperCase();
        try {
            if (vendorUC.indexOf("SUN") >= 0) {
                jvm = 'S';
                algorithmId = Class.forName("sun.security.x509.AlgorithmId");
                derValue = Class.forName("sun.security.util.DerValue");
                objectIdentifier = Class.forName("sun.security.util.ObjectIdentifier");
                x500Name = Class.forName("sun.security.x509.X500Name");
            } else if (vendorUC.indexOf("ORACLE CORPORATION") >= 0) {
                jvm = 'O';
                algorithmId = Class.forName("sun.security.x509.AlgorithmId");
                derValue = Class.forName("sun.security.util.DerValue");
                objectIdentifier = Class.forName("sun.security.util.ObjectIdentifier");
                x500Name = Class.forName("sun.security.x509.X500Name");
            } else if (vendorUC.indexOf("IBM") >= 0) {
                jvm = 'I';
                algorithmId = Class.forName("com.ibm.security.x509.AlgorithmId");
                derValue = Class.forName("com.ibm.security.util.DerValue");
                objectIdentifier = Class.forName("com.ibm.security.util.ObjectIdentifier");
                x500Name = Class.forName("com.ibm.security.x509.X500Name");
            } else {
                System.out.println("Not support JRE: " + vendor);
                System.exit(-1);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }

}

 



相關jar包:compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.52'


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM