签名产生规则:使用字母排序后拼接待加密字符串。形如:key1=value1&key2=value2&key3=value3,使用公钥结合RSA加密算法进行加密,传输中对密文使用URL编码。
公私钥地址
//D:/workspaces/xxx/rsa/
@Value("${RSA.pubKeyFile}")
private String pubKeyFile;
//D:/workspaces/xxx/rsa/
@Value("${RSA.priKeyFile}")
private String priKeyFile;
生成公私钥文件
public ObjectRestResponse<Object> generateKey(String platformCode) throws Exception {
KeyPair keyPair = RSAPassWordUtils.generateKeyPair();
// 获取 公钥 和 私钥
PublicKey pubKey = keyPair.getPublic();
PrivateKey priKey = keyPair.getPrivate();
// 保存 公钥 和 私钥
File file = new File(pubKeyFile+platformCode);
if (!file.exists()){
file.mkdirs();
}
RSAPassWordUtils.saveKeyForEncodedBase64(pubKey, new File(pubKeyFile+platformCode+"/pub.txt"));
RSAPassWordUtils.saveKeyForEncodedBase64(priKey, new File(priKeyFile+platformCode+"/pri.txt"));
System.out.println("公私钥文件路径:"+pubKeyFile+platformCode+"/pub.txt");
return new ObjectRestResponse<>().data(true);
}
私钥加密
public ObjectRestResponse<Object> priKeyEncrypt(@RequestBody ThirdPartyVo thirdPartyVo) throws Exception {
Map<String, Object> map = BeanUtil.beanToMap(thirdPartyVo);
String jsonObject = RSAPassWordUtils.sort(map,"&");
// JSON parse = JSONUtil.parse(thirdPartyVo);
// String jsonObject = parse.toString();
log.info("加密对象=============="+jsonObject);
File path = new File(priKeyFile + thirdPartyVo.getPlatformCode());
if (!path.exists()){
path.mkdirs();
}
File file = new File(priKeyFile + thirdPartyVo.getPlatformCode() + "/pri.txt");
String base64 = IOUtils.readFile(file);
String signPassword = RSAPassWordUtils.priKeyencrypt(jsonObject, base64);
return new ObjectRestResponse<>().data(signPassword);
}
package com.tomato.platform.utils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONUtil;
import com.tomato.platform.model.vo.ThirdPartyVo;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
public class RSAPassWordUtils {
/**
* 算法名称
*/
private static final String ALGORITHM = "RSA";
/** *//**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/** *//**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 256;
/**
* 密钥长度
*/
private static final int KEY_SIZE = 2048;
/**
* 随机生成密钥对(包含公钥和私钥)
*/
public static KeyPair generateKeyPair() throws Exception {
// 获取指定算法的密钥对生成器
KeyPairGenerator gen = KeyPairGenerator.getInstance(ALGORITHM);
// 初始化密钥对生成器(指定密钥长度, 使用默认的安全随机数源)
gen.initialize(KEY_SIZE);
// 随机生成一对密钥(包含公钥和私钥)
return gen.generateKeyPair();
}
/**
* 将 公钥/私钥 编码后以 Base64 的格式保存到指定文件
*/
public static void saveKeyForEncodedBase64(Key key, File keyFile) throws IOException {
// 获取密钥编码后的格式
byte[] encBytes = key.getEncoded();
// 转换为 Base64 文本
String encBase64 = new BASE64Encoder().encode(encBytes);
// 保存到文件
IOUtils.writeFile(encBase64, keyFile);
}
/**
* 根据公钥的 Base64 文本创建公钥对象
*/
public static PublicKey getPublicKey(String pubKeyBase64) throws Exception {
// 把 公钥的Base64文本 转换为已编码的 公钥bytes
byte[] encPubKey = new BASE64Decoder().decodeBuffer(pubKeyBase64);
// 创建 已编码的公钥规格
X509EncodedKeySpec encPubKeySpec = new X509EncodedKeySpec(encPubKey);
// 获取指定算法的密钥工厂, 根据 已编码的公钥规格, 生成公钥对象
return KeyFactory.getInstance(ALGORITHM).generatePublic(encPubKeySpec);
}
/**
* 根据私钥的 Base64 文本创建私钥对象
*/
public static PrivateKey getPrivateKey(String priKeyBase64) throws Exception {
// 把 私钥的Base64文本 转换为已编码的 私钥bytes
byte[] encPriKey = new BASE64Decoder().decodeBuffer(priKeyBase64);
// 创建 已编码的私钥规格
PKCS8EncodedKeySpec encPriKeySpec = new PKCS8EncodedKeySpec(encPriKey);
// 获取指定算法的密钥工厂, 根据 已编码的私钥规格, 生成私钥对象
return KeyFactory.getInstance(ALGORITHM).generatePrivate(encPriKeySpec);
}
/**
* 公钥加密数据
*/
public static byte[] encrypt(byte[] plainData, PublicKey pubKey) throws Exception {
// 获取指定算法的密码器
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 初始化密码器(公钥加密模型)
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
// 加密数据, 返回加密后的密文
return cipher.doFinal(plainData);
}
/**
* 私钥解密数据
*/
public static byte[] decrypt(byte[] cipherData, PrivateKey priKey) throws Exception {
// 获取指定算法的密码器
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 初始化密码器(私钥解密模型)
cipher.init(Cipher.DECRYPT_MODE, priKey);
// 解密数据, 返回解密后的明文
return cipher.doFinal(cipherData);
}
public static String priKeyencrypt( String str, String privateKey ) throws Exception{
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, priKey);
String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
public static String pubKeydecrypt(String str, String publicKey) throws Exception{
//64位解码加密后的字符串
byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pubKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}
/**
* 使用公钥解密
* @param data 已加密数据
* @see decByPriKey
*/
public static String decryptByPublicKey(String data,String pubKey) {
// 加密
String str = "";
try {
byte[] pubByte = Base64.decodeBase64(pubKey.getBytes("UTF-8"));
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubByte);
KeyFactory fac = KeyFactory.getInstance("RSA");
RSAPublicKey rsaPubKey = (RSAPublicKey) fac.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, rsaPubKey);
byte[] dataBytes = Base64.decodeBase64(data);
int inputLen = dataBytes.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offset = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offset > 0) {
if (inputLen - offset > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
str = new String(decryptedData);
} catch (Exception e) {
e.printStackTrace();
}
// 解密后的内容
return str;
}
public static Boolean auth(ThirdPartyVo thirdPartyVo,Map<String, String> map) throws Exception {
ThirdPartyVo partyVo = BeanUtil.mapToBean(map, ThirdPartyVo.class, false, new CopyOptions());
if (thirdPartyVo.getPlatformCode().equals(partyVo.getPlatformCode()) && thirdPartyVo.getPhone().equals(partyVo.getPhone())
&&thirdPartyVo.getTimestamp().equals(partyVo.getTimestamp())
){
if (thirdPartyVo.getAddress() != null && thirdPartyVo.getBusiWebsite() != null){
if (!thirdPartyVo.getAddress().equals(partyVo.getAddress()) || !thirdPartyVo.getBusiWebsite().equals(partyVo.getBusiWebsite())){
throw new Exception("地址或网址错误!");
}
}
}else {
throw new Exception("请检查平台商户编码、时间戳、电话号码是否正确!!");
}
return true;
}
/**
**使用字母排序后拼接待加密字符串。形如:key1=value1&key2=value2&key3=value3,
** separator参数表示分隔符"&"
**/
public static String sort(Map<String, Object> params, String separator) throws Exception {
if (null == params || params.isEmpty()) {
throw new Exception("接口参数不能为空。");
}
List<Map.Entry<String, Object>> entrys = new ArrayList<>(params.entrySet());
Collections.sort(entrys, Comparator.comparing(Map.Entry::getKey));
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Object> entry : entrys) {
String key = entry.getKey();
if (key.equalsIgnoreCase("sign")) {
continue;
}
if (entry.getValue() != null){
String value = entry.getValue().toString();
sb.append(key).append("=").append(value).append(separator);
}
}
return sb.substring(0, sb.length() - separator.length());
}
/**
**将key1=value1&key2=value2&key3=value3转换为MAP
**/
public static Map<String, String> getMap(String params) {
HashMap<String, String> map = new HashMap<>();
int start = 0, len = params.length();
while (start < len) {
int i = params.indexOf('&', start);
if (i == -1) {
i = params.length(); // 此时处理最后的键值对
}
String keyValue = params.substring(start, i);
int j = keyValue.indexOf('=');
String key = keyValue.substring(0, j);
String value = keyValue.substring(j + 1, keyValue.length());
map.put(key, value);
if (i == params.length()) {
break;
}
start = i + 1; // index+1 为下一个键值对的起始位置
}
return map;
}
}