package com.nova.sankuai.domain.api.zhongan;
|
|
import java.io.ByteArrayOutputStream;
|
import java.security.Key;
|
import java.security.KeyFactory;
|
import java.security.PrivateKey;
|
import java.security.PublicKey;
|
import java.security.Signature;
|
import java.security.interfaces.RSAPrivateKey;
|
import java.security.interfaces.RSAPublicKey;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.function.Function;
|
|
import javax.crypto.Cipher;
|
|
import org.apache.commons.lang.StringUtils;
|
import org.apache.tomcat.util.codec.binary.Base64;
|
|
import lombok.AllArgsConstructor;
|
import lombok.Getter;
|
|
/**
|
* <p>
|
* description
|
* </p>
|
*
|
* @author denglb 2021/11/15
|
*/
|
public class SignUtil {
|
public static final String CHARSET = "UTF-8";
|
public static final String RSA_ALGORITHM = "RSA";
|
public static final String RSA_ALGORITHM_SIGN_SHA1 = "SHA1WithRSA";
|
public static final String RSA_ALGORITHM_SIGN_SHA256 = "SHA256withRSA";
|
|
public static String doSign(Map<String, Object> map, String privateKeyStr) {
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
|
// 通过X509编码的Key指令获得公钥对象
|
// X509EncodedKeySpec x509KeySpec = new
|
// X509EncodedKeySpec(Base64.decodeBase64(publicKey));
|
// this.publicKey = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
|
// 通过PKCS#8编码的Key指令获得私钥对象
|
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
|
RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
|
|
String data = getSignContent(map);
|
Signature signature = Signature.getInstance(RSA_ALGORITHM_SIGN_SHA256);
|
signature.initSign(privateKey);
|
signature.update(data.getBytes(CHARSET));
|
return Base64.encodeBase64String(signature.sign());
|
} catch (Exception e) {
|
throw new RuntimeException("签名失败", e);
|
}
|
}
|
|
public static String doSignWithNoOrder(String content, String privateKeyStr) {
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
|
// 通过X509编码的Key指令获得公钥对象
|
// X509EncodedKeySpec x509KeySpec = new
|
// X509EncodedKeySpec(Base64.decodeBase64(publicKey));
|
// this.publicKey = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
|
// 通过PKCS#8编码的Key指令获得私钥对象
|
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(
|
Base64.decodeBase64(privateKeyStr));
|
RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
|
|
Signature signature = Signature.getInstance(RSA_ALGORITHM_SIGN_SHA256);
|
signature.initSign(privateKey);
|
signature.update(content.getBytes());
|
return Base64.encodeBase64String(signature.sign());
|
} catch (Exception e) {
|
throw new RuntimeException("签名失败", e);
|
}
|
}
|
|
/**
|
* 参数格式转换Map转String
|
*
|
* @param sortedParams
|
* @return
|
*/
|
public static String getSignContent(Map<String, Object> sortedParams) {
|
StringBuffer content = new StringBuffer();
|
List<String> keys = new ArrayList<>(sortedParams.keySet());
|
Collections.sort(keys);
|
int index = 0;
|
for (String key : keys) {
|
String value = sortedParams.get(key).toString();
|
if (isNotEmpty(key) && isNotEmpty(value)) {
|
content.append((index == 0 ? "" : "&") + key + "=" + value);
|
index++;
|
}
|
}
|
return content.toString();
|
}
|
|
private static boolean isNotEmpty(String str) {
|
return ((str != null) && (str.length() > 0));
|
}
|
|
private static boolean isEmpty(String str) {
|
return ((str == null) || (str.length() == 0));
|
}
|
|
/**
|
* 私钥加密
|
*
|
* @return String 加密数据
|
*/
|
public static String encryptByPrivateKey(Map<String, Object> map, String privateKeyStr) throws Exception {
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
|
// 通过PKCS#8编码的Key指令获得私钥对象
|
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
|
RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
|
// 数据加密
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
|
|
// 待加密内容
|
String content = getSignContent(map);
|
|
byte[] data = cipher.doFinal(content.getBytes(CHARSET));
|
return Base64.encodeBase64String(data);
|
} catch (Exception e) {
|
throw new RuntimeException("私钥加密失败", e);
|
}
|
}
|
|
/**
|
* 公钥加密
|
*
|
* @return String 加密数据
|
*/
|
public static String encryptByPublicKey(Map<String, Object> map, String publicKeyStr) {
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
|
// 通过X509编码的Key指令获得公钥对象
|
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
|
RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
|
|
// 数据加密
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
|
// 待加密内容
|
String content = getSignContent(map);
|
|
byte[] data = cipher.doFinal(content.getBytes(CHARSET));
|
return Base64.encodeBase64String(data);
|
} catch (Exception e) {
|
throw new RuntimeException("公钥加密失败", e);
|
}
|
}
|
|
/**
|
* 公钥加密(无排序)
|
*
|
* @return String 加密数据
|
*/
|
public static String encryptByPublicKeyWithNoOrderForLongData(String content, String publicKeyStr) {
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
|
// 通过X509编码的Key指令获得公钥对象
|
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(
|
Base64.decodeBase64(publicKeyStr));
|
RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
|
|
// 数据加密
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
|
byte[] data = content.getBytes();
|
int inputLen = data.length;
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
int offSet = 0;
|
byte[] cache;
|
int i = 0;
|
while (inputLen - offSet > 0) {
|
if (inputLen - offSet > 117) {
|
cache = cipher.doFinal(data, offSet, 117);
|
} else {
|
cache = cipher.doFinal(data, offSet, inputLen - offSet);
|
}
|
out.write(cache, 0, cache.length);
|
i++;
|
offSet = i * 117;
|
}
|
byte[] encryptedData = out.toByteArray();
|
out.close();
|
|
return Base64.encodeBase64String(encryptedData);
|
} catch (Exception e) {
|
throw new RuntimeException("公钥加密失败", e);
|
}
|
}
|
|
/**
|
* RSA-私钥解密过程
|
*
|
* @param context
|
* @param privateKeyStr
|
* @return
|
* @throws Exception
|
*/
|
public static String decryptRSA(String context, String privateKeyStr) {
|
if (isEmpty(privateKeyStr)) {
|
throw new RuntimeException("解密私钥为空, 请设置");
|
}
|
Cipher cipher;
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
|
// 通过PKCS#8编码的Key指令获得私钥对象
|
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
|
RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
|
|
// 使用默认RSA
|
cipher = Cipher.getInstance("RSA");
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
byte[] output = cipher.doFinal(Base64.decodeBase64(context));
|
return new String(output);
|
} catch (Exception e) {
|
throw new RuntimeException("解密数据失败");
|
}
|
}
|
|
/**
|
* RSA-私钥解密过程(长度超128byte分段解密)
|
*
|
* @param context
|
* @param privateKeyStr
|
* @return
|
* @throws Exception
|
*/
|
public static String decryptRSAByPrivateKeyForLongData(String context, String privateKeyStr) {
|
if (isEmpty(privateKeyStr)) {
|
throw new RuntimeException("解密私钥为空, 请设置");
|
}
|
Cipher cipher;
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
|
// 通过PKCS#8编码的Key指令获得私钥对象
|
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
|
RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
|
|
// 使用默认RSA
|
cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
|
byte[] encryptedData = Base64.decodeBase64(context);
|
int inputLen = encryptedData.length;
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
int offSet = 0;
|
byte[] cache;
|
int i = 0;
|
// 对数据分段解密
|
while (inputLen - offSet > 0) {
|
if (inputLen - offSet > 128) {
|
cache = cipher.doFinal(encryptedData, offSet, 128);
|
} else {
|
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
|
}
|
out.write(cache, 0, cache.length);
|
i++;
|
offSet = i * 128;
|
}
|
out.close();
|
return out.toString();
|
} catch (Exception e) {
|
throw new RuntimeException("解密数据失败");
|
}
|
}
|
|
/**
|
* 根据加签类型验证签名
|
*
|
* @param signParams
|
* @param sign
|
* @param publicKey
|
* @return
|
*/
|
public static boolean rsa256CheckContent(Map<String, Object> signParams, String sign, String publicKey) {
|
try {
|
String content = getSignContent(signParams);
|
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(RSA_ALGORITHM_SIGN_SHA256);
|
|
signature.initVerify(pubKey);
|
signature.update(content.getBytes(CHARSET));
|
boolean bverify = signature.verify(Base64.decodeBase64(sign));
|
return bverify;
|
} catch (Exception e) {
|
throw new RuntimeException("验签失败");
|
}
|
}
|
|
/**
|
* 根据加签类型验证签名
|
*
|
* @param sign
|
* @param publicKey
|
* @return
|
*/
|
public static boolean rsa256CheckContentWithNoOrder(String content, String sign, String publicKey) {
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
byte[] encodedKey = Base64.decodeBase64(publicKey);
|
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
|
Signature signature = Signature.getInstance(RSA_ALGORITHM_SIGN_SHA256);
|
|
signature.initVerify(pubKey);
|
signature.update(content.getBytes(CHARSET));
|
boolean bverify = signature.verify(Base64.decodeBase64(sign));
|
return bverify;
|
} catch (Exception e) {
|
throw new RuntimeException("验签失败");
|
}
|
}
|
|
/**
|
* RSA签名
|
*
|
* @param content 待签名的字符串
|
* @param privateKey rsa私钥字符串
|
* @return
|
*/
|
public static String doRsaSign(String content, String privateKey) {
|
return doRsaSign(content, privateKey, CHARSET);
|
}
|
|
/**
|
* RSA签名
|
*
|
* @param content 待签名的字符串
|
* @param privateKey rsa私钥字符串
|
* @param charset 字符编码
|
* @return
|
*/
|
public static String doRsaSign(String content, String privateKey, String charset) {
|
try {
|
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
|
KeyFactory keyf = KeyFactory.getInstance("RSA");
|
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
|
|
Signature signature = Signature.getInstance(RSA_ALGORITHM_SIGN_SHA1);
|
signature.initSign(priKey);
|
if (StringUtils.isEmpty(charset)) {
|
signature.update(content.getBytes());
|
} else {
|
signature.update(content.getBytes(charset));
|
}
|
byte[] signed = signature.sign();
|
return new String(Base64.encodeBase64(signed));
|
} catch (Exception e) {
|
throw new RuntimeException("签名失败", e);
|
}
|
}
|
|
/**
|
* @param content 待签名数据
|
* @param sign 签名值
|
* @param publicKey 分配给开发商公钥
|
* @return
|
*/
|
public static boolean doRsaSignCheck(String content, String sign, String publicKey) {
|
return doRsaSignCheck(content, sign, publicKey, CHARSET);
|
}
|
|
/**
|
* RSA验签
|
*
|
* @param content 待签名数据
|
* @param sign 签名值
|
* @param publicKey 分配给开发商公钥
|
* @param charset 字符集编码
|
* @return
|
*/
|
public static boolean doRsaSignCheck(String content, String sign, String publicKey, String charset) {
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
byte[] encodedKey = Base64.decodeBase64(publicKey);
|
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
|
Signature signature = Signature.getInstance(RSA_ALGORITHM_SIGN_SHA1);
|
signature.initVerify(pubKey);
|
signature.update(content.getBytes(charset));
|
return signature.verify(Base64.decodeBase64(sign));
|
} catch (Exception e) {
|
throw new RuntimeException("验签失败", e);
|
}
|
}
|
|
public static String encryptRSAByPrivateKey(String content, String privateKey) {
|
return doRSA(content, privateKey, KeyTypeEnum.PRIVATE_KEY, RSATypeEnum.ENCRYPT_MODE);
|
}
|
|
public static String encryptRSAByPublicKey(String content, String publicKey) {
|
return doRSA(content, publicKey, KeyTypeEnum.PUBLIC_KEY, RSATypeEnum.ENCRYPT_MODE);
|
}
|
|
public static String decryptRSAByPrivateKey(String content, String privateKey) {
|
return doRSA(content, privateKey, KeyTypeEnum.PRIVATE_KEY, RSATypeEnum.DECRYPT_MODE);
|
}
|
|
public static String decryptRSAByPublicKey(String content, String publicKey) {
|
return doRSA(content, publicKey, KeyTypeEnum.PUBLIC_KEY, RSATypeEnum.DECRYPT_MODE);
|
}
|
|
private static String doRSA(String content, String key, KeyTypeEnum keyType, RSATypeEnum rsaType) {
|
if (StringUtils.isEmpty(key)) {
|
throw new RuntimeException(keyType.getDesc() + "为空, 请设置");
|
}
|
try {
|
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
|
// 数据加密
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
cipher.init(rsaType.getCipherMode(), keyType.getKeyFunction().apply(keyFactory, key));
|
return rsaType.returnFunction.apply(cipher, content);
|
} catch (Exception e) {
|
throw new RuntimeException(rsaType.getErrMsg(), e);
|
}
|
}
|
|
@FunctionalInterface
|
public interface MyBiFunction<T, U, R> {
|
R apply(T t, U u) throws Exception;
|
|
default <V> MyBiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) throws Exception {
|
Objects.requireNonNull(after);
|
return (T t, U u) -> after.apply(apply(t, u));
|
}
|
}
|
|
@Getter
|
@AllArgsConstructor
|
public enum KeyTypeEnum {
|
PRIVATE_KEY(0, "私钥",
|
(keyFactory, key) -> keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(key)))),
|
PUBLIC_KEY(1, "公钥",
|
(keyFactory, key) -> keyFactory.generatePublic(new X509EncodedKeySpec(Base64.decodeBase64(key)))),
|
|
;
|
|
private Integer code;
|
private String desc;
|
private MyBiFunction<KeyFactory, String, Key> keyFunction;
|
}
|
|
@Getter
|
@AllArgsConstructor
|
public enum RSATypeEnum {
|
DECRYPT_MODE(0, "解密模式", Cipher.DECRYPT_MODE, "RSA解密失败",
|
(cipher, txt) -> new String(cipher.doFinal(Base64.decodeBase64(txt)))),
|
ENCRYPT_MODE(1, "加密模式", Cipher.ENCRYPT_MODE, "RSA加密失败",
|
(cipher, txt) -> Base64.encodeBase64String(cipher.doFinal(txt.getBytes(CHARSET)))),
|
|
;
|
|
private Integer code;
|
private String desc;
|
private int cipherMode;
|
private String errMsg;
|
private MyBiFunction<Cipher, String, String> returnFunction;
|
}
|
}
|