Rsa加密解密,支持分段加密解密,支持java,php

java版

package com.zmt.payment.common.encrypt.utils;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author : scott
 * @version : v1.0
 * @calssname : Rsa
 * @date : 2022/3/28 18:22
 * @status : create
 * @description :RSA 非对称加密 标准版-官方发布参考Oracle整合
 * 缺点:加密长度受密钥长度限制,导致加密数据长度不能超过总数据长度的   定值比例
 *  <p>
 *  需要依赖 Apache Commons Codec
 *  <p>
 *  Apache Commons Codec 软件包包含各种格式的简单编码器和解码器,如Base64和Hexadecimal。
 *  除了这些广泛使用的编码器和解码器之外,编解码器包还维护一组语音编码实用程序。
 */
public class RsaOfficial {
    /**
     * 加密算法类型
     * <p>
     * 只能是:DiffieHellman、DSA、RSA、EC
     *
     * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator">KeyPairGenerator Algorithms</a>
     */
    static final String ALGORITHM_KEY = "RSA";

    /**
     * 算法长度
     * DiffieHellman(1024)、DSA(1024)、RSA(1024,2048)
     *
     * @see <a href="https://docs.oracle.com/javase/8/docs/api/java/security/KeyPairGenerator.html">Class KeyPairGenerator</a>
     */
//    private static final int KEY_SIZE = 1024;
    private static final int KEY_SIZE = 2048;

