From cff0ee7a9cc9f7842582b3c24dfdaa301a062345 Mon Sep 17 00:00:00 2001 From: "PC-202302260912\\Administrator" <1769111741@qq.com> Date: Wed, 29 Nov 2023 11:46:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E4=B8=830.1=E6=96=B0=E6=B8=A0?= =?UTF-8?q?=E9=81=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AiWanRechargeController.java | 1 + .../controller/AnJiuRechargeController.java | 1 + .../controller/CHGnRechargeController.java | 1 + .../controller/DuoYouRechargeController.java | 1 + .../jmfy/controller/DyRechargeController.java | 2 +- .../controller/HaoFanRechargeController.java | 1 + .../controller/HaoGameRechargeController.java | 1 + .../controller/KTGameRechargeController.java | 1 + .../MHTGnWebRechargeController.java | 1 + .../MHTHwNetRechargeController.java | 1 + .../controller/MHTHwRechargeController.java | 1 + .../controller/MHTRechargeController.java | 1 + .../controller/MHTZFGnRechargeController.java | 1 + .../controller/QYGameRechargeController.java | 1 + .../controller/QuickRechargeController.java | 2 +- .../controller/QuickRechargeController2.java | 2 +- .../jmfy/controller/RechargeController.java | 2 +- .../controller/U1GameRechargeController.java | 104 +++++++ .../jmfy/controller/XPRechargeController.java | 1 + .../controller/XPiosRechargeController.java | 2 +- .../controller/XqTenthRechargeController.java | 20 ++ .../controller/YouGuRechargeController.java | 4 - .../controller/YouGuXQRechargeController.java | 1 + .../controller/YxylRechargeController.java | 2 +- .../java/com/jmfy/paramBean/PaySdkEnum.java | 1 + src/main/java/com/jmfy/util/Base64.java | 278 ++++++++++++++++++ src/main/java/com/jmfy/util/RSA.java | 60 ++++ .../java/com/jmfy/util/SignSerialization.java | 248 ++++++++++++++++ 28 files changed, 732 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/jmfy/controller/U1GameRechargeController.java create mode 100644 src/main/java/com/jmfy/controller/XqTenthRechargeController.java create mode 100644 src/main/java/com/jmfy/util/Base64.java create mode 100644 src/main/java/com/jmfy/util/RSA.java create mode 100644 src/main/java/com/jmfy/util/SignSerialization.java diff --git a/src/main/java/com/jmfy/controller/AiWanRechargeController.java b/src/main/java/com/jmfy/controller/AiWanRechargeController.java index 1c57dfb..de91c57 100644 --- a/src/main/java/com/jmfy/controller/AiWanRechargeController.java +++ b/src/main/java/com/jmfy/controller/AiWanRechargeController.java @@ -18,6 +18,7 @@ import java.util.*; * 爱玩游戏支付 * @author hj */ +@Deprecated @RestController public class AiWanRechargeController { diff --git a/src/main/java/com/jmfy/controller/AnJiuRechargeController.java b/src/main/java/com/jmfy/controller/AnJiuRechargeController.java index 1468ff0..3b89c05 100644 --- a/src/main/java/com/jmfy/controller/AnJiuRechargeController.java +++ b/src/main/java/com/jmfy/controller/AnJiuRechargeController.java @@ -19,6 +19,7 @@ import java.util.*; /** * 安久 */ +@Deprecated @RestController public class AnJiuRechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/CHGnRechargeController.java b/src/main/java/com/jmfy/controller/CHGnRechargeController.java index b66c85d..10334f5 100644 --- a/src/main/java/com/jmfy/controller/CHGnRechargeController.java +++ b/src/main/java/com/jmfy/controller/CHGnRechargeController.java @@ -27,6 +27,7 @@ import java.util.TreeMap; * @date 2021/6/8 * @discribe 草花支付接口 */ +@Deprecated @RestController public class CHGnRechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/DuoYouRechargeController.java b/src/main/java/com/jmfy/controller/DuoYouRechargeController.java index 36b93e8..5ea1d8c 100644 --- a/src/main/java/com/jmfy/controller/DuoYouRechargeController.java +++ b/src/main/java/com/jmfy/controller/DuoYouRechargeController.java @@ -18,6 +18,7 @@ import java.util.TreeMap; /** * 多游游戏支付 */ +@Deprecated @RestController public class DuoYouRechargeController { diff --git a/src/main/java/com/jmfy/controller/DyRechargeController.java b/src/main/java/com/jmfy/controller/DyRechargeController.java index b57c866..04e13d8 100644 --- a/src/main/java/com/jmfy/controller/DyRechargeController.java +++ b/src/main/java/com/jmfy/controller/DyRechargeController.java @@ -27,7 +27,7 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; - +@Deprecated @RestController public class DyRechargeController { diff --git a/src/main/java/com/jmfy/controller/HaoFanRechargeController.java b/src/main/java/com/jmfy/controller/HaoFanRechargeController.java index cd574f9..abfc873 100644 --- a/src/main/java/com/jmfy/controller/HaoFanRechargeController.java +++ b/src/main/java/com/jmfy/controller/HaoFanRechargeController.java @@ -17,6 +17,7 @@ import java.util.*; /** * 浩凡游戏 */ +@Deprecated @RestController public class HaoFanRechargeController { diff --git a/src/main/java/com/jmfy/controller/HaoGameRechargeController.java b/src/main/java/com/jmfy/controller/HaoGameRechargeController.java index c205441..23e05fb 100644 --- a/src/main/java/com/jmfy/controller/HaoGameRechargeController.java +++ b/src/main/java/com/jmfy/controller/HaoGameRechargeController.java @@ -32,6 +32,7 @@ import java.util.*; /** * 好游戏 */ +@Deprecated @RestController public class HaoGameRechargeController { diff --git a/src/main/java/com/jmfy/controller/KTGameRechargeController.java b/src/main/java/com/jmfy/controller/KTGameRechargeController.java index 5a4e02c..1dc7748 100644 --- a/src/main/java/com/jmfy/controller/KTGameRechargeController.java +++ b/src/main/java/com/jmfy/controller/KTGameRechargeController.java @@ -28,6 +28,7 @@ import java.util.*; /** * KT游戏 */ +@Deprecated @RestController public class KTGameRechargeController { diff --git a/src/main/java/com/jmfy/controller/MHTGnWebRechargeController.java b/src/main/java/com/jmfy/controller/MHTGnWebRechargeController.java index ea23248..674795e 100644 --- a/src/main/java/com/jmfy/controller/MHTGnWebRechargeController.java +++ b/src/main/java/com/jmfy/controller/MHTGnWebRechargeController.java @@ -30,6 +30,7 @@ import java.util.*; * @date 2021/3/15 * @discribe 国内先遣 */ +@Deprecated @RestController public class MHTGnWebRechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/MHTHwNetRechargeController.java b/src/main/java/com/jmfy/controller/MHTHwNetRechargeController.java index be83b69..f87fba6 100644 --- a/src/main/java/com/jmfy/controller/MHTHwNetRechargeController.java +++ b/src/main/java/com/jmfy/controller/MHTHwNetRechargeController.java @@ -33,6 +33,7 @@ import java.util.*; * time 平台支付时间 * sign 签名 */ +@Deprecated @RestController public class MHTHwNetRechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/MHTHwRechargeController.java b/src/main/java/com/jmfy/controller/MHTHwRechargeController.java index f32e5c0..18ed821 100644 --- a/src/main/java/com/jmfy/controller/MHTHwRechargeController.java +++ b/src/main/java/com/jmfy/controller/MHTHwRechargeController.java @@ -34,6 +34,7 @@ import java.util.*; * time 平台支付时间 * sign 签名 */ +@Deprecated @RestController public class MHTHwRechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/MHTRechargeController.java b/src/main/java/com/jmfy/controller/MHTRechargeController.java index 49af8cb..111b98f 100644 --- a/src/main/java/com/jmfy/controller/MHTRechargeController.java +++ b/src/main/java/com/jmfy/controller/MHTRechargeController.java @@ -34,6 +34,7 @@ import java.util.*; * time 平台支付时间 * sign 签名 */ +@Deprecated @RestController public class MHTRechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/MHTZFGnRechargeController.java b/src/main/java/com/jmfy/controller/MHTZFGnRechargeController.java index d85d904..a2bcb8a 100644 --- a/src/main/java/com/jmfy/controller/MHTZFGnRechargeController.java +++ b/src/main/java/com/jmfy/controller/MHTZFGnRechargeController.java @@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletRequest; * @date 2021/6/8 * @discribe */ +@Deprecated @RestController public class MHTZFGnRechargeController extends MHTGnWebRechargeController { diff --git a/src/main/java/com/jmfy/controller/QYGameRechargeController.java b/src/main/java/com/jmfy/controller/QYGameRechargeController.java index f2d26cb..d9866af 100644 --- a/src/main/java/com/jmfy/controller/QYGameRechargeController.java +++ b/src/main/java/com/jmfy/controller/QYGameRechargeController.java @@ -24,6 +24,7 @@ import java.util.*; /** * 乾游支付回调 */ +@Deprecated @RestController public class QYGameRechargeController { diff --git a/src/main/java/com/jmfy/controller/QuickRechargeController.java b/src/main/java/com/jmfy/controller/QuickRechargeController.java index 58dbe3e..df84ff1 100644 --- a/src/main/java/com/jmfy/controller/QuickRechargeController.java +++ b/src/main/java/com/jmfy/controller/QuickRechargeController.java @@ -19,7 +19,7 @@ import java.io.StringReader; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; - +@Deprecated @RestController public class QuickRechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/QuickRechargeController2.java b/src/main/java/com/jmfy/controller/QuickRechargeController2.java index a8793c9..7210063 100644 --- a/src/main/java/com/jmfy/controller/QuickRechargeController2.java +++ b/src/main/java/com/jmfy/controller/QuickRechargeController2.java @@ -19,7 +19,7 @@ import java.io.StringReader; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; - +@Deprecated @RestController public class QuickRechargeController2 { @Resource diff --git a/src/main/java/com/jmfy/controller/RechargeController.java b/src/main/java/com/jmfy/controller/RechargeController.java index 78ddf48..0fd7a03 100644 --- a/src/main/java/com/jmfy/controller/RechargeController.java +++ b/src/main/java/com/jmfy/controller/RechargeController.java @@ -27,7 +27,7 @@ import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; - +@Deprecated @RestController public class RechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/U1GameRechargeController.java b/src/main/java/com/jmfy/controller/U1GameRechargeController.java new file mode 100644 index 0000000..2950d64 --- /dev/null +++ b/src/main/java/com/jmfy/controller/U1GameRechargeController.java @@ -0,0 +1,104 @@ +package com.jmfy.controller; + +import com.jmfy.paramBean.PaySdkEnum; +import com.jmfy.util.JsonUtil; +import com.jmfy.util.MD5Util; +import com.jmfy.util.SignSerialization; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 自在封神游戏 + */ +@RestController +public class U1GameRechargeController { + + private static final String PAY_PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKRZpZWZJIjEy/MDlwPijq9dTVLoXpQaLlSYfzgAEBtO/5zVgtED/2r0mSrMCY561/cY7tw/FkI5ywJ+HcR+OZ4ch/05J8LMnRqFQJTyoytzR4r9mMOTq5LlMianUYLJcoTeNCLdb5qMeuLYe/8B/8Q1PAUFmxIs5yz/gPZlqWVxAgMBAAECgYAwvt4b5tYtMqGDLHdoEZRccwHyKzWSG8nOEYT6KRqd3up1q+Ym9FaXdIDRbr8O4WSYx25hKN0DO3z4+kr98qpHv0DJLVQlg/9QHfPcprP6vXKMXwf1OMkI4k7m1IwZUp2N/MNBH0WfMnWdqkZlINysbr6wK+kkwnz5q7tS/vOkeQJBANdQFSaKVmHCUWDV3Ndr0/bSphDEIZjn9c7RS86pz19ZPaeyy1le5AqvHRZB9WyMy3j8o9RzBz1oJQniyvwUAGcCQQDDaDVuqAcIQKQ/1lZMQNTfc8pTvL0nHhivILObUq0wUr6VE46+h9fhAUSJCptOrPtghDHFl5xdSRWYJl1tw2RnAkBRhDQ9vyotINCGhPFzbZN2YxIUTu0ZYtihUIQO3iNwyeyZzQtH7rEPinTMtHQigLuYNq4gBNy81u0O7RpEjZ4JAkEAidWz+v4jF7shILZ74QXKImR2z2JOuo0MNFwI1QMYjwGO1XEaO2Nu75QJV/FXY8O4/XfB8/LhpRusU8qcFJTC+QJAcWOeo2ZFf0E6EOmjfbTVdhUybCKuLdW16MHg0MoRulKdYSKKNZCd5u4BUAQCRLLeo2hTYXUHVdSgG5AnM4oqpA=="; + + public static final String NOTIFY_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHaFanJLyR4PsHRGIImpX6w7zsA9s3rCcos6kwZit5WMiJA3f1KQf8u+u9wj5OWjPjSkir6YsxVyp1iu+a6yaWvrTe0OW3TLMPIcZog0HDfyet8+flvxbbXQpvG2itr8hoGQTfjMWM5AzghTXN8IbfwrYVr39ebbW8yG1wcxBr/QIDAQAB"; + + private static final Logger LOGGER = LoggerFactory.getLogger(U1GameRechargeController.class); + + @RequestMapping(value = "/u1gameCallback") + public String u1gameCallback(HttpServletRequest request) throws Exception { + return callback(request, NOTIFY_PUBLIC_KEY); + } + + @RequestMapping(value = "/u1gameGetSign") + public String u1gameGetSign(HttpServletRequest request) throws Exception { + // SignSerialization为ICC SDK 工具类(游戏接入方可直接使用) + SignSerialization signSerialization = new SignSerialization(); + signSerialization.setPrivateKey(PAY_PRIVATE_KEY); + // 游戏客户端传递过来的订单ID等信息 + String productID = request.getParameter("productID"); + // 游戏支付业务编号(游戏标识),有且唯一,请在SDK提供的密钥文件下readme.txt中查看 + String service = "21930001"; + /* + * 模拟游戏客户端传递过来的支付下单数据 + * 下单数据示例: + * comment:游戏扩展数据,支付完成回调时,会完整返回给游戏服务端 + * content:[{"id":"game.onegold","name":"onegold","count":1,"price":100}] -> 内容只允许数字、英文字母、中文,不允许出现空格等其他特殊字符 + * game_user_id:123456789 -> iccgame sdk 用户唯一标识 + * notify_url:http://game-server.com/PayNotifyVerify.jsp -> 游戏服务器充值回调地址 + * out_trade_no:20220509XXXXXXXX -> 游戏订单号 + * service : 21930001 -> 游戏唯一支付业务标识,请在SDK提供的密钥文件下readme.txt中查看 + * total_fee : 100 -> 充值额度(以分为单位,必须为整数) + */ + signSerialization.setItem("comment", request.getParameter("comment")); + // 注:一般游戏商品表会配置在服务端,可根据游戏客户端传递的商品ID寻找到商品详情,如:商品名、商品价格等 + signSerialization.setItem("content", request.getParameter("content")); + signSerialization.setItem("game_user_id", request.getParameter("game_user_id")); + signSerialization.setItem("notify_url", "游戏服务器回调地址"); + signSerialization.setItem("out_trade_no", productID); + signSerialization.setItem("service", service); + signSerialization.setItem("total_fee", request.getParameter("total_fee")); + // 调用serialize函数对参数升序排列并进行URLEncoder,参数串进行RSA签名,,签名串也做URLEncoder,将 + // 将当前订单签名数据,返回给“游戏客户端” + return signSerialization.serialize(); + } + + /** + * 回调 + */ + public static String callback(HttpServletRequest request, String payKey) throws Exception { + HashMap parameterMap = JsonUtil.getInstence().getParameterMap2(request); + if (parameterMap.isEmpty()) { + LOGGER.info("u1game---> callback data is null"); + return "data is null"; + } + boolean sign = verifySign(parameterMap, payKey); + if (!sign) { + LOGGER.info("u1game---> sign error"); + return "sign error"; + } + + String order = parameterMap.get("out_trade_no"); // 支付订单号 唯一 + int amount = Integer.parseInt(parameterMap.get("total_fee")); // 充值金额 分 + String gameExt = request.getParameter("comment"); //透传参数 + String[] callback = gameExt.split("_"); + return PayLogic.initOrder(gameExt, order, String.valueOf(amount), new Date(), callback[0], PaySdkEnum.U1GAME); + } + + /** + * 验证sign + */ + public static boolean verifySign(Map map, String payKey) throws Exception { + // SDK服务端通过HTTP传递过来的支付订单信息 + String data = map.get("data"); + // SignSerialization为ICC SDK 工具类(游戏接入方可直接使用) + // 调用unserialize函数对参数进行反序列化并URLDecoder,调用setPublicKey函数设置登录公钥 + // 调用verify函数验签可返回boolean类型,根据结果去重组游戏客户端需要的数据 + SignSerialization signSerialization = SignSerialization.unserialize(data); + signSerialization.setPublicKey(payKey); + return signSerialization.verify(); + } +} diff --git a/src/main/java/com/jmfy/controller/XPRechargeController.java b/src/main/java/com/jmfy/controller/XPRechargeController.java index 5fd8846..4440c26 100644 --- a/src/main/java/com/jmfy/controller/XPRechargeController.java +++ b/src/main/java/com/jmfy/controller/XPRechargeController.java @@ -19,6 +19,7 @@ import java.util.HashMap; * @date 2021/6/9 * @discribe 喜扑专服 */ +@Deprecated @RestController public class XPRechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/XPiosRechargeController.java b/src/main/java/com/jmfy/controller/XPiosRechargeController.java index 6435222..92e899d 100644 --- a/src/main/java/com/jmfy/controller/XPiosRechargeController.java +++ b/src/main/java/com/jmfy/controller/XPiosRechargeController.java @@ -17,7 +17,7 @@ import java.util.*; /** * @discribe 喜扑ios */ - +@Deprecated @RestController public class XPiosRechargeController { @Resource diff --git a/src/main/java/com/jmfy/controller/XqTenthRechargeController.java b/src/main/java/com/jmfy/controller/XqTenthRechargeController.java new file mode 100644 index 0000000..1d22a8e --- /dev/null +++ b/src/main/java/com/jmfy/controller/XqTenthRechargeController.java @@ -0,0 +1,20 @@ +package com.jmfy.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +/** + * 小七0.1游戏 + */ +@RestController +public class XqTenthRechargeController { + + private static final String PAYKEY = "0370457c8e8f12489b7568b60ef85b61"; + + @RequestMapping(value = "/Web/xqTenthCallback") + public String xqTenthCallback(HttpServletRequest request) throws Exception { + return YouGuRechargeController.callback(request, PAYKEY); + } +} diff --git a/src/main/java/com/jmfy/controller/YouGuRechargeController.java b/src/main/java/com/jmfy/controller/YouGuRechargeController.java index b04fb07..561d1e6 100644 --- a/src/main/java/com/jmfy/controller/YouGuRechargeController.java +++ b/src/main/java/com/jmfy/controller/YouGuRechargeController.java @@ -32,10 +32,6 @@ public class YouGuRechargeController { /** * 回调 - * @param request - * @param payKey - * @return - * @throws IOException */ public static String callback(HttpServletRequest request, String payKey) throws IOException { JSONObject jsonObject = new JSONObject(); diff --git a/src/main/java/com/jmfy/controller/YouGuXQRechargeController.java b/src/main/java/com/jmfy/controller/YouGuXQRechargeController.java index 236be1a..f70f4b4 100644 --- a/src/main/java/com/jmfy/controller/YouGuXQRechargeController.java +++ b/src/main/java/com/jmfy/controller/YouGuXQRechargeController.java @@ -18,6 +18,7 @@ import java.util.Map; /** * 悠谷游戏 */ +@Deprecated @RestController public class YouGuXQRechargeController { diff --git a/src/main/java/com/jmfy/controller/YxylRechargeController.java b/src/main/java/com/jmfy/controller/YxylRechargeController.java index 694945b..3af990e 100644 --- a/src/main/java/com/jmfy/controller/YxylRechargeController.java +++ b/src/main/java/com/jmfy/controller/YxylRechargeController.java @@ -16,7 +16,7 @@ import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Date; import java.util.HashMap; - +@Deprecated @RestController public class YxylRechargeController { @Resource diff --git a/src/main/java/com/jmfy/paramBean/PaySdkEnum.java b/src/main/java/com/jmfy/paramBean/PaySdkEnum.java index a4526f2..1a000aa 100644 --- a/src/main/java/com/jmfy/paramBean/PaySdkEnum.java +++ b/src/main/java/com/jmfy/paramBean/PaySdkEnum.java @@ -21,6 +21,7 @@ public enum PaySdkEnum { ANJIU(11, "ANJIU"), YOUGU(12,"YOUGU"), FENGTI(13,"FENGTI"), + U1GAME(14, "U1GAME") ; private int id; diff --git a/src/main/java/com/jmfy/util/Base64.java b/src/main/java/com/jmfy/util/Base64.java new file mode 100644 index 0000000..adede77 --- /dev/null +++ b/src/main/java/com/jmfy/util/Base64.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2010 The MobileSecurePay Project + * All right reserved. + * author: shiqun.shi@alipay.com + */ +package com.jmfy.util; + +public final class Base64 { + + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final char PAD = '='; + static private final boolean fDebug = false; + static final private byte[] base64Alphabet = new byte[BASELENGTH]; + static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; + + static { + for (int i = 0; i < BASELENGTH; ++i) { + base64Alphabet[i] = -1; + } + for (int i = 'Z'; i >= 'A'; i--) { + base64Alphabet[i] = (byte) (i - 'A'); + } + for (int i = 'z'; i >= 'a'; i--) { + base64Alphabet[i] = (byte) (i - 'a' + 26); + } + + for (int i = '9'; i >= '0'; i--) { + base64Alphabet[i] = (byte) (i - '0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i <= 25; i++) { + lookUpBase64Alphabet[i] = (char) ('A' + i); + } + + for (int i = 26, j = 0; i <= 51; i++, j++) { + lookUpBase64Alphabet[i] = (char) ('a' + j); + } + + for (int i = 52, j = 0; i <= 61; i++, j++) { + lookUpBase64Alphabet[i] = (char) ('0' + j); + } + lookUpBase64Alphabet[62] = (char) '+'; + lookUpBase64Alphabet[63] = (char) '/'; + + } + + private static boolean isWhiteSpace(char octect) { + return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); + } + + private static boolean isPad(char octect) { + return (octect == PAD); + } + + private static boolean isData(char octect) { + return (octect < BASELENGTH && base64Alphabet[octect] != -1); + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static String encode(byte[] binaryData) { + + if (binaryData == null) { + return null; + } + + int lengthDataBits = binaryData.length * EIGHTBIT; + if (lengthDataBits == 0) { + return ""; + } + + int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; + int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; + char encodedData[] = null; + + encodedData = new char[numberQuartet * 4]; + + byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; + + int encodedIndex = 0; + int dataIndex = 0; + if (fDebug) { + System.out.println("number of triplets = " + numberTriplets); + } + + for (int i = 0; i < numberTriplets; i++) { + b1 = binaryData[dataIndex++]; + b2 = binaryData[dataIndex++]; + b3 = binaryData[dataIndex++]; + + if (fDebug) { + System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3); + } + + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); + + if (fDebug) { + System.out.println("val2 = " + val2); + System.out.println("k4 = " + (k << 4)); + System.out.println("vak = " + (val2 | (k << 4))); + } + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; + } + + // form integral number of 6-bit groups + if (fewerThan24bits == EIGHTBIT) { + b1 = binaryData[dataIndex]; + k = (byte) (b1 & 0x03); + if (fDebug) { + System.out.println("b1=" + b1); + System.out.println("b1<<2 = " + (b1 >> 2)); + } + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; + encodedData[encodedIndex++] = PAD; + encodedData[encodedIndex++] = PAD; + } else if (fewerThan24bits == SIXTEENBIT) { + b1 = binaryData[dataIndex]; + b2 = binaryData[dataIndex + 1]; + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; + encodedData[encodedIndex++] = PAD; + } + + return new String(encodedData); + } + + /** + * Decodes Base64 data into octects + * + * @param encoded string containing Base64 data + * @return Array containind decoded data. + */ + public static byte[] decode(String encoded) { + + if (encoded == null) { + return null; + } + + char[] base64Data = encoded.toCharArray(); + // remove white spaces + int len = removeWhiteSpace(base64Data); + + if (len % FOURBYTE != 0) { + return null;//should be divisible by four + } + + int numberQuadruple = (len / FOURBYTE); + + if (numberQuadruple == 0) { + return new byte[0]; + } + + byte decodedData[] = null; + byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; + char d1 = 0, d2 = 0, d3 = 0, d4 = 0; + + int i = 0; + int encodedIndex = 0; + int dataIndex = 0; + decodedData = new byte[(numberQuadruple) * 3]; + + for (; i < numberQuadruple - 1; i++) { + + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) + || !isData((d3 = base64Data[dataIndex++])) + || !isData((d4 = base64Data[dataIndex++]))) { + return null; + }//if found "no data" just return null + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + } + + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { + return null;//if found "no data" just return null + } + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + + d3 = base64Data[dataIndex++]; + d4 = base64Data[dataIndex++]; + if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters + if (isPad(d3) && isPad(d4)) { + if ((b2 & 0xf) != 0)//last 4 bits should be zero + { + return null; + } + byte[] tmp = new byte[i * 3 + 1]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); + return tmp; + } else if (!isPad(d3) && isPad(d4)) { + b3 = base64Alphabet[d3]; + if ((b3 & 0x3) != 0)//last 2 bits should be zero + { + return null; + } + byte[] tmp = new byte[i * 3 + 2]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + return tmp; + } else { + return null; + } + } else { //No PAD e.g 3cQl + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + + } + + return decodedData; + } + + /** + * remove WhiteSpace from MIME containing encoded Base64 data. + * + * @param data the byte array of base64 data (with WS) + * @return the new length + */ + private static int removeWhiteSpace(char[] data) { + if (data == null) { + return 0; + } + + // count characters that's not whitespace + int newSize = 0; + int len = data.length; + for (int i = 0; i < len; i++) { + if (!isWhiteSpace(data[i])) { + data[newSize++] = data[i]; + } + } + return newSize; + } +} diff --git a/src/main/java/com/jmfy/util/RSA.java b/src/main/java/com/jmfy/util/RSA.java new file mode 100644 index 0000000..dda2794 --- /dev/null +++ b/src/main/java/com/jmfy/util/RSA.java @@ -0,0 +1,60 @@ +package com.jmfy.util; + +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.security.Signature; +import java.security.spec.PKCS8EncodedKeySpec; + +public class RSA { + + public static final String SIGN_ALGORITHMS = "SHA1WithRSA"; + + /** + * RSA签名 + * + * @param content 待签名数据 + * @param private_key 商户私钥 + * @param input_charset 编码格式 + * @return 签名值 + */ + public static String sign(String content, String private_key, String input_charset) { + try { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.decode(private_key))); + Signature signature = Signature.getInstance(SIGN_ALGORITHMS); + signature.initSign(privateKey); + signature.update(content.getBytes(input_charset)); + return Base64.encode(signature.sign()); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * RSA验签名检查 + * + * @param content 待签名数据 + * @param sign 签名值 + * @param public_key 支付宝公钥 + * @param input_charset 编码格式 + * @return 布尔值 + */ + public static boolean verify(String content, String sign, String public_key, String input_charset) { + try { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(Base64.decode(public_key))); + Signature signature = Signature.getInstance(SIGN_ALGORITHMS); + signature.initVerify(publicKey); + signature.update(content.getBytes(input_charset)); + return signature.verify(Base64.decode(sign)); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + // End Class +} diff --git a/src/main/java/com/jmfy/util/SignSerialization.java b/src/main/java/com/jmfy/util/SignSerialization.java new file mode 100644 index 0000000..9937133 --- /dev/null +++ b/src/main/java/com/jmfy/util/SignSerialization.java @@ -0,0 +1,248 @@ +package com.jmfy.util; + +import java.net.*; +import java.util.*; +import java.util.regex.*; + +/** + * + * @author Administrator + */ +public class SignSerialization { + + public static final String TYPE_MD5 = "md5"; + public static final String TYPE_RSA = "rsa"; + + /** + * 参数容器 + */ + protected TreeMap _properties = new TreeMap(new Comparator() { + @Override + public int compare(String s, String t1) { + return s.compareTo(t1); + } + }); + + /** + * 公钥 + */ + protected String _publicKey = ""; + + /** + * 私钥 + */ + protected String _privateKey = ""; + + /** + * 签名类型 + */ + protected String _signType = "rsa"; + + /** + * 签名结果 + */ + protected String _sign = ""; + + /** + * 反序列化方法 + * + * @param data + * @return + */ + public static SignSerialization unserialize(String data) { + // 实例自己 + SignSerialization that = new SignSerialization(); + // 解析数据 + String[] rows = data.split("&"); + for (int i = 0; i < rows.length; i++) { + int offset = rows[i].indexOf("="); + String k = rows[i].substring(0, offset); + String v = ""; + try { + v = URLDecoder.decode(rows[i].substring(offset + 1), "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + if (k.equals("sign_type")) { + that._signType = v; + continue; + } else if (k.equals("sign")) { + that._sign = v; + continue; + } + try { + that.setItem(k, v); + } catch (Exception e) { + e.printStackTrace(); + } + } + return that; + } + + /** + * 读取一项数据 + * + * @param key + * @return + */ + public String getItem(String key) { + return this._properties.get(key); + } + + /** + * 设置一项数据 + * + * @param key + * @param value + * @return + * @throws Exception + */ + public SignSerialization setItem(String key, String value) throws Exception { + if (key.equals("sign") || key.equals("sign_type")) { + throw new Exception("sign and sign_type not change."); + } + this._properties.put(key, value); + return this; + } + + /** + * 清理注释 + * + * @param key + * @return + */ + public String clearComment(String key) { + Pattern pattern1 = Pattern.compile("^[-]+[\\s]*[\\w]+[\\s]+[\\w]+[\\s]+[\\w]+[\\s]*[-]+$", Pattern.CASE_INSENSITIVE + Pattern.MULTILINE); + Pattern pattern2 = Pattern.compile("[\\s]+", Pattern.CASE_INSENSITIVE + Pattern.MULTILINE); + key = pattern1.matcher(key).replaceAll(""); + key = pattern2.matcher(key).replaceAll(""); + return key; + } + + /** + * 设置公钥 + * + * @param key + * @return + */ + public SignSerialization setPublicKey(String key) { + this._publicKey = this.clearComment(key); + return this; + } + + /** + * 设置私钥 + * + * @param key + * @return + */ + public SignSerialization setPrivateKey(String key) { + this._privateKey = this.clearComment(key); + return this; + } + + /** + * 验证结果 + * + * @return + * @throws Exception + */ + public boolean verify() throws Exception { + String data = this.getSignData(); + String sign = this._sign; + return this.verify(data, sign); + } + + /** + * 验证结果 + * + * @param sign + * @return + */ + public boolean verify(String sign) throws Exception { + String data = this.getSignData(); + return this.verify(data, sign); + } + + /** + * 验证签名 + * + * @param data + * @param sign + * @return + * @throws Exception + */ + public boolean verify(String data, String sign) throws Exception { + if (this._publicKey == null || this._publicKey.isEmpty()) { + throw new Exception("public key not empty."); + } + return RSA.verify(data, sign, this._publicKey, "utf-8"); + } + + /** + * 签名数据 + * + * @return + * @throws Exception + */ + public String sign() throws Exception { + // 签名数据 + String data = this.getSignData(); + return this.sign(data); + } + + /** + * 签名数据 + * + * @param data + * @return + * @throws Exception + */ + public String sign(String data) throws Exception { + if (this._privateKey == null || this._privateKey.isEmpty()) { + throw new Exception("private key not empty."); + } + // 签名数据 + String sign = RSA.sign(data, this._privateKey, "UTF-8"); + return sign; + } + + /** + * 获得签名数据 + * + * @return + */ + public String getSignData() { + StringBuilder buffer = new StringBuilder(); + Iterator iter = this._properties.entrySet().iterator(); + while (iter.hasNext()) { + if (buffer.length() > 0) { + buffer.append("&"); + } + Map.Entry entry = (Map.Entry) iter.next(); + String k = (String) entry.getKey(); + String v = (String) entry.getValue(); + buffer.append(k); + buffer.append("="); + try { + buffer.append(URLEncoder.encode(v, "UTF-8")); + } catch (Exception e) { + e.printStackTrace(); + } + } + return buffer.toString(); + } + + /** + * 序列化数据 + * + * @return + * @throws Exception + */ + public String serialize() throws Exception { + String data = this.getSignData(); + String sign = this.sign(data); + return data + "&sign_type=rsa&sign=" + URLEncoder.encode(sign, "UTF-8"); + } + // End Class +}