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.*;
/**
*
* 用于加密解密的各种工具集
*
*
* @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 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 sortMap, String md5Key) throws Exception {
// 按ASCII码升序组成签名参数字符串
SortedMap sortedMap = new TreeMap(sortMap);
Set 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 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();
}
}