    /**
     * 初始化秘钥对
     *
     * @return 标准密钥对
     * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator">KeyPairGenerator Algorithms</a>
     */
    public static KeyPair initKeyPair() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_KEY);
            keyPairGenerator.initialize(KEY_SIZE);
            return keyPairGenerator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * 初始化密钥对
     *
     * @return 字节数组数据类型的密钥对
     * @see #initKeyPair()
     */
    public static ByteKey getByteKey() {
        KeyPair keyPair = initKeyPair();
        return new ByteKey(
                keyPair.getPublic() ,
                keyPair.getPrivate());
    }

    /**
     * 初始化密钥对
     *
     * @return String 类型的密钥对
     * @see #initKeyPair()
     */
    public static StringKey getStringKey() {
        KeyPair keyPair = initKeyPair();
        return new StringKey(
                keyPair.getPublic() ,
                keyPair.getPrivate());
    }

    /**
     * 通过公钥加密数据
     *
     * @param publicKeyByte 公钥,字节数组类型
     * @param dataByte      需要加密的数据,字节数组类型
     * @return 返回公钥加密数据
     * @throws InvalidKeySpecException   使用字节数据类型的公钥根据指定算法生成公钥时异常
     *                                   可能出现的原因:
     *                                   1、公钥错误
     *                                   2、公钥与算法不匹配
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws BadPaddingException       秘钥错误
     * @throws IllegalBlockSizeException 加密模块长度不合法
     *                                   长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @see #publicKey(byte[], byte[], int)
     * @see #privateKeyDecryptByte(byte[], byte[]) 对应解密时使用
     */
    public static byte[] publicKeyEncryptByte(byte[] publicKeyByte, byte[] dataByte) throws InvalidKeySpecException,
            NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return publicKey(
                publicKeyByte ,
                dataByte ,
                Cipher.ENCRYPT_MODE);
    }

    /**
     * 通过私钥解密数据
     *
     * @param privateKeyByte 私钥,字节数组类型
     * @param dataByte       需要解密的数据,字节数组类型
     * @return 返回通过私钥解密的数据,字节数组类型
     * @throws InvalidKeySpecException   使用字节数据类型的公钥根据指定算法生成公钥时异常
     *                                   可能出现的原因:
     *                                   1、公钥错误
     *                                   2、公钥与算法不匹配
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws BadPaddingException       秘钥错误
     * @throws IllegalBlockSizeException 加密模块长度不合法
     *                                   长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @see #privateKey(byte[], byte[], int)
     * @see #publicKeyEncryptByte(byte[], byte[]) 对应加密时使用
     */
    public static byte[] privateKeyDecryptByte(byte[] privateKeyByte, byte[] dataByte) throws InvalidKeySpecException,
            NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return privateKey(
                privateKeyByte ,
                dataByte ,
                Cipher.DECRYPT_MODE);
    }

    /**
     * 通过公钥加密数据
     *
     * @param publicKey 公钥
     * @param data      需要加密的数据
     * @return 返回公钥加密数据
     * @throws InvalidKeySpecException   使用字节数据类型的公钥根据指定算法生成公钥时异常
     *                                   可能出现的原因:
     *                                   1、公钥错误
     *                                   2、公钥与算法不匹配
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws BadPaddingException       秘钥错误
     * @throws IllegalBlockSizeException 加密模块长度不合法
     *                                   长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @see #privateKey(byte[], byte[], int)
     * @see #privateKeyDecrypt(String, String) 对应解密时使用
     */
    public static String publicKeyEncrypt(String publicKey, String data) throws InvalidKeySpecException,
            NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return Base64.encodeBase64String(
                publicKeyEncryptByte(
                        Base64.decodeBase64(publicKey) ,
                        data.getBytes())
        );
    }

    /**
     * 通过私钥解密数据
     *
     * @param privateKey 私钥
     * @param data       需要解密的数据
     * @return 返回私钥解密数据
     * @throws InvalidKeySpecException   使用字节数据类型的公钥根据指定算法生成公钥时异常
     *                                   可能出现的原因:
     *                                   1、公钥错误
     *                                   2、公钥与算法不匹配
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws BadPaddingException       秘钥错误
     * @throws IllegalBlockSizeException 加密模块长度不合法
     *                                   长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @see #publicKey(byte[], byte[], int)
     * @see #publicKeyEncrypt(String, String) 对应加密时使用
     */
    public static String privateKeyDecrypt(String privateKey, String data) throws InvalidKeySpecException,
            NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return new String(
                privateKeyDecryptByte(
                        Base64.decodeBase64(privateKey) ,
                        Base64.decodeBase64(data))
        );
    }

    /**
     * 通过私钥加密数据
     *
     * @param privateKeyByte 私钥,字节数组类型
     * @param dataByte       需要解密的数据,字节数组类型
     * @return 返回私钥加密数据,字节数组类型
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws IllegalBlockSizeException 加密模块长度不合法
     *                                   长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @throws BadPaddingException       秘钥错误
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws InvalidKeySpecException   使用字节数据类型的公钥根据指定算法生成公钥时异常
     *                                   可能出现的原因:
     *                                   1、公钥错误
     *                                   2、公钥与算法不匹配
     * @see #privateKey(byte[], byte[], int)
     * @see #publicKeyDecryptByte(byte[], byte[]) 对应解密时使用
     */
    public static byte[] privateKeyEncryptByte(byte[] privateKeyByte, byte[] dataByte) throws NoSuchPaddingException,
            IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
        return privateKey(
                privateKeyByte ,
                dataByte ,
                Cipher.ENCRYPT_MODE);
    }

    /**
     * 通过公钥解密数据
     *
     * @param publicKeyByte 公钥,字节数组类型
     * @param dataByte      需要加密的数据,字节数组类型
     * @return 返回公钥解密数据,字节数组类型
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws IllegalBlockSizeException 加密模块长度不合法
     *                                   长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @throws BadPaddingException       秘钥错误
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws InvalidKeySpecException   使用字节数据类型的公钥根据指定算法生成公钥时异常
     *                                   可能出现的原因:
     *                                   1、公钥错误
     *                                   2、公钥与算法不匹配
     * @see #publicKey(byte[], byte[], int)
     * @see #privateKeyEncryptByte(byte[], byte[]) 对应加密时使用
     */
    public static byte[] publicKeyDecryptByte(byte[] publicKeyByte, byte[] dataByte) throws NoSuchPaddingException,
            IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
        return publicKey(
                publicKeyByte ,
                dataByte ,
                Cipher.DECRYPT_MODE);
    }

    /**
     * 通过私钥加密数据
     *
     * @param privateKey 私钥
     * @param data       需要解密的数据
     * @return 私密加密的数据
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws IllegalBlockSizeException 加密模块长度不合法
     *                                   长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @throws BadPaddingException       秘钥错误
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws InvalidKeySpecException   使用字节数据类型的公钥根据指定算法生成公钥时异常
     *                                   可能出现的原因:
     *                                   1、公钥错误
     *                                   2、公钥与算法不匹配
     * @see #privateKey(byte[], byte[], int)
     * @see #publicKeyDecrypt(String, String) 对应解密时使用
     */
    public static String privateKeyEncrypt(String privateKey, String data) throws NoSuchPaddingException,
            IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
        return Base64.encodeBase64String(
                privateKey(
                        Base64.decodeBase64(privateKey) ,
                        data.getBytes() ,
                        Cipher.ENCRYPT_MODE)
        );
    }

    /**
     * 通过公钥解密数据
     *
     * @param publicKey 公钥,字节数组类型
     * @param data      需要加密的数据,字节数组类型
     * @return 返回公钥解密数据,字节数组类型
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws IllegalBlockSizeException 加密模块长度不合法
     *                                   长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @throws BadPaddingException       秘钥错误
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws InvalidKeySpecException   使用字节数据类型的公钥根据指定算法生成公钥时异常
     *                                   可能出现的原因:
     *                                   1、公钥错误
     *                                   2、公钥与算法不匹配
     * @see #publicKey(byte[], byte[], int)
     * @see #privateKeyEncrypt(String, String) 对应加密时使用
     */
    public static String publicKeyDecrypt(String publicKey, String data) throws NoSuchPaddingException,
            IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
        return new String(
                publicKey(
                        Base64.decodeBase64(publicKey) ,
                        Base64.decodeBase64(data) ,
                        Cipher.DECRYPT_MODE)
        );
    }

    /**
     * 通过公钥加密、解密数据
     *
     * @param publicKeyByte    公钥,字节数组类型
     * @param dataByte         需要加密的数据,字节数组类型
     * @param encryptOrDecrypt 加密还是解密
     *                         加密:{@link Cipher#ENCRYPT_MODE}
     *                         解密:{@link Cipher#DECRYPT_MODE}
     * @return 返回通过公钥加密的数据
     * @throws InvalidKeySpecException   使用字节数据类型的公钥根据指定算法生成公钥时异常
     *                                   可能出现的原因:
     *                                   1、公钥错误
     *                                   2、公钥与算法不匹配
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws BadPaddingException       秘钥错误
     *                                   可能出现的错误:秘钥与秘钥类型不匹配
     * @throws IllegalBlockSizeException 加密模块长度不合法
     *                                   长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @see <a href="https://docs.oracle.com/javase/8/docs//technotes/guides/security/StandardNames.html#KeyFactory">KeyFactory Algorithms</a>
     */
    private static byte[] publicKey(byte[] publicKeyByte, byte[] dataByte, int encryptOrDecrypt) throws
            InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyByte);

        KeyFactory keyFactory;
        try {
            keyFactory = KeyFactory.getInstance(ALGORITHM_KEY);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException(e);
        }

        Key publicKey = keyFactory.generatePublic(x509KeySpec);
        String algorithmPublicKey = keyFactory.getAlgorithm();

        Cipher cipherPublicKey;
        try {
            cipherPublicKey = Cipher.getInstance(algorithmPublicKey);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException(e);
        }

        cipherPublicKey.init(encryptOrDecrypt, publicKey);

        return cipherPublicKey.doFinal(dataByte);
    }

    /**
     * 通过私钥加密、解密数据
     *
     * @param privateKeyByte   私钥,字节数组类型
     * @param dataByte         需要解密的数据,字节数组类型
     * @param encryptOrDecrypt 加密还是解密
     *                         加密:{@link Cipher#ENCRYPT_MODE}
     *                         解密:{@link Cipher#DECRYPT_MODE}
     * @return 返回通过私钥解密的数据,字节数组类型
     * @throws InvalidKeySpecException   使用字节数据类型的私钥根据指定算法生成私钥时异常
     *                                   可能出现的原因:
     *                                   1、私钥错误
     *                                   2、私钥与算法不匹配
     * @throws NoSuchPaddingException    本例中不出现
     *                                   使用 {@link KeyPairGenerator#getInstance(String, String)}、
     *                                   {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常
     * @throws InvalidKeyException       秘钥无效、秘钥与秘钥类型不匹配
     * @throws BadPaddingException       秘钥错误
     *                                   可能出现的错误:秘钥与秘钥类型不匹配
     * @throws IllegalBlockSizeException 解密模块长度不合法
     *                                   长度限制:需要解密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11)
     * @see <a href="https://docs.oracle.com/javase/8/docs//technotes/guides/security/StandardNames.html#KeyFactory">KeyFactory Algorithms</a>
     */
    private static byte[] privateKey(byte[] privateKeyByte, byte[] dataByte, int encryptOrDecrypt) throws
            InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException,
            IllegalBlockSizeException {

        KeyFactory keyFactory;
        try {
            keyFactory = KeyFactory.getInstance(ALGORITHM_KEY);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException(e);
        }

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyByte);

        String algorithmPrivateKey = keyFactory.getAlgorithm();
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        Cipher cipherPrivateKey;
        try {
            cipherPrivateKey = Cipher.getInstance(algorithmPrivateKey);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException(e);
        }

        cipherPrivateKey.init(encryptOrDecrypt, privateKey);

        return cipherPrivateKey.doFinal(dataByte);
    }

    /**
     * 字节数据类型的密钥对
     */
    public static class ByteKey {

        /**
         * 公钥
         */
        private final byte[] publicKey;

        /**
         * 私钥
         */
        private final byte[] privateKey;

        /**
         * 构造器
         *
         * @param publicKey  公钥
         * @param privateKey 私钥
         */
        private ByteKey(PublicKey publicKey, PrivateKey privateKey) {
            this.publicKey = publicKey.getEncoded();
            this.privateKey = privateKey.getEncoded();
        }

        /**
         * 获取公钥
         *
         * @return 返回公钥
         */
        public byte[] getPublicKey() {
            return publicKey;
        }

        /**
         * 获取私钥,byte[]
         *
         * @return 返回私钥,byte[]
         */
        public byte[] getPrivateKey() {
            return privateKey;
        }

    }

    /**
     * String数据类型的密钥对
     */
    public static class StringKey {

        /**
         * 公钥
         */
        private final String publicKey;

        /**
         * 私钥
         */
        private final String privateKey;

        /**
         * 构造器
         *
         * @param publicKey  公钥
         * @param privateKey 私钥
         */
        private StringKey(PublicKey publicKey, PrivateKey privateKey) {
            this.publicKey = Base64.encodeBase64String(publicKey.getEncoded());
            this.privateKey = Base64.encodeBase64String(privateKey.getEncoded());
        }

        /**
         * 获取公钥
         *
         * @return 返回公钥,String
         */
        public String getPublicKey() {
            return publicKey;
        }

        /**
         * 获取私钥
         *
         * @return 返回私钥,String
         */
        public String getPrivateKey() {
            return privateKey;
        }

    }
}

