自己封裝的數字證書簽名及簽名驗證方法,附帶生成證書的語句


如果java環境搭建好,注釋中內容可以新建一個bat來執行,或者直接粘貼到黑屏執行,即可生成私鑰和公鑰的證書

REM # create keystore file
keytool -genkey -dname "CN=Test Bank, OU=Test, O=Test, L=BeiJing, ST=BeiJing, C=CN" -alias testAlias -keyalg RSA -keysize 1024 -keystore TestPrivate.jks -keypass 12345678 -storepass 12345678 -validity 365

REM # export cert file
keytool -export -alias testAlias -file TestPublic.cer -keystore TestPrivate.jks -storepass 12345678

package com.develop.util;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


public class SignUtil {
    /**
    
    如果java環境搭建好,注釋中內容可以新建一個bat來執行,或者直接粘貼到黑屏執行,即可生成私鑰和公鑰的證書
    
    REM # create keystore file
    keytool -genkey -dname "CN=Test Bank, OU=Test, O=Test, L=BeiJing, ST=BeiJing, C=CN" -alias testAlias -keyalg RSA -keysize 2048 -keystore TestPrivate.jks -keypass 12345678 -storepass 12345678 -validity 365
    
    REM # export cert file
    keytool -export -alias testAlias -file TestPublic.cer  -keystore TestPrivate.jks -storepass 12345678
    
    
    **/
    
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;
    
    /**
     * 簽名方法
     * @param srcByte 待簽名數據(byte)
     * @param keystorePath 密鑰庫文件路徑
     * @param keystorePwd 密鑰庫密碼
     * @param keystoreType 密鑰庫類型 無設置默認JKS
     * @param algorithm 算法 無設置默認取證書算法
     * @param alias 私鑰別名 無設置默認自動查找
     * @return
     */
    public static byte[] sign(byte[] srcByte,String keystorePath,String keystorePwd,String keystoreType,String algorithm,String alias){
        
        if(srcByte==null){
            System.out.println("待簽名數據為空!");
            return null;
        }
        
        if(keystorePath==null||"".equals(keystorePath)){
            System.out.println("密鑰庫路徑為空!");
            return null;
        }
        
        if(keystorePwd==null){
            System.out.println("密鑰庫密碼為空!");
            return null;
        }
        
        KeyStore keyStore = getKeyStore(keystorePath, keystorePwd, keystoreType);
        
        if(keyStore==null){
            System.out.println("獲取密鑰庫對象失敗!");
            return null;
        }
        
        if(alias==null||"".equals(alias)){
            alias = getAlias(keyStore);
        }
        
        PrivateKey privateKey = getPrivateKey(keyStore, keystorePwd, alias);
        
        if(privateKey==null){
            System.out.println("獲取私鑰對象失敗!");
            return null;
        }
        
        X509Certificate x509Certificate = getX509Certificate(keyStore, alias);
        
        if(algorithm==null||"".equals(algorithm)){
            algorithm = x509Certificate.getSigAlgName();
        }
        
        return doSign(srcByte, privateKey, algorithm);
    }
    
    /**
     * 簽名方法
     * @param srcData 待簽名數據(String)
     * @param keystorePath 密鑰庫文件路徑
     * @param keystorePwd 密鑰庫密碼
     * @param keystoreType 密鑰庫類型 無設置默認JKS
     * @param algorithm 簽名算法 無設置默認取證書算法
     * @return
     */
    public static String sign(String srcData,String keystorePath,String keystorePwd,String keystoreType,String algorithm){
        
        String signedData = "";
        
        System.out.println("待簽名參數:"+srcData);
        
        if(srcData==null||"".equals(srcData)){
            System.out.println("待簽名數據為空!");
            return "";
        }
        
        byte[] srcByte = srcData.getBytes();//待簽名數據String轉成byte
        
        byte[] rsByte = sign(srcByte, keystorePath, keystorePwd, keystoreType, algorithm, null);
        
        if(rsByte==null){
            System.out.println("簽名失敗!");
            return "";
        }
        
        signedData = new BASE64Encoder().encodeBuffer(rsByte);
        
        System.out.println("簽名串:"+signedData);
        
        return signedData;
    }
    
