package cc.mrbird.febs.pay.util;
|
|
|
|
import org.apache.commons.codec.binary.Base64;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
import javax.crypto.Cipher;
|
import java.io.ByteArrayOutputStream;
|
import java.nio.charset.StandardCharsets;
|
import java.security.*;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
/**
|
* RSA加解密的工具类
|
*/
|
public class RSAUtil {
|
// private static final Logger logger = LoggerFactory.getLogger(RSAUtil.class);
|
public static final String SIGNATURE_ALGORITHM_SHA1 = "SHA1withRSA";
|
public static final String SIGNATURE_ALGORITHM_MD5 = "MD5withRSA";
|
public static final String RSA = "RSA";
|
|
public static final String ANDROID_ENCRYPT_ALGORITHM = "RSA/ECB/NoPadding";
|
public static final String DEFAULT_ENCRYPT_ALGORITHM = "RSA/ECB/PKCS1Padding";
|
|
public static final String PUBLIC_KEY = "publicKey";
|
public static final String PRIVATE_KEY = "privateKey";
|
|
/** */
|
/**
|
* RSA最大加密明文大小
|
*/
|
private static final int MAX_ENCRYPT_BLOCK = 116;
|
|
/** */
|
/**
|
* RSA最大解密密文大小
|
*/
|
private static final int MAX_DECRYPT_BLOCK = 128;
|
|
/**
|
* 初始化BC提供者,RSA算法必须要先初始化BC才能进行加密解密和签名验签
|
*/
|
private static void initProvider() {
|
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
|
Security.addProvider(new BouncyCastleProvider());
|
}
|
}
|
|
/**
|
* 生成RSA签名串
|
*
|
* @param data 需要生成签名串的数据
|
* @param privateKey 私钥
|
* @return
|
* @throws BizException
|
*/
|
public static String sign(String data, String privateKey, boolean isSha) throws Exception {
|
try {
|
initProvider();
|
byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
|
byte[] keyBytes = CodeUtil.base64Decode(privateKey);
|
String algorithm = isSha ? SIGNATURE_ALGORITHM_SHA1 : SIGNATURE_ALGORITHM_MD5;
|
|
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
PrivateKey priKey = KeyFactory.getInstance(RSA).generatePrivate(pkcs8KeySpec);
|
Signature signature = Signature.getInstance(algorithm);
|
signature.initSign(priKey);
|
signature.update(dataBytes);
|
return CodeUtil.base64Encode(signature.sign());
|
}catch (Throwable e){
|
// logger.error("==>sign err:", e);
|
throw new Exception("生成RSA签名失败", e);
|
}
|
}
|
|
/**
|
* 验证RSA签名串
|
*
|
* @param data 需要验签的数据
|
* @param publicKey 公钥
|
* @param sign 用户传过来的签名串
|
* @return
|
* @throws BizException
|
*/
|
public static boolean verify(String data, String publicKey, String sign, boolean isSha) throws Exception {
|
try {
|
initProvider();
|
byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
|
byte[] signBytes = CodeUtil.base64Decode(sign);
|
String algorithm = isSha ? SIGNATURE_ALGORITHM_SHA1 : SIGNATURE_ALGORITHM_MD5;
|
PublicKey publicK = getPublicKey(publicKey);
|
|
Signature signature = Signature.getInstance(algorithm);
|
signature.initVerify(publicK);
|
signature.update(dataBytes);
|
return signature.verify(signBytes);
|
} catch (Throwable e) {
|
// logger.error("==>verify err:", e);
|
throw new Exception("RSA验签失败", e);
|
}
|
}
|
|
/**
|
* 对称密钥公钥加密
|
*
|
* @param publicKeyStr 公钥Str
|
* @param content 密钥原文
|
* @return 加密密文
|
*/
|
public static String encryptByPublicKey(String publicKeyStr, String content) throws Exception {
|
|
byte[] dataBytes = content.getBytes(StandardCharsets.UTF_8);
|
dataBytes = doCipher(dataBytes, publicKeyStr, true, false);
|
return CodeUtil.base64Encode(dataBytes);
|
|
}
|
|
/**
|
* 对称密钥密文解密
|
*
|
* @param privateKeyStr 私钥字符串
|
* @param content 对称密钥密文
|
* @return 对称密钥明文
|
* @throws Exception
|
*/
|
public static String decryptByPrivateKey(String privateKeyStr, String content) throws Exception{
|
byte[] dataBytes = CodeUtil.base64Decode(content);
|
dataBytes = doCipher(dataBytes, privateKeyStr, false, false);
|
return new String(dataBytes, StandardCharsets.UTF_8);
|
|
}
|
|
private static byte[] doCipher(byte[] dataBytes, String keyStr, boolean isEncrypt, boolean isAndroid) throws Exception {
|
|
initProvider();
|
|
Key key;
|
Cipher cipher;
|
int maxBlock;
|
|
if (isEncrypt) {
|
maxBlock = MAX_ENCRYPT_BLOCK;
|
key = getPublicKey(keyStr);
|
if (isAndroid) {
|
cipher = Cipher.getInstance(ANDROID_ENCRYPT_ALGORITHM);// 如果是安卓机
|
} else {
|
cipher = Cipher.getInstance(DEFAULT_ENCRYPT_ALGORITHM);
|
}
|
cipher.init(Cipher.ENCRYPT_MODE, key);
|
} else {
|
maxBlock = MAX_DECRYPT_BLOCK;
|
byte[] keyBytes = Base64.decodeBase64(keyStr);
|
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
|
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
|
cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
cipher.init(Cipher.DECRYPT_MODE, privateK);
|
}
|
|
int offSet = 0, i = 0, inputLen = dataBytes.length;
|
byte[] cache;
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
try {
|
// 对数据分段加密/解密
|
while (inputLen - offSet > 0) {
|
if (inputLen - offSet > maxBlock) {
|
cache = cipher.doFinal(dataBytes, offSet, maxBlock);
|
} else {
|
cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
|
}
|
out.write(cache, 0, cache.length);
|
i++;
|
offSet = i * maxBlock;
|
}
|
return out.toByteArray();
|
} finally {
|
out.close();
|
}
|
}
|
|
/**
|
* 生成公私密钥对
|
* @return
|
*/
|
public static Map<String, String> genKeyPair() throws Exception {
|
try {
|
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
|
keyPairGen.initialize(1024);
|
KeyPair keyPair = keyPairGen.generateKeyPair();
|
|
Map<String, String> keyMap = new HashMap<>(2);
|
keyMap.put(PUBLIC_KEY, CodeUtil.base64Encode(keyPair.getPublic().getEncoded()));
|
keyMap.put(PRIVATE_KEY, CodeUtil.base64Encode(keyPair.getPrivate().getEncoded()));
|
return keyMap;
|
}catch (Throwable e){
|
throw new Exception("生成RSA密钥对出现异常", e);
|
}
|
}
|
|
private static PublicKey getPublicKey(String publicKey) throws Exception {
|
byte[] keyBytes = CodeUtil.base64Decode(publicKey);
|
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
|
return keyFactory.generatePublic(x509KeySpec);
|
}
|
}
|