package com.nova.sankuai.domain.api.doudouqian;
|
|
import com.alibaba.fastjson.JSONObject;
|
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.lang3.StringUtils;
|
|
import javax.crypto.Cipher;
|
import javax.crypto.spec.SecretKeySpec;
|
import java.io.ByteArrayOutputStream;
|
import java.nio.charset.StandardCharsets;
|
import java.security.Key;
|
import java.security.KeyFactory;
|
import java.security.MessageDigest;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
import java.util.*;
|
|
/**
|
* <p>
|
* 用于加密解密的各种工具集
|
* </p>
|
*
|
* @author Tiangle
|
* @since 2022/4/26
|
**/
|
public class DdqSignUtil {
|
|
/**
|
* @param bizDataJson 业务数据
|
* @param channelCode 机构申请得到的渠道号
|
* @param publicKey 公钥
|
* @param md5Key MD5秘钥
|
* @return
|
* @throws Exception
|
*/
|
public static String buildRequest(String bizDataJson, String channelCode, String publicKey, String md5Key) throws Exception {
|
// aesKey
|
String aesKey = DdqSignUtil.getRandom(16, true);
|
// timeStamp
|
String timestamp = System.currentTimeMillis() / 1000 + "";
|
// biz_data
|
String bizEncryptData = DdqSignUtil.encrypt(bizDataJson, aesKey);
|
// secretKey
|
String secretKey = DdqSignUtil.encryptByPublicKey(aesKey, publicKey);
|
|
Map<String, String> sortMap = new HashMap<>();
|
sortMap.put("channel_code", channelCode);
|
sortMap.put("timestamp", timestamp);
|
sortMap.put("biz_data", bizEncryptData);
|
sortMap.put("secret_key", secretKey);
|
String sign = DdqSignUtil.createSign(sortMap, md5Key);
|
|
// 构建请求参数
|
JSONObject params = new JSONObject();
|
params.put("sign", sign);
|
params.put("secret_key", secretKey);
|
params.put("biz_data", bizEncryptData);
|
params.put("channel_code", channelCode);
|
params.put("timestamp", timestamp);
|
return params.toString();
|
}
|
|
/**
|
* 生成指定位数的随机字符串
|
*
|
* @param length 长度
|
* @param useAlphabet 是否使用字母
|
* @return String
|
*/
|
public static String getRandom(int length, boolean useAlphabet) {
|
StringBuffer buffer = new StringBuffer();
|
String s = "0123456789" + (useAlphabet ? "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" : "");
|
for (int i = 0; i < length; i++) {
|
buffer.append(s.charAt(new Random().nextInt(s.length())));
|
}
|
return buffer.toString();
|
}
|
|
/**
|
* AES 加密
|
*
|
* @param content 待加密内容
|
* @param key 秘钥
|
* @return String 密文
|
* @throws Exception EX
|
*/
|
public static String encrypt(String content, String key) throws Exception {
|
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
|
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"));
|
byte[] bytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
|
return Base64.encodeBase64String(bytes);
|
}
|
|
/**
|
* AES 解密
|
*
|
* @param encryptBytes 密文
|
* @param key 秘钥
|
* @return String 明文
|
* @throws Exception EX
|
*/
|
public static String decrypt(String encryptBytes, String key) throws Exception {
|
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
|
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "AES"));
|
byte[] decryptBytes = cipher.doFinal(Base64.decodeBase64(encryptBytes));
|
return new String(decryptBytes);
|
}
|
|
/**
|
* 用公钥加密
|
*
|
* @param value 要加密数据
|
* @param key 密钥
|
* @return byte[]
|
* @throws Exception RSA异常
|
*/
|
public static String encryptByPublicKey(String value, String key) throws Exception {
|
byte[] data = getBytes(value);
|
// 对公钥解密
|
byte[] keyBytes = Base64.decodeBase64(key);
|
// 取公钥
|
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
|
// 对数据解密
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
return Base64.encodeBase64String(doFinalBySegment(cipher, data, true));
|
}
|
|
/**
|
* 获取字符串的字节数组
|
*
|
* @param content 字符串
|
* @return byte[]
|
*/
|
public static byte[] getBytes(String content) {
|
return content.getBytes(StandardCharsets.UTF_8);
|
}
|
|
private static byte[] doFinalBySegment(Cipher cipher, byte[] source, boolean isEncode) throws Exception {
|
ByteArrayOutputStream out = null;
|
try {
|
int blockSize = isEncode ? 117 : 128;
|
if (source.length <= blockSize) {
|
return cipher.doFinal(source);
|
}
|
out = new ByteArrayOutputStream();
|
int offsetIndex = 0, offset = 0, sourceLength = source.length;
|
while (sourceLength - offset > 0) {
|
int size = Math.min(sourceLength - offset, blockSize);
|
byte[] buffer = cipher.doFinal(source, offset, size);
|
out.write(buffer, 0, buffer.length);
|
offsetIndex++;
|
offset = offsetIndex * blockSize;
|
}
|
return out.toByteArray();
|
} finally {
|
IOUtils.closeQuietly(out);
|
}
|
}
|
|
/**
|
* MD5 Encrypt
|
*
|
* @param info 待加密字符串
|
* @return String
|
* @throws Exception 加密异常
|
*/
|
public static String md5Encrypt(String info) throws Exception {
|
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
md5.update(info.getBytes(StandardCharsets.UTF_8));
|
byte[] result = md5.digest();
|
StringBuffer buffer = new StringBuffer();
|
for (byte b : result) {
|
String str = Integer.toHexString(b & 0xFF);
|
if (str.length() == 1) {
|
buffer.append("0");
|
}
|
buffer.append(str);
|
}
|
return buffer.toString().toUpperCase();
|
}
|
|
/**
|
* 创建签名字符串
|
*
|
* @param sortMap 用于创建签名的参数集合
|
* @param md5Key MD5加密秘钥
|
* @return
|
* @throws Exception
|
*/
|
public static String createSign(Map<String, String> sortMap, String md5Key) throws Exception {
|
// 按ASCII码升序组成签名参数字符串
|
SortedMap sortedMap = new TreeMap(sortMap);
|
Set<String> set = sortedMap.keySet();
|
StringBuffer tempSign = new StringBuffer();
|
for (String o : set) {
|
tempSign.append(o).append("=").append(sortedMap.get(o));
|
tempSign.append("&");
|
}
|
tempSign.deleteCharAt(tempSign.length() - 1);
|
// 获取加密签名字符串
|
String sign = md5Encrypt(tempSign + md5Key);
|
return sign;
|
}
|
|
/**
|
* 用私钥解密
|
*
|
* @param value 密文
|
* @param key 密钥
|
* @return String
|
* @throws Exception RSA异常
|
*/
|
public static String decryptByPrivateKey(String value, String key) throws Exception {
|
byte[] data = Base64.decodeBase64(value);
|
// 对私钥解密
|
byte[] keyBytes = Base64.decodeBase64(key);
|
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
|
// 对数据解密
|
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
return getString(doFinalBySegment(cipher, data, false));
|
}
|
|
/**
|
* 转换字节数组为字符串
|
*
|
* @param content 字节数组
|
* @return String
|
*/
|
public static String getString(byte[] content) {
|
return new String(content, StandardCharsets.UTF_8);
|
}
|
|
/**
|
* 查询参数
|
*
|
* @param paramMap
|
* @param name
|
* @return String
|
*/
|
public static String getValue(Map<String, Object> paramMap, String name) {
|
if (paramMap == null || paramMap.isEmpty() || StringUtils.isBlank(name) || !paramMap.containsKey(name)) {
|
return null;
|
}
|
Object obj = paramMap.get(name);
|
if (obj == null) {
|
return null;
|
}
|
String value = obj.toString();
|
return value.trim();
|
}
|
}
|