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;