服务端接入时使用的算法,及部分示例代码。

# 准备

请先获得参数:

  • productKey:SDK服务端为每个应用分配的私钥
  • productCode:SDK服务端为每个应用分配的项目id

# 1、参数data

用途 请求的参数数据内容

  • 基本规则:

    • markData(Key1,Val1,Key2,Val2,Key3,Val3....)
    • productKeytimestamp不参与生成data
  • 相关功能代码:

    Java 示例代码
    private static final String CHAR_CODE = "UTF-8";
    
    /** 计算Data */
    private static String markData(Object... key_val) throws Exception
    {
    
    	HashMap<String, Object> map = new HashMap<String, Object>();
    	for (int i = 1; i < key_val.length; i += 2)
    		if (key_val[i] != null && key_val[i - 1] != null)
    			map.put(key_val[i - 1] + "", key_val[i]);
    	return markDataFlag(map);
    }
    
    /** 具体执行计算Data */
    private static String markDataFlag(Map<String, Object> params) throws Exception
    {
    	JSONObject nameValuePairs = new JSONObject();
    
    	for (Map.Entry<String, Object> entry : params.entrySet())
    	{
    		String key = entry.getKey();
    		if (key == null)
    		{
    			throw new NullPointerException("key == null");
    		}
    		nameValuePairs.put(key, entry.getValue());
    	}
    	//将数组转化为 json 字符串
    	String jsonStr = nameValuePairs.toString();
    
    	// 对 jsonStrbase64 进行  编码
    	String tmpData = Base64.encodeToString(jsonStr.getBytes(CHAR_CODE), Base64.DEFAULT);
    	Logger.i("markDataFlag and json to base64 is" + tmpData);
    
    	// 将 tmpData 进行对称换位 ,  得到结果就是 data 密文数据
    	String finalData;
    	if (tmpData.length() > 51)
    	{
    		char[] chars = changeArray(tmpData.toCharArray(), 1, 33, 10, 42, 18, 50, 19, 51);
    		finalData = new String(chars);
    	}
    	else
    	{
    		finalData = tmpData;
    	}
    	return finalData;
    }
    
    /** 换位 */
    public static char[] changeArray(char[] chars, int... index) {
    	for (int i = 1; i < index.length; i += 2) {
    		final int l = index[i - 1];
    		final int r = index[i];
    		char c = chars[l];
    		chars[l] = chars[r];
    		chars[r] = c;
    	}
    	return chars;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
  • 调用示例

    markData("key1", 1, "key2", 2);
    
    1
    • 结果

      data=eyJrZXkxIjoxLCJrZXkyIjoyfQ==
      
      1

# 2、参数timestamp

用途 请求的参数时间戳

  • 基本规则:
    • 用作获取当前的时间戳单位为秒

      public static String getTimestamp()
      {
      	return String.valueOf(System.currentTimeMillis() / 1000);
      }
      
      1
      2
      3
      4

# 3、参数sign

用途 请求的参数签名值

  • 基本规则:

    • markSign(APPKEY, Key1,Val1,Key2,Val2,Key3,Val3....)
    • APPKEY对应productKey: SDK服务端为每个应用分配的私钥
    • 主要签名字段包括pcodedatatimestamp
  • 相关功能代码:

    Java 示例代码
    private static final String K_SIGN = "sign";
    
    /** 计算sign */
    private static String markSign(String appKey, String... key_val)
    {
    	HashMap<String, String> map = new HashMap<String, String>();
    	for (int i = 1; i < key_val.length; i += 2)
    		if (key_val[i] != null && key_val[i - 1] != null)
    			map.put(key_val[i - 1], key_val[i]);
    	return markSignFlag(appKey, map);
    }
    
    /** 具体执行计算sign */
    private static String markSignFlag(String appKey, Map<String, String> params)
    {
    	ArrayList<String> keys = new ArrayList<String>(params.keySet());
    	keys.remove(K_SIGN);
    	Collections.sort(keys);
    	StringBuilder builder = new StringBuilder();
    
    	for (int i = 0; i < keys.size(); i++)
    	{
    		final String key = keys.get(i);
    		final String value = params.get(key);
    		if (key != null && key.length() > 0)
    		{
    			builder.append(key).append("=").append(value).append('&');
    		}
    	}
    	builder.append(appKey);
    	String srcData = builder.toString();
    	return SignUtil.encrypt(SignUtil.MD5, srcData);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
  • 调用示例

    String timestamp = "1502186851";// String.valueOf(System.currentTimeMillis() / 1000);
    String data = "eyJrZXkxIjoxLCJrZXkyIjoyfQ==";
    String productKey = "12345678";
    String productCode = "12345678";
    String sign = markSign(productKey, "pcode", productCode, "data", data, "timestamp", timestamp);
    
    1
    2
    3
    4
    5
    • 结果

      sign=1f03d3a85ad79e364f81b855e91f69bd
      
      1

!> 附: 签名工具类 SignUtil.java

java代码

# 支付通知解密算法

# 3.1 基本规则

  1. markSign(callbackKey, Key1,Val1) 生成签名
    • callbackKey对应callbackKey: SDK服务端为每个应用分配的支付回调秘钥
    • 主要签名字段包括 data
  2. 生成后的签名与回调里的参数sign 进行比较
  3. 签名验证成功后, 将data参数用base64解密,即可得到支付结果数据
  • callbackkey:SDK服务端为游戏的同步的秘钥

  • 相关功能代码参考(java):

    String dataStr = ""; // 获取的data参数
    String dataSign = SignUtils.markSign(syncKey, "data", dataStr);
    String signStr = getPara("sign");
    if (StrKit.equals(dataSign, signStr))
    {
    	renderText("FAIL sign fail");
    	return;
    }
    String data = new String(Base64.decodeBase64(dataStr.getBytes()));
    JSONObject jsonObject = new JSONObject(data);
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • 解析后data的值参考:

    {
    	"amount": 6,
    	"gameOrder": "cpOrderId_1505271109529",
    	"orderNo": "HUA10000000277",
    	"selfDefine": "透传参数",
    	"status": 0,
    	"channelUid": "c4ca4238a0b923820dcc509a6f75849b",
    	"payTime": 1505271109000,
    	"channel": "sample" 
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
本文档对解决你的问题有所帮助?