java实现RSA非对称加密解密

之前写过一篇java实现AES对称加密解密
在对密码加密传输的场景下 RSA非对称加密解密可能会更加适合。
原理就是后台生成一对公钥和私钥,公钥给前端用来加密,后台用私钥去解密,保证了传输过程中就算被截获也避免密码泄露。
下面是代码:

package com.zhaohy.app.utils;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class RSAUtil {
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;
    
    /**
     * 获取密钥对
     * 
     * @return 密钥对
     */
    public static KeyPair getKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(1024);
        return generator.generateKeyPair();
    }
    
    /**
     * 获取私钥
     * 
     * @param privateKey 私钥字符串
     * @return
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        return keyFactory.generatePrivate(keySpec);
    }
    
    /**
     * 获取公钥
     * 
     * @param publicKey 公钥字符串
     * @return
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        return keyFactory.generatePublic(keySpec);
    }
    
    /**
     * RSA加密
     * 
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return
     */
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
        // 加密后的字符串
        return new String(Base64.encodeBase64String(encryptedData));
    }
    
    /**
     * RSA解密
     * 
     * @param data       待解密数据
     * @param privateKey 私钥
     * @return
     */
    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] dataBytes = Base64.decodeBase64(data);
        int inputLen = dataBytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        // 解密后的内容
        return new String(decryptedData, "UTF-8");
    }
    /**
     * 签名
     * 
     * @param data       待签名数据
     * @param privateKey 私钥
     * @return 签名
     */
    public static String sign(String data, PrivateKey privateKey) throws Exception {
        byte[] keyBytes = privateKey.getEncoded();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey key = keyFactory.generatePrivate(keySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initSign(key);
        signature.update(data.getBytes());
        return new String(Base64.encodeBase64(signature.sign()));
    }
    
    /**
     * 验签
     * 
     * @param srcData   原始字符串
     * @param publicKey 公钥
     * @param sign      签名
     * @return 是否验签通过
     */
    public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
        byte[] keyBytes = publicKey.getEncoded();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(key);
        signature.update(srcData.getBytes());
        return signature.verify(Base64.decodeBase64(sign.getBytes()));
    }
    
    /**
     * 文件解密
     * 
     * @param publicKeyStr
     * @param srcFileName
     * @param destFileName
     */
    public static void decryptFileBig(String publicKeyStr, String srcFileName, String destFileName) {
        Cipher cipher = null;
        InputStream is = null;
        OutputStream out = null;
        try {
            X509EncodedKeySpec encodedKey = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            PublicKey pubKey = keyf.generatePublic(encodedKey);
            cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
            cipher.init(Cipher.DECRYPT_MODE, pubKey);
            File f = new File(srcFileName);
            is = new FileInputStream(f);
            out = new FileOutputStream(destFileName);
            int blockSize = cipher.getBlockSize();
            int size = Integer.valueOf(String.valueOf(f.length()));
            byte[] decryptByte = new byte[size];
            is.read(decryptByte);
            //分别对各块数据进行解密
            int j = 0;
            while ((decryptByte.length - j * blockSize) > 0) {
                out.write(cipher.doFinal(decryptByte, j * blockSize, blockSize));
                j++;
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 加密大文件
     * @param privateKeyStr
     * @param srcFileName
     * @param destFileName
     */
    public static void encryptFileBig(String privateKeyStr, String srcFileName, String destFileName) {
        if (privateKeyStr == null) {
            new Exception("加密私钥为空, 请设置");
        }
        Cipher cipher = null;
        InputStream is = null;
        OutputStream out = null;
        CipherInputStream cis = null;
        try {
            // 使用默认RSA  
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
                Base64.decodeBase64(privateKeyStr));
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            PrivateKey priKey = keyf.generatePrivate(priPKCS8);
            cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
            cipher.init(Cipher.ENCRYPT_MODE, priKey);
            int blockSize = cipher.getBlockSize();
            is = new FileInputStream(srcFileName);
            File f = new File(srcFileName);
            int size = Integer.valueOf(String.valueOf(f.length()));
            byte[] encryptByte = new byte[size];
            is.read(encryptByte);
            out = new FileOutputStream(destFileName);
            int outputBlockSize = cipher.getOutputSize(encryptByte.length);
            int leavedSize = encryptByte.length % blockSize;
            int blocksNum = leavedSize == 0 ? encryptByte.length / blockSize : encryptByte.length / blockSize + 1;
            byte[] cipherData = new byte[blocksNum * outputBlockSize];
            for (int i = 0; i < blocksNum; i++) {
                if ((encryptByte.length - i * blockSize) > blockSize) {
                    cipher.doFinal(encryptByte, i * blockSize, blockSize, cipherData,i * outputBlockSize);
                } else {
                    cipher.doFinal(encryptByte, i * blockSize, encryptByte.length - i * blockSize,cipherData, i * outputBlockSize);
                }
            }
            out.write(cipherData);
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (null != cis) {
                try {
                    cis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * RSA文件签名
     * 
     * @param filePath
     * @param privateKey
     * @param encode
     * @return
     */
    public static String signFile(String filePath, String privateKey, String encode) {
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader bfr = null;
        try {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            PrivateKey priKey = keyf.generatePrivate(priPKCS8);
            java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");
            signature.initSign(priKey);
            fis = new FileInputStream(new File(filePath));
            isr = new InputStreamReader(fis, encode);
            bfr = new BufferedReader(isr);
            String lineTxt = "";
            while (!AppFrameworkUtil.isBlank(lineTxt = bfr.readLine())) {
                signature.update(lineTxt.getBytes(encode));
            }
            byte[] signed = signature.sign();
            String ret = new String(Base64.encodeBase64(signed));
            System.out.println("signed:" + ret);
            return ret;
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (bfr != null) {
                try {
                    bfr.close();
                } catch (IOException e) {
                }
            }
            if (isr != null) {
                try {
                    isr.close();
                } catch (IOException e) {
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }
    
    /** 
     * RSA文件验签名检查 
     * @param content 待签名数据 
     * @param sign 签名值 
     * @param publicKey 分配给开发商公钥 
     * @param encode 字符集编码 
     * @return 布尔值 
     */
    public static boolean doCheckFile(String filePath, String sign, String publicKey, String encode) {
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader bfr = null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = Base64.decodeBase64(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");
            signature.initVerify(pubKey);
            fis = new FileInputStream(new File(filePath));
            isr = new InputStreamReader(fis, "UTF-8");
            bfr = new BufferedReader(isr);
            String lineTxt = "";
            while (!AppFrameworkUtil.isBlank(lineTxt = bfr.readLine())) {
                signature.update(lineTxt.getBytes(encode));
            }
            boolean bverify = signature.verify(Base64.decodeBase64(sign));
            return bverify;
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (bfr != null) {
                try {
                    bfr.close();
                } catch (IOException e) {
                }
            }
            if (isr != null) {
                try {
                    isr.close();
                } catch (IOException e) {
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                }
            }
        }
        return false;
    }
    
    public static void main(String[] args) {
        try {
            // 生成密钥对
            KeyPair keyPair = getKeyPair();
            String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
            String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));
            
            System.out.println("私钥:" + privateKey);
            System.out.println("公钥:" + publicKey);
            // RSA加密
            String data = "123秘密啊";
            String encryptData = encrypt(data, getPublicKey(publicKey));
            System.out.println("加密后内容:" + encryptData);
            // RSA解密
            String decryptData = decrypt(encryptData, getPrivateKey(privateKey));
            System.out.println("解密后内容:" + decryptData);
            
            // RSA签名
            String sign = sign(data, getPrivateKey(privateKey));
            System.out.println("sign==" + sign);
            // RSA验签
            boolean result = verify(data, getPublicKey(publicKey), sign);
            System.out.println("验签结果:" + result);
            
            /****大文件加签验签****/
            //加签验签
            String fileSign = signFile("/home/zhaohy/Documents/test.doc", privateKey, "UTF-8");
            System.out.println("fileSign==" + fileSign);
           boolean checkFileBoolean = doCheckFile("/home/zhaohy/Documents/test.doc", fileSign, publicKey, "UTF-8");
           System.out.println("大文件校验签名结果:" + checkFileBoolean);
            //加密解密
            encryptFileBig(privateKey, "/home/zhaohy/Documents/test.txt", "/home/zhaohy/Documents/test.dat");
            decryptFileBig(publicKey, "/home/zhaohy/Documents/test.dat", "/home/zhaohy/Documents/test1.txt");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.print("加解密异常");
        }
    }
}

运行结果:

私钥:MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALpLjdbsu172ftiv3eUC/JghSSzNRlp8p9Ilr8XlK/gl3gaPFFo1BAHWWyb9MhoTdE5BvES6E/eW5gVKby8olLa6ILbh9UYif0SKWca7pTt2nqn2Cd8v29/94ZF9i+yMoime3wuS7QxJEHG7qCqps7KVNtP/4/628lq1jB6B3DrPAgMBAAECgYBUtCGrxTt0dBM8psn3ZKJA8XF6A2OnpOIRNL109zxEucL3rHqOgWhvBW2wjpMHNC0/n7fgb9LAUkYHxc5D3OmwXAhvgRzDmMTeoaikrLeJpxX9NQ4TU3CFcL9YabQ+rjB6yMgfbmmA0B/odxpzIZd6ypHq91ogI/rfP4McaX7NwQJBAO9Qm4SoOn/0SzfOE+PjnIyLkDqW2kFRJv+c/4Z0H/yPOIjytHhe6hQQ8KHT2azOP+SeAWbjb152a5Rp/E8da/8CQQDHSKDBSGZuN/Qyk1eGJ80T9+GSQI0oYQfZcHYNUkAKrWceHISL5jMrUXWHSlKjFC5E7RsqQKMn72xisrlLcXExAkEA7YAB11VdOT8opulNtAxfgNvA92RelhQDsAoPTVBRrkQ0xzSXBh6sD93/8ZpdnLHTlv94RLPSAt1jRpcoXxvD4QJBALtv00uYVkdqt3NuZE8ZVmlmp7KQpnQJN4HLpi2HZBbm2+tVdVHEVfJzbrCuNiWO0KohvYAzRYJFTlNSuLd93rECQDcgPHh0qBOW22ggxiqpfbLIURvPAT9urp8NuTM0K0rW3mC2me55yPSDQ7jL1t9vwYkfahc0GUl1V1Cq/449AHU=
公钥:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6S43W7Lte9n7Yr93lAvyYIUkszUZafKfSJa/F5Sv4Jd4GjxRaNQQB1lsm/TIaE3ROQbxEuhP3luYFSm8vKJS2uiC24fVGIn9EilnGu6U7dp6p9gnfL9vf/eGRfYvsjKIpnt8Lku0MSRBxu6gqqbOylTbT/+P+tvJatYwegdw6zwIDAQAB
加密后内容:R7GqGE2r51PmJAt3wtKhsbqfFzeobvzqFlAp8Tv0+3HkevsUF2a+/ZO7Sn53cKGwXIkOkDQN0S/pk/Eacd8Wk1wXKTKx57eSaQJFv/HQ5nDUfvtMWIg0IcHNmHyNBfDPVe/MiMkKf23/a/EyEfCQEzsCQyHLyHoTg34a1SNXTLs=
解密后内容:123秘密啊
sign==p8JR0aserak6iPltfAJx/mlvlp5Ox5NcpvRo7R1rxDItekMhyF82RVizgMqsmEBpWzW9Qkxm6AWzjzEr+XhR7u4KhxEO7euTHC9NGJ0TAtDKqtAsfFaZi8ZyY4MkHnSCFZVMcWMR3GhZ8ALJGe/lSstNSEp8H9lQE8u2o2oYiiw=
验签结果:true
signed:aavuNSCwaT2jZ6XrlAbSJNLBDalkWZ1t0tnQnveUw+3exlpcvRu0xotAlrW0V4voLLeRydLgIjwCwq1YxqFyKcYlOuORzorlmihjSXBZf0GZoJIlTIaUZ8/TJV+CRFObFnnEQ+8QAbRs4b7AB6nv1A2bxMeKulS0OTPxSkSFTdM=
fileSign==aavuNSCwaT2jZ6XrlAbSJNLBDalkWZ1t0tnQnveUw+3exlpcvRu0xotAlrW0V4voLLeRydLgIjwCwq1YxqFyKcYlOuORzorlmihjSXBZf0GZoJIlTIaUZ8/TJV+CRFObFnnEQ+8QAbRs4b7AB6nv1A2bxMeKulS0OTPxSkSFTdM=
大文件校验签名结果:true

可以看到加密解密成功,里面最后加密解密文件自测只对txt或html等文本文件有效,doc或者excel加密文件后解密出来的东西乱码。

参考:https://www.cnblogs.com/pcheng/p/9629621.html

====2021年5月28日更新====
以上分段加密解密时针对1024长度的密文有效2048长度的密文就会报错,所以更新以下工具类,兼容2048而且还有针对pem格式的秘钥处理。

package ly.mp.project.common.otautils;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

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

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;


public class RSAUtils {
    /**
     * 秘钥对算法名称
     */
    private static final String ALGORITHM = "RSA";

    private static final String SIGN_SHA1RSA_ALGORITHMS = "SHA1WithRSA";

    private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK_1024 = 117;
    private static final int MAX_ENCRYPT_BLOCK_2048 = 245;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK_1024 = 128;
    private static final int MAX_DECRYPT_BLOCK_2048 = 256;

    /**
     * RSA2048公私钥长度
     */
    private static final int PUBLIC_KEY_LEN_2048 = 392;
    private static final int PRIVATE_KEY_LEN_2048 = 1264;

    static {
        java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    /**
     * SHA1WithRSA算法签名
     */
    public static String SHA1WithRSASign(String content, String privateKey, String charset) throws Exception {
        return signHandle(content, privateKey, charset, SIGN_SHA1RSA_ALGORITHMS);
    }
    
    /**
     * SHA1WithRSA算法签名
     */
    public static String SHA1WithRSASign(byte[] contentByte, String privateKey) throws Exception {
        return signHandle(contentByte, privateKey, SIGN_SHA1RSA_ALGORITHMS);
    }
    
    /**
     * SHA1WithRSAPemKey算法签名
     */
    public static String SHA1WithRSAPemKeySign(byte[] contentByte, String privateKey) throws Exception {
        return signPemKeyHandle(contentByte, privateKey, SIGN_SHA1RSA_ALGORITHMS);
    }

    /**
     * SHA256WithRSA 算法签名
     */
    public static String SHA256WithRSASign(String content, String privateKey, String charset) throws Exception {
        return signHandle(content, privateKey, charset, SIGN_SHA256RSA_ALGORITHMS);
    }
    
    /**
     * SHA256WithRSA 算法签名
     */
    public static String SHA256WithRSASign(byte[] contentByte, String privateKey) throws Exception {
        return signHandle(contentByte, privateKey, SIGN_SHA256RSA_ALGORITHMS);
    }
    
    /**
     * SHA256WithRSAPemKey 算法签名
     */
    public static String SHA256WithRSAPemKeySign(byte[] contentByte, String privateKey) throws Exception {
        return signPemKeyHandle(contentByte, privateKey, SIGN_SHA256RSA_ALGORITHMS);
    }

    /**
     * SHA1WithRSA算法验签
     */
    public static boolean SHA1WithRSAVerify(String content, String publicKey, String signInfo, String charset) throws Exception {
        return verifyHandle(content, publicKey, signInfo, charset, SIGN_SHA1RSA_ALGORITHMS);
    }
    
    /**
     * SHA1WithRSA算法验签
     */
    public static boolean SHA1WithRSAVerify(byte[] contentByte, String publicKey, String signInfo) throws Exception {
        return verifyHandle(contentByte, publicKey, signInfo, SIGN_SHA1RSA_ALGORITHMS);
    }
    
    /**
     * SHA1WithRSA算法验签
     */
    public static boolean SHA1WithRSAPemKeyVerify(byte[] contentByte, String publicKey, String signInfo) throws Exception {
        return verifyPemKeyHandle(contentByte, publicKey, signInfo, SIGN_SHA1RSA_ALGORITHMS);
    }

    /**
     * SHA256WithRSA算法验签
     */
    public static boolean SHA256WithRSAVerify(String content, String publicKey, String signInfo, String charset) throws Exception {
        return verifyHandle(content, publicKey, signInfo, charset, SIGN_SHA256RSA_ALGORITHMS);
    }
    
    /**
     * SHA256WithRSA算法验签
     */
    public static boolean SHA256WithRSAVerify(byte[] contentByte, String publicKey, String signInfo) throws Exception {
        return verifyHandle(contentByte, publicKey, signInfo, SIGN_SHA256RSA_ALGORITHMS);
    }
    
    /**
     * SHA256WithRSA算法验签
     */
    public static boolean SHA256WithRSAPemKeyVerify(byte[] contentByte, String publicKey, String signInfo) throws Exception {
        return verifyPemKeyHandle(contentByte, publicKey, signInfo, SIGN_SHA256RSA_ALGORITHMS);
    }

    /**
     * 签名处理
     */
    public static String signHandle(String content, String privateKey, String charset, String algorithm) throws Exception {
        Signature signature = Signature.getInstance(algorithm);
        signature.initSign(getPrivateKey(privateKey));
        if (charset == null || charset.length() == 0) {
            signature.update(content.getBytes());
        } else {
            signature.update(content.getBytes(charset));
        }
        byte[] signed = signature.sign();
        return new String(Base64.encodeBase64(signed));
    }
    
    /**
     * 签名处理
     */
    public static String signHandle(byte[] contentByte, String privateKey, String algorithm) throws Exception {
        Signature signature = Signature.getInstance(algorithm);
        signature.initSign(getPrivateKey(privateKey));
        signature.update(contentByte);
        byte[] signed = signature.sign();
        return new String(Base64.encodeBase64(signed));
    }
    
    /**
     * pemStrKey签名处理
     */
    public static String signPemKeyHandle(byte[] contentByte, String privateKey, String algorithm) throws Exception {
        Signature signature = Signature.getInstance(algorithm);
        signature.initSign(privateKey(privateKey));
        signature.update(contentByte);
        byte[] signed = signature.sign();
        return new String(Base64.encodeBase64(signed));
    }

    /**
     * 验签处理
     */
    public static boolean verifyHandle(String content, String publicKey, String signInfo, String charset, String algorithm) throws Exception {
        Signature signature = Signature.getInstance(algorithm);
        signature.initVerify(getPublicKey(publicKey));
        if (charset == null || charset.length() == 0) {
            signature.update(content.getBytes());
        } else {
            signature.update(content.getBytes(charset));
        }
        return signature.verify(Base64.decodeBase64(signInfo));
    }
    
    /**
     * 验签处理
     */
    public static boolean verifyHandle(byte[] contentByte, String publicKey, String signInfo, String algorithm) throws Exception {
        Signature signature = Signature.getInstance(algorithm);
        signature.initVerify(getPublicKey(publicKey));
        signature.update(contentByte);
        return signature.verify(Base64.decodeBase64(signInfo));
    }
    
    /**
     * 验签处理
     */
    public static boolean verifyPemKeyHandle(byte[] contentByte, String publicKey, String signInfo, String algorithm) throws Exception {
        Signature signature = Signature.getInstance(algorithm);
        signature.initVerify(publicKey(publicKey));
        signature.update(contentByte);
        return signature.verify(Base64.decodeBase64(signInfo));
    }

    /**
     * 公钥解密
     */
    public static String decryptByPublicKey(String publicKey, String cipherText, String charset) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, getPublicKey(publicKey));
        byte[] cipherBytes = Base64.decodeBase64(cipherText);
        int MAX_DECRYPT_BLOCK = publicKey.length() < PUBLIC_KEY_LEN_2048 ? MAX_DECRYPT_BLOCK_1024 : MAX_DECRYPT_BLOCK_2048;
        byte[] decryptedData = sectionHandle(cipherBytes, cipher, MAX_DECRYPT_BLOCK);
        return new String(decryptedData, charset);
    }
    
    public static String decryptByPemPublicKey(String pemPublicKey, String cipherText, String charset) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, publicKey(pemPublicKey));
        byte[] cipherBytes = Base64.decodeBase64(cipherText);
        int MAX_DECRYPT_BLOCK = pemPublicKey.length() < PUBLIC_KEY_LEN_2048 ? MAX_DECRYPT_BLOCK_1024 : MAX_DECRYPT_BLOCK_2048;
        byte[] decryptedData = sectionHandle(cipherBytes, cipher, MAX_DECRYPT_BLOCK);
        return new String(decryptedData, charset);
    }

    /**
     * 私钥加密
     */
    public static String encryptByPrivateKey(String privateKey, String content, String charset) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey(privateKey));
        int MAX_ENCRYPT_BLOCK = privateKey.length() < PRIVATE_KEY_LEN_2048 ? MAX_ENCRYPT_BLOCK_1024 : MAX_ENCRYPT_BLOCK_2048;
        byte[] encryptedData = sectionHandle(content.getBytes(charset), cipher, MAX_ENCRYPT_BLOCK);
        return Base64.encodeBase64String(encryptedData);
    }
    
    /**
     * pem格式私钥加密
     * @param pemPrivateKey
     * @param contentByte
     * @return
     * @throws Exception
     */
    public static String encryptByPemPrivateKey(String pemPrivateKey, byte[] contentByte) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, privateKey(pemPrivateKey));
        int MAX_ENCRYPT_BLOCK = pemPrivateKey.length() < PRIVATE_KEY_LEN_2048 ? MAX_ENCRYPT_BLOCK_1024 : MAX_ENCRYPT_BLOCK_2048;
        byte[] encryptedData = sectionHandle(contentByte, cipher, MAX_ENCRYPT_BLOCK);
        return Base64.encodeBase64String(encryptedData);
    }
    
    /**
     * 私钥加密 
     * @param privateKey
     * @param contentByte
     * @return
     * @throws Exception
     */
    public static String encryptByPrivateKey(String privateKey, byte[] contentByte) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey(privateKey));
        int MAX_ENCRYPT_BLOCK = privateKey.length() < PRIVATE_KEY_LEN_2048 ? MAX_ENCRYPT_BLOCK_1024 : MAX_ENCRYPT_BLOCK_2048;
        byte[] encryptedData = sectionHandle(contentByte, cipher, MAX_ENCRYPT_BLOCK);
        return Base64.encodeBase64String(encryptedData);
    }

    /**
     * 私钥解密
     */
    public static String decryptByPrivateKey(String privateKey, String cipherText, String charset) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKey));
        byte[] cipherBytes = Base64.decodeBase64(cipherText);
        int MAX_DECRYPT_BLOCK = privateKey.length() < PRIVATE_KEY_LEN_2048 ? MAX_DECRYPT_BLOCK_1024 : MAX_DECRYPT_BLOCK_2048;
        byte[] decryptedData = sectionHandle(cipherBytes, cipher, MAX_DECRYPT_BLOCK);
        return new String(decryptedData, charset);
    }
    
    /**
     * pem格式私钥解密
     * @param pemPrivateKey
     * @param cipherText
     * @param charset
     * @return
     * @throws Exception
     */
    public static String decryptByPemPrivateKey(String pemPrivateKey, String cipherText, String charset) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey(pemPrivateKey));
        byte[] cipherBytes = Base64.decodeBase64(cipherText);
        int MAX_DECRYPT_BLOCK = pemPrivateKey.length() < PRIVATE_KEY_LEN_2048 ? MAX_DECRYPT_BLOCK_1024 : MAX_DECRYPT_BLOCK_2048;
        byte[] decryptedData = sectionHandle(cipherBytes, cipher, MAX_DECRYPT_BLOCK);
        return new String(decryptedData, charset);
    }
    
    /**
     * 公钥加密
     */
    public static String encryptByPublicKey(String publicKey, String content, String charset) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));
        int MAX_ENCRYPT_BLOCK = publicKey.length() < PUBLIC_KEY_LEN_2048 ? MAX_ENCRYPT_BLOCK_1024 : MAX_ENCRYPT_BLOCK_2048;
        byte[] encryptedData = sectionHandle(content.getBytes(charset), cipher, MAX_ENCRYPT_BLOCK);
        return Base64.encodeBase64String(encryptedData);
    }
    
    /**
     * 公钥加密
     * @param publicKey
     * @param contentByte
     * @return
     * @throws Exception
     */
    public static String encryptByPublicKey(String publicKey, byte[] contentByte) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));
        int MAX_ENCRYPT_BLOCK = publicKey.length() < PUBLIC_KEY_LEN_2048 ? MAX_ENCRYPT_BLOCK_1024 : MAX_ENCRYPT_BLOCK_2048;
        byte[] encryptedData = sectionHandle(contentByte, cipher, MAX_ENCRYPT_BLOCK);
        return Base64.encodeBase64String(encryptedData);
    }
    
    /**
     * pem格式公钥加密
     * @param pemPublicKey
     * @param contentByte
     * @return
     * @throws Exception
     */
    public static String encryptByPemPublicKey(String pemPublicKey, byte[] contentByte) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey(pemPublicKey));
        int MAX_ENCRYPT_BLOCK = pemPublicKey.length() < PUBLIC_KEY_LEN_2048 ? MAX_ENCRYPT_BLOCK_1024 : MAX_ENCRYPT_BLOCK_2048;
        byte[] encryptedData = sectionHandle(contentByte, cipher, MAX_ENCRYPT_BLOCK);
        return Base64.encodeBase64String(encryptedData);
    }

    /**
     * 构建RSA密钥对
     */
    public static RSAKeyPair generateKeyPair(int keySize) throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
        keyPairGenerator.initialize(keySize);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
        String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        RSAKeyPair rsaKeyPair = new RSAKeyPair(publicKeyString, privateKeyString);
        return rsaKeyPair;
    }

    /**
     * 从公私钥文件中获取公私钥字符, 如:rsa_public_key.pem,rsa_private_key.pem
     */
    public static String loadPubOrPriKeyByFile(String keyFilePath) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new FileReader(keyFilePath));
            String readLine;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                if (readLine.charAt(0) == '-') {
                    continue;
                } else {
                    sb.append(readLine);
                }
            }
            br.close();
            return sb.toString();
        } catch (IOException e) {
            throw new Exception("公钥数据流读取错误");
        } catch (NullPointerException e) {
            throw new Exception("公钥输入流为空");
        }
    }

    /**
     * 从证书中获取公钥
     */
    public static String loadPublicKeyByCert(String certPath) throws Exception {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(certPath);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
            PublicKey publicKey = cert.getPublicKey();
            return Base64.encodeBase64String(publicKey.getEncoded());
        } catch (Exception e) {
            throw new Exception("读取秘钥证书异常" + e.getMessage());
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    /**
     * 私钥转换
     * 用来加密的RSA私钥的格式是PKCS1格式的(适用于非java),并不是PKCS8格式的(适用于java),把PKCS1格式转为PKCS8格式
     */
    private static PrivateKey getPrivateKey(String privateKeyText) throws NoSuchAlgorithmException, InvalidKeySpecException {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        return keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
    }
    

    /**
     * 公钥转换
     */
    private static PublicKey getPublicKey(String publicKeyText) throws NoSuchAlgorithmException, InvalidKeySpecException {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        return keyFactory.generatePublic(x509EncodedKeySpec);
    }
    
    /**
     * pem格式读取私钥
     * @param pemString
     * @param password
     * @return
     * @throws IOException
     */
    public static PrivateKey privateKey(String pemString, String password) throws IOException {
          return (PrivateKey) parseKey(pemString, password);
    }

    /**
     * pem格式读取私钥
     * @param pemString
     * @return
     * @throws IOException
     */
    public static PrivateKey privateKey(String pemString) throws IOException {
          return (PrivateKey) parseKey(pemString, null);
    }

    /**
     * pem格式读取公钥
     * @param pemString
     * @return
     * @throws IOException
     */
    public static PublicKey publicKey(String pemString) throws IOException {
          return (PublicKey) parseKey(pemString, null);
    }

    /**
     * Parses a Key instance from a PEM representation.
     * <p>
     * When the provided key is encrypted, the provided pass phrase is applied.
     *
     * @param pemString  a PEM representation of a private key (cannot be null or empty)
     * @param passPhrase optional pass phrase (must be present if the private key is encrypted).
     * @return a  Key instance (never null)
     */
    public static Key parseKey(String pemString, String passPhrase) throws IOException {

        if (passPhrase == null) {
            passPhrase = "";
        }
        try (StringReader reader = new StringReader(pemString); //
             PEMParser pemParser = new PEMParser(reader)) {

            final Object object = pemParser.readObject();
            final JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME);

            final KeyPair kp;

            if (object instanceof PEMEncryptedKeyPair) {
                // Encrypted key - we will use provided password
                final PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(passPhrase.toCharArray());
                kp = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
            } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
                // Encrypted key - we will use provided password
                try {
                    final PKCS8EncryptedPrivateKeyInfo encryptedInfo = (PKCS8EncryptedPrivateKeyInfo) object;
                    final InputDecryptorProvider provider = new JceOpenSSLPKCS8DecryptorProviderBuilder().build(passPhrase.toCharArray());
                    final PrivateKeyInfo privateKeyInfo = encryptedInfo.decryptPrivateKeyInfo(provider);
                    return converter.getPrivateKey(privateKeyInfo);
                } catch (PKCSException | OperatorCreationException e) {
                    throw new IOException("Unable to decrypt private key.", e);
                }
            } else if (object instanceof PrivateKeyInfo) {
                return converter.getPrivateKey((PrivateKeyInfo) object);
            } else if (object instanceof SubjectPublicKeyInfo) {
                return converter.getPublicKey((SubjectPublicKeyInfo) object);
            } else {
                // Unencrypted key - no password needed
                kp = converter.getKeyPair((PEMKeyPair) object);
            }
            return kp.getPrivate();
        }
    }

    /**
     * 分段加解密处理
     */
    private static byte[] sectionHandle(byte[] data, Cipher cipher, int maxLen) throws IllegalBlockSizeException, BadPaddingException, IOException {
        int dataLen = data.length;
        //偏移量
        int offLen = 0;
        int i = 0;
        byte[] cache;
        ByteArrayOutputStream bops = new ByteArrayOutputStream();
        while (dataLen - offLen > 0) {
            if (dataLen - offLen > maxLen) {
                cache = cipher.doFinal(data, offLen, maxLen);
            } else {
                cache = cipher.doFinal(data, offLen, dataLen - offLen);
            }
            bops.write(cache);
            i++;
            offLen = maxLen * i;
        }
        byte[] handleData = bops.toByteArray();
        bops.close();
        return handleData;
    }

    /**
     * RSA密钥对对象
     */
    public static class RSAKeyPair {
        private String publicKey;
        private String privateKey;

        public RSAKeyPair(String publicKey, String privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }

        public String getPublicKey() {
            return publicKey;
        }

        public String getPrivateKey() {
            return privateKey;
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容