package com.zmt.payment.common.encrypt.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author : scott
 * @version : v1.0
 * @calssname : RsaCustomize
 * @date : 2022/3/28 22:36
 * @status : create
 * @description : RSA 非对称加密 自定义版
 */
@Slf4j
public class Rsa {
    /**
     * 加密算法类型
     */
    static final String ALGORITHM_KEY = "RSA";

    /**
     * 算法长度  1024  or   2048
     */
    private static final int KEY_SIZE = 2048;

    /**
     * 加密数据拆分节点
     */
    private static final int MAX_ENCRYPT_BLOCK = (KEY_SIZE / 8) -11;

    /**
     * 解密数据拆分节点
     */
    private static final int MAX_DECRYPT_BLOCK = KEY_SIZE / 8;

    public static final String SIGN_ALGORITHMS = "SHA256withRSA";

    /**
     * 算法实例
     */
    private static String ALGORITHM_RSA = "RSA";

    /**     密钥流程:初始化密钥   ->  (公钥 + 私钥)对                           **/
    /**     加密流程:客户端       ->   公钥+待解密数据      ->   加密数据        **/
    /**     解密流程:服务端       ->   私钥钥+加密密数据    ->   解密数据        **/
    /**     签名流程:商户端       ->   公钥
     *                公钥加密数据 + 私钥 = 签名数据
     *
     *                平台端:     ->    私钥
     *                私钥加密数据 + 私钥 = 签名
     *
     *      验签流程:商户端       ->     校验平台签名
     *                私钥加密数据 + 私钥签名 + 公钥
     *
     *                 平台端      ->     校验商户签名
     *                 公钥加密数据 + 公钥签名 + 公钥
     * **/
    /**     验签流程:服务端       ->   私钥钥+加密密数据    ->   解密数据        **/