    /**
     * 驗簽方法
     * @param srcByte 待簽名數據(byte)
     * @param signedByte 簽名串(byte)
     * @param certificatePath 證書文件路徑
     * @param algorithm 驗簽算法 無設置默認取證書算法
     * @return
     */
    public static boolean verify(byte[] srcByte,byte[] signedByte,String certificatePath,String algorithm){
        
        if(srcByte==null){
            System.out.println("傳入的原數據參數為空!");
            return false;
        }
        
        if(signedByte==null){
            System.out.println("傳入的簽名串參數為空!");
            return false;
        }
        
        if(certificatePath==null||"".equals(certificatePath)){
            System.out.println("公鑰證書路徑參數為空!");
            return false;
        }
        
        X509Certificate x509Certificate = getX509Certificate(certificatePath);
        
        if(x509Certificate==null){
            System.out.println("獲取X509證書對象失敗!");
            return false;
        }
        
        PublicKey publicKey = getPublicKey(x509Certificate);
        
        if(publicKey==null){
            System.out.println("公鑰對象獲取失敗!");
            return false;
        }
        
        if(algorithm==null||"".equals(algorithm)){
            algorithm = x509Certificate.getSigAlgName();
        }
        
        return doVerify(srcByte, signedByte, publicKey, algorithm);
    }
    
