提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
一、参数加密
public static String buildRequest(String params, String privateKey, String publicKey) {
// 时间戳
String timestamp = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
// 构建签名
TreeMap<String, String> map = new TreeMap<>();
map.put("params", params);
map.put("timestamp", timestamp);
// 待签名明文
String plain = toSortedString(map);
// 做md5摘要处理
String md5 = MD5.digest(plain, StandardCharsets.UTF_8);
try {
// 签名
String sign = sign(md5, privateKey);
map.put("sign", sign);
String aesKey = generateAesKey(); // 生成16位AES密钥
params = encryptAES(params, aesKey);
map.replace("params", params); // 对params进行AES加密, 并替换进map
// 对AES密钥进行RSA加密, 并将加密后的AES密钥加入map
aesKey = encryptRSA(aesKey, publicKey);
map.put("key", aesKey); // 用公钥加密
}catch (Exception e){
log.error("商户API签名失败,请检查具体的原因",e);
}
return JSON.toJSONString(map);
}
private static String toSortedString(TreeMap<String, String> map) {
StringBuilder sb = new StringBuilder();
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (true) {
Map.Entry<String, String> entry = it.next();
sb.append(entry.getKey()).append('=').append(entry.getValue());
if (it.hasNext()) {
sb.append('&');
} else {
break;
}
}
return sb.toString();
}
/**
* RSA签名
* @param data
* @param privateKeyStr
* @return
*/
public static String sign(String data, String privateKeyStr) throws Exception {
log.info("sign data:{},privateKeyStr:{}",data,privateKeyStr);
PrivateKey privateKey = getPrivateKey(privateKeyStr);
Signature signature = Signature.getInstance(algorithmStr);
signature.initSign(privateKey);
signature.update(data.getBytes(StandardCharsets.UTF_8));
return new String(Base64.encodeBase64(signature.sign()));
}
/**
* 私钥字符串转PrivateKey实例
*
* @param privateKey 私钥字符串
* @return
*/
public static PrivateKey getPrivateKey(String privateKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
return keyFactory.generatePrivate(keySpec);
}
/**
* 生成16位不重复的随机数,含数字+大小写
* 作为AES密钥使用
*/
private static String generateAesKey() {
StringBuilder uid = new StringBuilder ();
//产生16位的强随机数
Random rd = new SecureRandom ();
for (int i = 0; i < 16; i++) {
int type = rd.nextInt (3);
switch (type) {
case 0:
uid.append (rd.nextInt (10));
break;
case 1:
uid.append ((char) (rd.nextInt (25) + 65));
break;
case 2:
uid.append ((char) (rd.nextInt (25) + 97));
break;
default:
break;
}
}
return uid.toString ();
}
/**
* AES加密
*
* @param content 需要加密的内容
* @param strKey 加密秘钥
* @return 加密后的比特流
*/
private static String encryptAES(String content, String strKey) throws Exception {
SecretKeySpec key = new SecretKeySpec (strKey.getBytes (), "AES"); //NOSONAR
Cipher cipher = Cipher.getInstance ("AES");
byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
cipher.init (Cipher.ENCRYPT_MODE, key);
return byte2hex(cipher.doFinal(byteContent));
}
/**
* byte[]转16进制string
* @param b
* @return
*/
private static String byte2hex(byte[] b) {
StringBuilder hs = new StringBuilder ();
for (byte bi : b) {
String temp = Integer.toHexString (bi & 0XFF);
if (temp.length () == 1) {
hs.append ("0");
}
hs.append (temp);
}
return hs.toString ().toUpperCase ();
}
/**
* RSA加密
* @param data
* @param publicKeyStr
* @return
*/
public static String encryptRSA(String data, String publicKeyStr) throws Exception {
// 对数据加密
PublicKey publicKey = getPublicKey(publicKeyStr);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init (Cipher.ENCRYPT_MODE, publicKey);
return byte2hex(cipher.doFinal (data.getBytes ()));
}
加密原理:
生成一个随机串,用该随机串对请求参数进行非对称加密,然后再对该随机串进行对称加密,生成签名和验签过程中,对参数进行了排序。
二、参数解密
public static String parseRequest(String strReq, String privateKey, String publicKey) {
//log.info("params:{},privateKey:{},publicKey:{}",strReq,privateKey,publicKey);
JSONObject obj = JSON.parseObject(strReq);
String params = obj.getString("params"); // 用 aes加密后的密文
String aesKey = obj.getString("key"); // 用公钥加密的密文
String sign = obj.getString("sign");
String timestamp = obj.getString("timestamp");
try {
// 对AESkey进行RSA解密
aesKey = decryptRSA(aesKey, privateKey); // 解密之后的aesKey明文
// 对params进行AES解密
params = decryptAES(params, aesKey); // 用aes解密为明文
// 构建验签明文
TreeMap<String, String> map = new TreeMap<>();
map.put("params", params);
map.put("timestamp", timestamp);
String plain = toSortedString(map);
// 做md5摘要
String md5 = MD5.digest(plain, StandardCharsets.UTF_8);
// 验签
boolean passed = verify(md5, publicKey, sign);
if (!passed) {
throw new RuntimeException("merchantAPI 验签失败");
}
}catch (Exception e){
log.error("商户API验签失败,请检查具体的原因",e);
}
return params;
}
/**
* RSA解密
* @param message
* @param privateKeyStr
* @return
*/
public static String decryptRSA(String message, String privateKeyStr) throws Exception {
PrivateKey privateKey = getPrivateKey(privateKeyStr);
byte[] bytes = hex2byte(message);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(2, privateKey);
byte[] result = cipher.doFinal(bytes);
return new String(result);
}
/**
* AES解密
*
* @param content 待解密内容
* @param strKey 解密密钥
* @return 解密后的
*/
private static String decryptAES(String content, String strKey) throws Exception {
SecretKeySpec key = new SecretKeySpec (strKey.getBytes (), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init (Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(hex2byte(content)));
}
/**
* 验签
* @param sign
* @param md5
* @param publicKeyStr
* @return
*/
public static boolean verify(String md5, String publicKeyStr,String sign) throws Exception {
log.info("verify data:{},publicKeyStr:{},sign:{}",md5,publicKeyStr,sign);
PublicKey publicKey = getPublicKey(publicKeyStr);
byte[] signBytes = Base64.decodeBase64(sign);
Signature signature = Signature.getInstance(algorithmStr);
signature.initVerify(publicKey);
signature.update(md5.getBytes(StandardCharsets.UTF_8));
return signature.verify(signBytes);
}
/**
* 公钥字符串转PrivateKey实例
*
* @param publicKey 公钥字符串
* @return
*/
public static PublicKey getPublicKey(String publicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] decodedKey =Base64.decodeBase64(publicKey.getBytes());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
return keyFactory.generatePublic(keySpec);
}
三、生成公钥私钥
/**
* 获取密钥对
*
* @return 密钥对
*/
public static KeyPair getKeyPair() {
KeyPair keyPair = null;
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(1024);
keyPair = generator.generateKeyPair();
} catch (Exception e) {
log.error("getKeyPair: ", e);
}
return keyPair;
}
public static void testGenerateKeyPair() {
// 生成密钥对
KeyPair keyPair = getKeyPair();
String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));
System.out.println("私钥:" + privateKey);
System.out.println("公钥:" + publicKey);
}