    /**
     * 使用公钥将数据加密
     * @param sourceData:原始字符串
     * @param publicKey:公钥
     * @return
     */
    public static String publicEncrypt(String sourceData , String publicKey){
        return rsaEncrypt(
                sourceData ,
                publicKey ,
                Boolean.FALSE);
    }

    /**
     * 使用私钥将数据加密
     * @param sourceData:原始字符串
     * @param privateKey:私钥
     * @return
     */
    public static String privateEncrypt(String sourceData , String privateKey){
        return rsaEncrypt(
                sourceData ,
                privateKey ,
                Boolean.TRUE);
    }


    /**
     * 使用公钥解密
     * @param encryptedData:私钥加密数据
     * @param privateKey:(公钥)私钥
     * @return
     */
    public static String publicDecrypt(String encryptedData , String privateKey) {
        return rsaDecrypt(
                encryptedData ,
                privateKey ,
                Boolean.FALSE);
    }

    /**
     * 使用私钥解密
     * @param encryptedData:公钥加密数据
     * @param privateKey:私钥
     * @return
     */
    public static String privateDecrypt(String encryptedData , String privateKey) {
        return rsaDecrypt(
                encryptedData ,
                privateKey ,
                Boolean.TRUE);
    }

    /**
     * RSA加密算法 - 分段
     * @param sourceData:待加密数据/原始数据
     * @param key :公钥/私钥
     * @param isPrivate TRUE = 私钥 | FALSE = 公钥
     * @return
     */
    protected static String rsaEncrypt(String sourceData , String key , Boolean isPrivate){
        try {
            Key key1 = isPrivate ? loadPrivateKey(key) : loadPublicKey(key);
            byte[] data = sourceData.getBytes();
            byte[] dataReturn = new byte[0];
            Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
            cipher.init(Cipher.ENCRYPT_MODE, key1);

            // 加密时超过117/245字节就报错。为此采用分段加密的办法来加密
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
                byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i,i + MAX_ENCRYPT_BLOCK));
                sb.append(new String(doFinal));
                dataReturn = ArrayUtils.addAll(dataReturn, doFinal);
            }

            return Base64.encodeBase64URLSafeString(dataReturn);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * RSA解密算法 - 分段
     * @param encryptedData:加密数据/待解密数据
     * @param key:公钥/私钥
     * @param isPrivate TRUE = 私钥 | FALSE = 公钥
     * @return
     */
    protected static String rsaDecrypt(String encryptedData, String key , Boolean isPrivate){
        try {
            Key key1 = isPrivate ? loadPrivateKey(key) : loadPublicKey(key);
            byte[] data = Base64.decodeBase64(encryptedData);

            Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
            cipher.init(Cipher.DECRYPT_MODE, key1);

            // 解密时超过128字节就报错。为此采用分段解密的办法来解密
            byte[] dataReturn = new byte[0];
            for (int i = 0; i < data.length; i += MAX_DECRYPT_BLOCK) {
                byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_DECRYPT_BLOCK));
                dataReturn = ArrayUtils.addAll(dataReturn, doFinal);
            }

            return new String(dataReturn);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 私钥签名
     * @param encryptData:加密数据
     * @param privateKey:私钥
     * @return
     */
    public static String rsaSign(String encryptData , String privateKey) {
        try {
            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
            signature.initSign(loadPrivateKey(privateKey));
            signature.update(encryptData.getBytes());
            byte[] signed = signature.sign();
            return Base64.encodeBase64URLSafeString(signed);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥验签
     * @param encryptStr:加密数据
     * @param sign:签名数据
     * @param publicKey:公钥
     * @return
     * @throws Exception
     */
    public static boolean verifySign(String encryptStr , String sign , String publicKey)throws Exception {
        try {
            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
            signature.initVerify(loadPublicKey(publicKey));
            signature.update(encryptStr.getBytes());
            return signature.verify(Base64.decodeBase64(sign));
        }  catch (NoSuchAlgorithmException e) {
            throw new Exception(String.format("验证数字签名时没有[%s]此类算法", SIGN_ALGORITHMS));
        } catch (InvalidKeyException e) {
            throw new Exception("验证数字签名时公钥无效");
        } catch (SignatureException e) {
            throw new Exception("验证数字签名时出现异常");
        }
    }

    /**
     * 字符串转加载公钥
     * @param publicKeyStr
     * @return
     * @throws Exception
     */
    public static PublicKey loadPublicKey(String publicKeyStr) throws Exception {
        byte[] buffer = Base64.decodeBase64(publicKeyStr);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 字符串转加载私钥
     * @param privateKeyStr
     * @return
     * @throws Exception
     */
    public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
        byte[] buffer = Base64.decodeBase64(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * URL安全编码器
     * @param encryptStr
     * @return
     */
    public  static String urlsafe_encode (String encryptStr){
        return encryptStr
                .replaceAll("\\+","-")
                .replaceAll("/","_")
                .replaceAll("=","")
                .replaceAll("(\r\n|\r|\n|\n\r)","");

    }

    /**
     * URL安全解码器
     * @param encryptStr
     * @return
     */
    public  static String urlsafe_decode(String encryptStr){
        encryptStr= encryptStr
                .replaceAll("-","+")
                .replaceAll("_","/");
        int mob = encryptStr.length() % 4;
        if(mob > 0){
            encryptStr += "====".substring(mob);
        }
        return encryptStr;
    }


    /**
     * 加解密测试
     * @param args
     * @throws Exception
     */
    public  static  void main(String[ ] args) throws Exception {

//        密钥生成 2048
        Long startTime = System.currentTimeMillis();
        RsaOfficial.StringKey key = RsaOfficial.getStringKey();
        String publicKeyStr = key.getPublicKey();
        String privateKeyStr = key.getPrivateKey();
        Long keyTime = System.currentTimeMillis();
        log.warn("密钥生成耗时:{} ms" , (keyTime - startTime));


        //加密
        String data = "i like java";
        data = "{\"emptyBillingInfo\":true,\"inWebsiteType\":\"default\",\"merOrderNo\":\"13396670-20220327005549\",\"merchantNo\":\"1009\",\"notifyUrl\":\"https://pay.wechatka.com/apg/wechatka/notify/13396670\",\"payAmount\":\"5.48\",\"payCurrency\":\"USD\",\"returnUrl\":\"https://pay.wechatka.com/apg/wechatka/return/13396670\",\"sign\":\"fadb2b66f9275e3ee56a80761967ce25d9ca0cceb16e29f7eb9569004899386c60518a19a7d0c91d24aa44547eef0657f63bedd549f7c32183f9c2eb1567efc4\",\"tranCode\":\"TA002\",\"goods\":\"[{price:5.48,num:1,name:抖币}]\"}";

        String privateEncryptStr = privateEncrypt(data , privateKeyStr);
        String publicEncryptStr = publicEncrypt(data , publicKeyStr);
        String privateEncryptSign = rsaSign(privateEncryptStr , privateKeyStr);
        String publicEncryptSign = rsaSign(publicEncryptStr , privateKeyStr);

        log.info("公钥:{}" , publicKeyStr);
        log.info("私钥:{}" , privateKeyStr);
        log.info("原始数据:{}" , data);
        log.info("私钥加密数据: " + privateEncryptStr);
        log.info("公钥加密数据: " + publicEncryptStr);
        log.info("私钥签名: " + privateEncryptSign);
        log.info("公钥签名: " + publicEncryptSign);
        log.info("公钥解密:" + publicDecrypt(privateEncryptStr , publicKeyStr));
        log.info("私钥解密:" + privateDecrypt(publicEncryptStr , privateKeyStr));
        log.info("verifySign1: " + verifySign(privateEncryptStr , privateEncryptSign , publicKeyStr));
        log.info("verifySign2: " + verifySign(publicEncryptStr , publicEncryptSign , publicKeyStr));

    }


}

php版

<?php 
header ( "Content-type:text/html; charset=utf-8" ); 
//php:5.5.12            apache:2.4.9

class  OpensslRSA{
        //私钥;
       public $private_key = '
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDC7C3fv7IHxkZdfmkk6ll55dveQujAxAo+ky5nmnRvmpib68tIR5NMcE/wwnxZG8lnZcOPAh/Tnj22UZCDQKFFzsvenZKYzuSBDGT1SPu78N0SXYrw6kLPn4rZfdbO/hbjpAgHTc0hyidOWk0obV3vel5bEt2sZU0n/APyJnAxboa2Lm+1f+b6CncFQ4uihqDx4yK4PZAceqa3B3Uf3ZigKArOMtjzYrZY2/Jciib2zRO+tbxvQO+j2SAMvJX1/DsD4Y0GGkmakVlPhgtJ2RHJtl1JaUD/MuCh0HGRV1ZH2O5Xr/7rowZHcIeAvowkXyo6vJcLpxTEJt3YZwLXQrLTAgMBAAECggEAMq8Y6pI855qd11e0XV32cCTdu/hn7x/KjiTVLylRV2e6gOiaDixWV8zobHEVxlHcV991Ly1dOzhtUYf57LcUeENibXtJkCRT9F5VrhYRJvhlc44RP72aK8SPZSg8f8xABWc0kzmeukeHWu9OGtH9V/TYrhPEwjwBCQGVwRRPnfpsKvWUkz8u3NuBS39ivVroJjKz4TsHDDwUkS60gEEgUjjQ4psZQnRhg4wPbGFodkTWvDrzXAjbxSRVque2XZRCPRVczcnW3IDS7+cQmbZd8kagioG+HHEVcCIj1cdOTGA4Gm4PImEIy1ggYGXe4OZMi/1eQq69Hh5isdFvTVZfOQKBgQDjLWKBFSjG+e4/Y4Xecf25uUhtF3L69Zrog8pAaEb3+OAXYwRVvqp69FCbd13aJBMCUk3HFqW/usJOXAqVRaWT0zHovg4rQbcDdYFV3ajWa1BCDKxEBDROxIezliXX4kGE21IDIEzzWoDB+enDlRXGsvhuOrHOISMlYNANGN92ZwKBgQDbpy0TQQaOpCbCyTmf1qE/TAfgo4bfIlmrV8Ua5NePw0f22j50GZRIjbpFPK6jcsILhL9WAG9xvU/NevQsUzgVuKWEqBeWBuTzIJRY3yv8UwSkfyYbZf9WdjhxbWSZdRJsxBj58J6pFe84TnKbTNL1gCLT+59N/CaqemHHNQaktQKBgAuy96KsI0hz8IgFKQy2lBlvaEJt9bbk1RBqUQ0WEamNgITTzZJY2lCwqkIHWKb2OqBg+q5pBSolhQIiDU14o7lEJArXVsV1geZEs99nJd288wojuu9ZxBPWXSKrddFzTmp4HPYaQLw7ievzYc13rQJpjw+mKCf0Xun63Vv/Tuq7AoGBALQhkAyXKfp2Ubcx8EjNaeUPw/IMCQIaGHE0hFb+zmx+WBjvd4IcrAcn+1bmYc12wf1SOtsbdklPWA+Jwo5LHNZrW4nDk7wcIUvlLuMG+fpuVoNUJnsXlWNhhf43GOXkJVz/IABwvJyreUeyxbfoM6TTFTzEwCrjGw55WJBWQwF1AoGAbf5qkTTTBO0BqB29FiiN6NJ6FXK12mML1MZxOX6XziZKnb+zHQu7CdVnemGGbYo+lT1kEobfkVQtOq00dbAUBqndTvsuI7si8Ckv0H0xcoRXhv6U8ceT2XpriL2JwSgdTOzvck70qlQnjill7lPrCFjPL4DMSQmqFijs2tQsjyk=
';
       //公钥
        public $public_key = '
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwuwt37+yB8ZGXX5pJOpZeeXb3kLowMQKPpMuZ5p0b5qYm+vLSEeTTHBP8MJ8WRvJZ2XDjwIf0549tlGQg0ChRc7L3p2SmM7kgQxk9Uj7u/DdEl2K8OpCz5+K2X3Wzv4W46QIB03NIconTlpNKG1d73peWxLdrGVNJ/wD8iZwMW6Gti5vtX/m+gp3BUOLooag8eMiuD2QHHqmtwd1H92YoCgKzjLY82K2WNvyXIom9s0TvrW8b0Dvo9kgDLyV9fw7A+GNBhpJmpFZT4YLSdkRybZdSWlA/zLgodBxkVdWR9juV6/+66MGR3CHgL6MJF8qOryXC6cUxCbd2GcC10Ky0wIDAQAB
';
 
        public $pi_key;
        public $pu_key;
 
        //判断公钥和私钥是否可用
        public function __construct()
        {
            //私钥太长,格式不对。使用此方法格式化私钥
            $this->private_key =str_replace(array("\r\n", "\r", "\n"), "", $this->private_key);
            $this->private_key =  "-----BEGIN PRIVATE KEY-----\n" . wordwrap($this->private_key, 64, "\n",true) . "\n-----END PRIVATE KEY-----";
            //这个函数可用来判断私钥是否是可用的,可用返回资源id Resource id
            $this->pi_key =  openssl_pkey_get_private($this->private_key);
            
            //公钥太长,格式不对。使用此方法格式化公钥
            $this->public_key =str_replace(array("\r\n", "\r", "\n"), "", $this->public_key);
            $this->public_key =  "-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->public_key, 64, "\n",true) . "\n-----END PUBLIC KEY-----";
            //这个函数可用来判断公钥是否是可用的
            $this->pu_key = openssl_pkey_get_public($this->public_key);
        }
  
 
        //加密码时把特殊符号替换成URL可以带的内容
        function urlsafe_b64encode($string) {
            $data = base64_encode($string);
            $data = str_replace(array('+','/','='),array('-','_',''),$data);
            return $data;
        }
 
        //解密码时把转换后的符号替换特殊符号
        function urlsafe_b64decode($string) {
            $data = str_replace(array('-','_'),array('+','/'),$string);
            $mod4 = strlen($data) % 4;
            if ($mod4) {
                $data .= substr('====', $mod4);
            }
            return base64_decode($data);
        }
 
         //私钥加密
        public function PrivateEncrypt($data){
           // openssl_private_encrypt($data,$encrypted,$this->pi_key);
            $crypto = '';
            foreach (str_split($data, 117) as $chunk) {
                openssl_private_encrypt($chunk, $encryptData, $this->pi_key);
                $crypto .= $encryptData;
            }
            $encrypted = $this->urlsafe_b64encode($crypto);//加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的
            return $encrypted;
        }
 
        //私钥加密的内容通过公钥解密出来
        public function PublicDecrypt($encrypted){
            $crypto = '';
            foreach (str_split($this->urlsafe_b64decode($encrypted), 128) as $chunk) {
                openssl_public_decrypt($chunk, $decryptData, $this->pu_key);
                $crypto .= $decryptData;
            }
            return $crypto;
        }
 
        //公钥加密
        public function PublicEncrypt($data){
            //openssl_public_encrypt($data,$encrypted,$this->pu_key);//公钥加密
            $crypto = '';
            foreach (str_split($data, 117) as $chunk) {
                openssl_public_encrypt($chunk, $encryptData, $this->pu_key);
                $crypto .= $encryptData;
            }
            $encrypted = $this->urlsafe_b64encode($crypto);
            return $encrypted;
        }
 
        //公钥加密的内容通过私钥解密出来。密文过长,使用此方法进行解密。
        public function PrivateDecrypt($encrypted)
        {
            $pub_id = openssl_get_publickey($this->pu_key);
            $key_len = openssl_pkey_get_details($pub_id)['bits'];
            $part_len = $key_len/8;
            $crypto = '';
            foreach (str_split($this->urlsafe_b64decode($encrypted), $part_len) as $chunk) {
                openssl_private_decrypt($chunk, $decryptData, $this->pi_key);
                $crypto .= $decryptData;
            }
            return $crypto;
        }

}


//使用方法
$rsa = new OpensslRSA();
//待加密的明文
$data = '0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255';
//明文公钥加密
$encrypt_data = $rsa -> PublicEncrypt($data);
//密文私钥解密
$decrypt_data = $rsa -> PrivateDecrypt($encrypt_data);

// echo $encrypt_data;
echo $decrypt_data;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值