    /**
     * 驗簽方法
     * @param srcData 待簽名數據(String)
     * @param signedData 簽名串(String)
     * @param certificatePath 證書文件路徑
     * @param algorithm 驗簽算法 無設置默認取證書算法
     * @return
     */
    public static boolean verify(String srcData,String signedData,String certificatePath,String algorithm){
        
        boolean result = false;
        
        System.out.println("驗簽參數(待簽名數據):"+srcData);
        System.out.println("驗簽參數(簽名串):"+signedData);
        
        if(srcData==null||"".equals(srcData)){
            System.out.println("傳入待簽名數據為空!");
            return false;
        }
        
        if(signedData==null||"".equals(signedData)){
            System.out.println("傳入簽名串為空!");
            return false;
        }
        
        byte[] srcByte = srcData.getBytes();
        byte[] signedByte = null;
        try {
            signedByte = new BASE64Decoder().decodeBuffer(signedData);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        result = verify(srcByte, signedByte, certificatePath, algorithm);
        
        System.out.println("驗簽結果:"+result);
        
        return result;
    }
    
    /**
     * 創建簽名對象進行簽名
     * @param srcByte 待簽名數據(byte)
     * @param privateKey 私鑰
     * @param algorithm 簽名算法 無設置默認取證書算法
     * @return
     */
    private static byte[] doSign(byte[] srcByte,PrivateKey privateKey,String algorithm){
        
        System.out.println("簽名算法:"+algorithm);
        
        try {
            
            Signature signature=Signature.getInstance(algorithm);
            signature.initSign(privateKey);
            signature.update(srcByte);
            return signature.sign();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        }

        return null;
    }
    
    /**
     * 創建簽名對象進行驗簽
     * @param srcByte 原待簽名數據(byte)
     * @param signedByte 簽名串(byte)
     * @param publicKey 公鑰
     * @param algorithm 驗簽算法 無設置默認取證書算法
     * @return
     */
    private static boolean doVerify(byte[] srcByte,byte[] signedByte,PublicKey publicKey,String algorithm){
        
        System.out.println("驗簽算法:"+algorithm);
        
        try {
            
            Signature signature=Signature.getInstance(algorithm);
            signature.initVerify(publicKey);
            signature.update(srcByte);
            return signature.verify(signedByte);
            
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        }

        return false;
    }
    
    /**
     * 找到路徑下的密鑰庫文件,獲取密鑰庫對象
     * @param keystorePath 密鑰庫文件路徑
     * @param keystorePwd 密鑰庫密碼
     * @param keystoreType 密鑰庫類型 無設置默認JKS
     * @return
     */
    private static KeyStore getKeyStore(String keystorePath,String keystorePwd,String keystoreType){
        
        System.out.println("密鑰庫文件路徑:"+keystorePath);
        
        if(keystoreType==null||"".equals(keystoreType)){
            keystoreType = KeyStore.getDefaultType();
        }
        
        System.out.println("創建密鑰庫對象使用的密鑰庫類型:"+keystoreType);
        
        FileInputStream stream = null;
        KeyStore keyStore = null;
        try {
            stream = new FileInputStream(keystorePath);
            keyStore = KeyStore.getInstance(keystoreType);
            keyStore.load(stream, keystorePwd.toCharArray());
            
            System.out.println("讀取文件密鑰庫對象成功!");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(stream!=null){
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                stream = null;
            }
        }
        
        return keyStore;
    }
    
    /**
     * 查找密鑰庫中私鑰別名,找到名稱就停止查找
     * @param keyStore 密鑰庫
     * @return
     */
    private static String getAlias(KeyStore keyStore){
        String alias = null;
        try {
            Enumeration<String> aliases = keyStore.aliases();
            while(aliases.hasMoreElements()){
                String element = aliases.nextElement();
                if(keyStore.isKeyEntry(element)){
                    alias = element;
                    break;
                }
            }
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        
        return alias;
    }
    
    /**
     * 獲取密鑰庫中的私鑰
     * @param keyStore 密鑰庫對象
     * @param keystorePwd 密鑰庫密碼
     * @param alias 私鑰的別名
     * @return
     */
    private static PrivateKey getPrivateKey(KeyStore keyStore,String keystorePwd,String alias){
        
        System.out.println("私鑰別名:"+alias);
        
        try {
            return (PrivateKey)keyStore.getKey(alias, keystorePwd.toCharArray());
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
    /**
     * 找到路徑下的證書文件,獲取證書對象
     * @param certificatePath 證書文件路徑
     * @return
     */
    private static X509Certificate getX509Certificate(String certificatePath){
        
        System.out.println("證書文件路徑:"+certificatePath);
        
        FileInputStream stream = null;
        X509Certificate x509Certificate = null;
        try {
            stream = new FileInputStream(certificatePath);
            CertificateFactory certificateFactory = CertificateFactory.getInstance("x.509");//1.6版本只支持x.509標准證書
            x509Certificate = (X509Certificate)certificateFactory.generateCertificate(stream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } finally{
            if(stream!=null){
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                stream = null;
            }
        }
        
        return x509Certificate;
    }
    
    /**
     * 獲取證書的公鑰
     * @param x509Certificate 證書對象
     * @return
     */
    private static PublicKey getPublicKey(X509Certificate x509Certificate){
        return x509Certificate.getPublicKey();
    }
    
    /**
     * 通過密鑰庫獲取證書對象
     * @param keyStore 密鑰庫
     * @param alias 私鑰別名
     * @return
     */
    private static X509Certificate getX509Certificate(KeyStore keyStore,String alias){
        try {
            return (X509Certificate)keyStore.getCertificate(alias);
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
    
    /**
     * 明文加密
     * @param plainText 明文
     * @param key 公鑰或私鑰
     * @return
     */
    public static byte[] encrypt(byte[] plainText, Key key){
        
        System.out.println("加密方法encrypt開始!");
        
        ByteArrayOutputStream out = null;
        try {
            Cipher cipher = Cipher.getInstance(key.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, key);
            
            int inputLen = plainText.length;
            out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 對數據分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(plainText, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = out.toByteArray();
            
            return encryptedData;

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } finally{
            if(out!=null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                out = null;
            }
            System.out.println("加密方法encrypt結束!");
        }
        
        return null;
    }
    
    /**
     * 密文解密
     * @param ciphertext 密文
     * @param key 公鑰或私鑰
     * @return
     */
    public static byte[] decrypt(byte[] ciphertext, Key key){
        
        System.out.println("解密方法decrypt開始!");
        
        ByteArrayOutputStream out = null;
        try {
            Cipher cipher = Cipher.getInstance(key.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, key);
            
            int inputLen = ciphertext.length;
            out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 對數據分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(ciphertext, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(ciphertext, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            
            return decryptedData;

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } finally{
            if(out!=null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                out = null;
            }
            System.out.println("解密方法decrypt結束!");
        }
        
        return null;
    }
    
    
    public static void main(String[] args) {
        String srcData = "test測試數據";
        
        //簽名驗簽測試
        String rsData = sign(srcData, "D:\\test\\TestPrivate.jks", "12345678" , null, null);
        boolean result = verify(srcData, rsData, "D:\\test\\TestPublic.cer", null);

        
        //加密解密測試
        KeyPairGenerator keyPairGenerator = null;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        keyPairGenerator.initialize(1024);
        KeyPair key = keyPairGenerator.genKeyPair();
        PrivateKey privateKey = key.getPrivate();
        PublicKey publicKey = key.getPublic();
        
        byte[] a = encrypt(srcData.getBytes(), privateKey);
        
        byte[] b = decrypt(a, publicKey);
        
        System.out.println(new String(b));
        
    }
    
}

 

 

keytool:

 

Keytool 選項 描述
-genkey 產生一個鍵值對(公鑰和私鑰)
-v 允許動作輸出
-alias<alias_name> 鍵的別名。只有前八位字符有效。
-keyalg 產生鍵的加密算法。支持DSA和RSA。
-keysize 產生鍵的長度。如果不支持,keytool用默認值1024 bits.通常我們用2048 bits 或更長的key。
-dname

專有名稱,描述誰創建的密鑰。該值被用作自簽名證書的頒發者和主題字段。注意你可以不在命令行指定。如果沒有指定keytool會提示你(CN, OU, and so on)。

-keypass

鍵的密碼。

主要為了安全起見,如果沒提供,keytool會提示你輸入。

-validity

鍵的有效期,單位:天

Note: A value of 10000 or greater is recommended.

-keystore.keystore 用於存儲私鑰的文件。
-storepass

私鑰存儲文件的密碼。

主要為了安全起見,如果沒提供,keytool會提示你輸入。這個密碼不會存儲在你的shell歷史記錄中。

 


免責聲明!

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



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