自己封装的数字证书签名及签名验证方法,附带生成证书的语句

如果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历史记录中。

原文地址:https://www.cnblogs.com/jinzhiming/p/6003980.html