xiaoyu 2 years atrás
parent
commit
0b6f577d80
21 changed files with 1506 additions and 0 deletions
  1. BIN
      helper/refill/api/xyz/tianyi/800系统接口文档/【1.优先详看】天翼流量800新接口协议(2021.11).pdf
  2. 187 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/C#加密模版.txt
  3. 424 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/C++ AES加密模板.txt
  4. 115 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/Java AES加密模板.java
  5. 54 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/php AES加密模板.php
  6. 70 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/python AES加密模板.py
  7. 54 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【2】回调解密Demo/c#回调解密.txt
  8. 10 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【2】回调解密Demo/java回调解密.txt
  9. 24 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【2】回调解密Demo/php回调示例.txt
  10. 128 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【3】回调Demo(明文)/.net&C#回调示例.txt
  11. 42 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【3】回调Demo(明文)/java回调示例.txt
  12. 48 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【4】签名校验模板及公钥/Java DSA校验模板.java
  13. 7 0
      helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【4】签名校验模板及公钥/回调参数签名校验公钥.txt
  14. BIN
      helper/refill/api/xyz/tianyi/800系统接口文档/【3.申请参数用】BMS合同参数配置申请操作指引.pdf
  15. BIN
      helper/refill/api/xyz/tianyi/800系统接口文档/【4.测试订购失败时看】合作方接口联调常见问题处理指引-2018.7.xlsx
  16. 13 0
      helper/refill/api/xyz/tianyi/800系统接口文档/平台下单地址及出口IP.txt
  17. BIN
      helper/refill/api/xyz/tianyi/800系统接口文档/综合平台订购接口错误编码表及处理建议_2021.11.xlsx
  18. 68 0
      helper/refill/api/xyz/tianyi/RefillCallBack.php
  19. 165 0
      helper/refill/api/xyz/tianyi/RefillPhone.php
  20. 1 0
      helper/refill/api/xyz/tianyi/account.txt
  21. 96 0
      helper/refill/api/xyz/tianyi/config.php

BIN
helper/refill/api/xyz/tianyi/800系统接口文档/【1.优先详看】天翼流量800新接口协议(2021.11).pdf


+ 187 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/C#加密模版.txt

@@ -0,0 +1,187 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Web;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+
+public partial class dx : System.Web.UI.Page
+{
+    protected void Page_Load(object sender, EventArgs e)
+    {
+        string url = "http://118.123.170.72:8888/fps/flowService.do";
+ 
+     string codes="{\"request_no\":\"123\",\"service_code\":\"FS0001\",\"contract_id\":\"AccessPartner2014\",\"order_id\":\"0\",\"plat_offer_id\":\"100091\",\"phone_id\":\"18017017801\",\"activity_id\":\"100085\",\"order_type\":\"1\",\"channel_id\":\"1\"}";
+ 
+        byte[] encryptData = Encrypts(codes, "H5gOs1ZshKZ6WikN", "8888159601152533");
+        string content = Str2Hex(encryptData).ToLower();
+     
+        string p = "{\"partner_no\":\"100054374\",\"code\":\"" + content + "\"}";
+  
+ 
+      string ok = Common.Fun.MyPost(url, p);
+     Response.Write(ok);
+
+    }
+
+    /// <summary>
+    /// 字节转16进制
+    /// </summary>
+    /// <param name="s"></param>
+    /// <returns></returns>
+    public static string Str2Hex(byte[] s)
+    {
+        System.Text.StringBuilder strBuf = new System.Text.StringBuilder();
+     
+        
+        //byte[] arrByte = System.Text.Encoding.GetEncoding("GB2312").GetBytes(s);
+
+
+        for (int i = 0; i < s.Length; i++)
+          {
+              strBuf.Append((char)(((s[i] >> 4) & 0xF) + ((int)'a')));
+              strBuf.Append((char)(((s[i]) & 0xF) + ((int)'a')));
+          }
+          return strBuf.ToString();
+    } 

+ 
+ 
+    /// <summary>
+    /// AES-128-CBC
+    /// </summary>
+    /// <param name="toEncrypt"></param>
+    /// <param name="key"></param>
+    /// <param name="iv"></param>
+    /// <returns></returns>
+
+    public static byte[] Encrypts(string toEncrypt, string key, string iv)
+    {
+
+
+        byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
+        byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);
+
+
+        byte[] resultArray = EncryptStringToBytes_Aes(toEncrypt, keyArray, ivArray);
+        return resultArray;
+
+    }
+
+
+    /// <summary>
+    /// AES-128-CBC  加密处理
+    /// </summary>
+    /// <param name="plainText"></param>
+    /// <param name="Key"></param>
+    /// <param name="IV"></param>
+    /// <returns></returns>
+   public  static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
+    {
+        // Check arguments.
+        if (plainText == null || plainText.Length <= 0)
+            throw new ArgumentNullException("plainText");
+        if (Key == null || Key.Length <= 0)
+            throw new ArgumentNullException("Key");
+        if (IV == null || IV.Length <= 0)
+            throw new ArgumentNullException("Key");
+        byte[] encrypted;
+        // Create an AesCryptoServiceProvider object
+        // with the specified key and IV.
+        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
+        {
+            aesAlg.Key = Key;
+            aesAlg.IV = IV;
+
+            // Create a decrytor to perform the stream transform.
+            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
+
+            // Create the streams used for encryption.
+            using (MemoryStream msEncrypt = new MemoryStream())
+            {
+                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
+                {
+                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
+                    {
+
+                        //Write all data to the stream.
+                        swEncrypt.Write(plainText);
+                    }
+                    encrypted = msEncrypt.ToArray();
+                }
+            }
+        }
+
+
+        // Return the encrypted bytes from the memory stream.
+        return encrypted;
+
+    }
+
+
+    public static DataTable JsonToDataTable(string strJson)
+    {
+        //取出表名   
+        var rg = new Regex(@"(?<={)[^:]+(?=:\[)", RegexOptions.IgnoreCase);
+        string strName = rg.Match(strJson).Value;
+        DataTable tb = null;
+        //去除表名   
+        // strJson = strJson.Substring(strJson.IndexOf("[") + 1);
+        //strJson = strJson.Substring(0, strJson.IndexOf("]"));
+
+        //获取数据   
+        rg = new Regex(@"(?<={)[^}]+(?=})");
+        MatchCollection mc = rg.Matches(strJson);
+        for (int i = 0; i < mc.Count; i++)
+        {
+            string strRow = mc[i].Value;
+            string[] strRows = strRow.Split(',');
+
+            //创建表   
+            if (tb == null)
+            {
+                tb = new DataTable();
+                tb.TableName = strName;
+                foreach (string str in strRows)
+                {
+                    var dc = new DataColumn();
+                    string[] strCell = str.Split(':');
+                    dc.ColumnName = strCell[0];
+                    dc.ColumnName = dc.ColumnName.Replace("\"", "");
+                    tb.Columns.Add(dc);
+                }
+                tb.AcceptChanges();
+            }
+
+            //增加内容   
+            DataRow dr = tb.NewRow();
+            for (int r = 0; r < strRows.Length; r++)
+            {
+                string str = "";
+                if (strRows[r].Split(':')[1].Trim().IndexOf("http") > -1)
+                {
+                    dr[r] = strRows[r].Split(':')[1].Trim().Replace(",", ",").Replace(":", ":").Replace("\"", "") + ":" + strRows[r].Split(':')[2].Trim().Replace(",", ",").Replace(":", ":").Replace("\"", "").Replace("\\", "");
+                }
+                else
+                {
+                    dr[r] = strRows[r].Split(':')[1].Trim().Replace(",", ",").Replace(":", ":").Replace("\"", "");
+                }
+
+
+            }
+            tb.Rows.Add(dr);
+            tb.AcceptChanges();
+        }
+
+        return tb;
+    }
+}
+
+
+ 
+ 
+ 

+ 424 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/C++ AES加密模板.txt

@@ -0,0 +1,424 @@
+/*AES接口*/
+
+#ifndef SRC_UTILS_AES_H
+#define SRC_UTILS_AES_H
+
+class AES  
+{
+public:
+    AES(unsigned char* key);
+    virtual ~AES();
+    unsigned char* Cipher(unsigned char* input);    // 加密,传入的数组大小必须是16字节
+    unsigned char* InvCipher(unsigned char* input);  // 解密,传入的数组也必须是16字节
+    void* Cipher(void* input, int length=0);      // 可以传入数组,大小必须是16的整数倍,如果不是将会越界操作;如果不传length而默认为0,那么将按照字符串处理,遇'\0'结束
+    void* InvCipher(void* input, int length);      // 必须传入数组和大小,必须是16的整数倍
+
+private:
+    unsigned char Sbox[256];
+    unsigned char InvSbox[256];
+    unsigned char w[11][4][4];
+
+    void KeyExpansion(unsigned char* key, unsigned char w[][4][4]);
+    unsigned char FFmul(unsigned char a, unsigned char b);
+
+    void SubBytes(unsigned char state[][4]);
+    void ShiftRows(unsigned char state[][4]);
+    void MixColumns(unsigned char state[][4]);
+    void AddRoundKey(unsigned char state[][4], unsigned char k[][4]);
+
+    void InvSubBytes(unsigned char state[][4]);
+    void InvShiftRows(unsigned char state[][4]);
+    void InvMixColumns(unsigned char state[][4]);
+};
+
+#endif    // SRC_UTILS_AES_H
+
+
+/*AES实现*/
+
+#include "aes.h"
+#include "string.h"
+
+AES::AES(unsigned char* key)
+{
+    unsigned char sBox[] =
+    { /*  0    1    2    3    4    5    6    7    8    9    a    b    c    d    e    f */ 
+        0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, /*0*/  
+        0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, /*1*/
+        0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, /*2*/ 
+        0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, /*3*/ 
+        0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, /*4*/ 
+        0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, /*5*/
+        0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, /*6*/  
+        0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, /*7*/ 
+        0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, /*8*/ 
+        0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, /*9*/ 
+        0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, /*a*/
+        0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, /*b*/
+        0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, /*c*/ 
+        0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, /*d*/
+        0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, /*e*/ 
+        0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16  /*f*/
+    };
+    unsigned char invsBox[256] = 
+    { /*  0    1    2    3    4    5    6    7    8    9    a    b    c    d    e    f  */  
+        0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, /*0*/ 
+        0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, /*1*/
+        0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, /*2*/ 
+        0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, /*3*/ 
+        0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, /*4*/ 
+        0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, /*5*/ 
+        0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, /*6*/ 
+        0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, /*7*/
+        0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, /*8*/ 
+        0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, /*9*/
+        0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, /*a*/
+        0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, /*b*/ 
+        0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, /*c*/ 
+        0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, /*d*/ 
+        0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, /*e*/ 
+        0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d  /*f*/
+    }; 
+    memcpy(Sbox, sBox, 256);
+    memcpy(InvSbox, invsBox, 256);
+    KeyExpansion(key, w);
+}
+
+AES::~AES()
+{
+
+}
+
+unsigned char* AES::Cipher(unsigned char* input)
+{
+    unsigned char state[4][4];
+    int i,r,c;
+
+    for(r=0; r<4; r++)
+    {
+        for(c=0; c<4 ;c++)
+        {
+            state[r][c] = input[c*4+r];
+        }
+    }
+
+    AddRoundKey(state,w[0]);
+
+    for(i=1; i<=10; i++)
+    {
+        SubBytes(state);
+        ShiftRows(state);
+        if(i!=10)MixColumns(state);
+        AddRoundKey(state,w[i]);
+    }
+
+    for(r=0; r<4; r++)
+    {
+        for(c=0; c<4 ;c++)
+        {
+            input[c*4+r] = state[r][c];
+        }
+    }
+
+    return input;
+}
+
+unsigned char* AES::InvCipher(unsigned char* input)
+{
+    unsigned char state[4][4];
+    int i,r,c;
+
+    for(r=0; r<4; r++)
+    {
+        for(c=0; c<4 ;c++)
+        {
+            state[r][c] = input[c*4+r];
+        }
+    }
+
+    AddRoundKey(state, w[10]);
+    for(i=9; i>=0; i--)
+    {
+        InvShiftRows(state);
+        InvSubBytes(state);
+        AddRoundKey(state, w[i]);
+        if(i)
+        {
+            InvMixColumns(state);
+        }
+    }
+    
+    for(r=0; r<4; r++)
+    {
+        for(c=0; c<4 ;c++)
+        {
+            input[c*4+r] = state[r][c];
+        }
+    }
+
+    return input;
+}
+
+void* AES::Cipher(void* input, int length)
+{
+    unsigned char* in = (unsigned char*) input;
+    int i;
+    if(!length)        // 如果是0则当做字符串处理
+    {
+        while(*(in+length++));
+        in = (unsigned char*) input;
+    }
+    for(i=0; i<length; i+=16)
+    {
+        Cipher(in+i);
+    }
+    return input;
+}
+
+void* AES::InvCipher(void* input, int length)
+{
+    unsigned char* in = (unsigned char*) input;
+    int i;
+    for(i=0; i<length; i+=16)
+    {
+        InvCipher(in+i);
+    }
+    return input;
+}
+
+void AES::KeyExpansion(unsigned char* key, unsigned char w[][4][4])
+{
+    int i,j,r,c;
+    unsigned char rc[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
+    for(r=0; r<4; r++)
+    {
+        for(c=0; c<4; c++)
+        {
+            w[0][r][c] = key[r+c*4];
+        }
+    }
+    for(i=1; i<=10; i++)
+    {
+        for(j=0; j<4; j++)
+        {
+            unsigned char t[4];
+            for(r=0; r<4; r++)
+            {
+                t[r] = j ? w[i][r][j-1] : w[i-1][r][3];
+            }
+            if(j == 0)
+            {
+                unsigned char temp = t[0];
+                for(r=0; r<3; r++)
+                {
+                    t[r] = Sbox[t[(r+1)%4]];
+                }
+                t[3] = Sbox[temp];
+                t[0] ^= rc[i-1];
+            }
+            for(r=0; r<4; r++)
+            {
+                w[i][r][j] = w[i-1][r][j] ^ t[r];
+            }
+        }
+    }
+}
+
+unsigned char AES::FFmul(unsigned char a, unsigned char b)
+{
+    unsigned char bw[4];
+    unsigned char res=0;
+    int i;
+    bw[0] = b;
+    for(i=1; i<4; i++)
+    {
+        bw[i] = bw[i-1]<<1;
+        if(bw[i-1]&0x80)
+        {
+            bw[i]^=0x1b;
+        }
+    }
+    for(i=0; i<4; i++)
+    {
+        if((a>>i)&0x01)
+        {
+            res ^= bw[i];
+        }
+    }
+    return res;
+}
+
+void AES::SubBytes(unsigned char state[][4])
+{
+    int r,c;
+    for(r=0; r<4; r++)
+    {
+        for(c=0; c<4; c++)
+        {
+            state[r][c] = Sbox[state[r][c]];
+        }
+    }
+}
+
+void AES::ShiftRows(unsigned char state[][4])
+{
+    unsigned char t[4];
+    int r,c;
+    for(r=1; r<4; r++)
+    {
+        for(c=0; c<4; c++)
+        {
+            t[c] = state[r][(c+r)%4];
+        }
+        for(c=0; c<4; c++)
+        {
+            state[r][c] = t[c];
+        }
+    }
+}
+
+void AES::MixColumns(unsigned char state[][4])
+{
+    unsigned char t[4];
+    int r,c;
+    for(c=0; c< 4; c++)
+    {
+        for(r=0; r<4; r++)
+        {
+            t[r] = state[r][c];
+        }
+        for(r=0; r<4; r++)
+        {
+            state[r][c] = FFmul(0x02, t[r])
+                        ^ FFmul(0x03, t[(r+1)%4])
+                        ^ FFmul(0x01, t[(r+2)%4])
+                        ^ FFmul(0x01, t[(r+3)%4]);
+        }
+    }
+}
+
+void AES::AddRoundKey(unsigned char state[][4], unsigned char k[][4])
+{
+    int r,c;
+    for(c=0; c<4; c++)
+    {
+        for(r=0; r<4; r++)
+        {
+            state[r][c] ^= k[r][c];
+        }
+    }
+}
+
+void AES::InvSubBytes(unsigned char state[][4])
+{
+    int r,c;
+    for(r=0; r<4; r++)
+    {
+        for(c=0; c<4; c++)
+        {
+            state[r][c] = InvSbox[state[r][c]];
+        }
+    }
+}
+
+void AES::InvShiftRows(unsigned char state[][4])
+{
+    unsigned char t[4];
+    int r,c;
+    for(r=1; r<4; r++)
+    {
+        for(c=0; c<4; c++)
+        {
+            t[c] = state[r][(c-r+4)%4];
+        }
+        for(c=0; c<4; c++)
+        {
+            state[r][c] = t[c];
+        }
+    }
+}
+
+void AES::InvMixColumns(unsigned char state[][4])
+{
+    unsigned char t[4];
+    int r,c;
+    for(c=0; c< 4; c++)
+    {
+        for(r=0; r<4; r++)
+        {
+            t[r] = state[r][c];
+        }
+        for(r=0; r<4; r++)
+        {
+            state[r][c] = FFmul(0x0e, t[r])
+                        ^ FFmul(0x0b, t[(r+1)%4])
+                        ^ FFmul(0x0d, t[(r+2)%4])
+                        ^ FFmul(0x09, t[(r+3)%4]);
+        }
+    }
+}
+
+
+/*加解密类*/
+
+#include "aes.h"
+#include "aes_encryptor.h"
+#include "log.h"
+
+#include <fstream>
+using namespace std;
+
+AesEncryptor::AesEncryptor(unsigned char* key)
+{
+    m_pEncryptor = new AES(key);
+}
+
+
+AesEncryptor::~AesEncryptor(void)
+{
+    delete m_pEncryptor;
+}
+
+void AesEncryptor::Byte2Hex(const unsigned char* src, int len, char* dest) {
+    for (int i=0; i<len; ++i) {
+        sprintf_s(dest + i * 2, 3, "%02X", src[i]);    
+    }
+}
+
+void AesEncryptor::Hex2Byte(const char* src, int len, unsigned char* dest) {
+    int length = len / 2;
+    for (int i=0; i<length; ++i) {
+        dest[i] = Char2Int(src[i * 2]) * 16 + Char2Int(src[i * 2 + 1]);
+    }
+}
+
+string AesEncryptor::EncryptString(string strInfor) {
+    int nLength = strInfor.length();
+    int spaceLength = 16 - (nLength % 16);
+    unsigned char* pBuffer = new unsigned char[nLength + spaceLength];
+    memset(pBuffer, '\0', nLength + spaceLength);
+    memcpy_s(pBuffer, nLength + spaceLength, strInfor.c_str(), nLength);
+    m_pEncryptor->Cipher(pBuffer, nLength + spaceLength);
+    
+    // 这里需要把得到的字符数组转换成十六进制字符串 
+    char* pOut = new char[2 * (nLength + spaceLength)];
+    memset(pOut, '\0', 2 * (nLength + spaceLength));
+    Byte2Hex(pBuffer, nLength + spaceLength, pOut);
+
+    string retValue(pOut);
+    delete[] pBuffer;
+    delete[] pOut;
+    return retValue;
+}
+
+string AesEncryptor::DecryptString(string strMessage) {
+    int nLength = strMessage.length() / 2;
+    unsigned char* pBuffer = new unsigned char[nLength];
+    memset(pBuffer, '\0', nLength);
+    Hex2Byte(strMessage.c_str(), strMessage.length(), pBuffer);
+
+    m_pEncryptor->InvCipher(pBuffer, nLength);
+    string retValue((char*)pBuffer);
+    delete[] pBuffer;
+    return retValue;
+}

+ 115 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/Java AES加密模板.java

@@ -0,0 +1,115 @@
+package com._21cn;
+
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * AES-128-CBC加解密模式
+ * @author libai
+ */
+public class AES {
+	
+	/**
+	 * 加密方法(此方法已经包含了将加密生成二进制加密串转为纯字母型的十六进制串的操作)
+	 * @param encData 要加密的数据
+	 * @param secretKey 密钥 ,16位的数字和字母
+	 * @param vector 初始化向量,16位的数字和字母
+	 * @return
+	 * @throws NoSuchPaddingException 
+	 * @throws NoSuchAlgorithmException 
+	 * @throws InvalidAlgorithmParameterException 
+	 * @throws InvalidKeyException 
+	 * @throws BadPaddingException 
+	 * @throws IllegalBlockSizeException 
+	 * @throws Exception
+	 */
+	public static String Encrypt(String encData ,String secretKey,String vector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException  {
+		
+		if(secretKey == null) {
+			return null;
+		}
+		if(secretKey.length() != 16) {
+			return null;
+		}
+		byte[] raw = secretKey.getBytes();
+		SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
+		Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// "算法/模式/补码方式"
+		IvParameterSpec iv = new IvParameterSpec(vector.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
+		cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
+		byte[] encrypted = cipher.doFinal(encData.getBytes());
+		return encodeBytes( encrypted );	//将加密生成二进制加密串转为纯字母型的十六进制串后返回
+	}
+
+	/**
+	 * 解密方法(此方法已经包含了将纯字母型的十六进制串转为二进制加密串的操作)
+	 * @param decData
+	 * @param secretKey 密钥 ,16位的数字和字母
+	 * @param vector 初始化向量,16位的数字和字母
+	 * @return
+	 * @throws UnsupportedEncodingException 
+	 * @throws NoSuchPaddingException 
+	 * @throws NoSuchAlgorithmException 
+	 * @throws InvalidAlgorithmParameterException 
+	 * @throws InvalidKeyException 
+	 * @throws BadPaddingException 
+	 * @throws IllegalBlockSizeException 
+	 * @throws Exception
+	 */
+	public static String Decrypt(String decData ,String secretKey,String vector) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
+		
+		if(secretKey == null) {
+			return null;
+		}
+		if(secretKey.length() != 16) {
+			return null;
+		}
+		byte[] raw = secretKey.getBytes("ASCII");
+		SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
+		Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+		IvParameterSpec iv = new IvParameterSpec(vector.getBytes());
+		cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
+		byte[] encrypted1 = decodeBytes(decData);	//解密前先将纯字母型的十六进制串转为二进制加密串
+		byte[] original = cipher.doFinal(encrypted1);
+		String originalString = new String(original);
+		return originalString;
+	}
+
+	/**
+	 * 转16进制
+	 * @param bytes
+	 * @return
+	 */
+	public static String encodeBytes(byte[] bytes) {
+		StringBuffer strBuf = new StringBuffer();
+		for (int i = 0; i < bytes.length; i++) {
+			strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a')));
+			strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a')));
+		}
+		return strBuf.toString();
+	}
+
+	/**
+	 * 转字节数组
+	 * @param str
+	 * @return
+	 */
+	public static byte[] decodeBytes(String str) {
+		byte[] bytes = new byte[str.length() / 2];
+		for (int i = 0; i < str.length(); i += 2) {
+			char c = str.charAt(i);
+			bytes[i / 2] = (byte) ((c - 'a') << 4);
+			c = str.charAt(i + 1);
+			bytes[i / 2] += (c - 'a');
+		}
+		return bytes;
+	}		
+}

+ 54 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/php AES加密模板.php

@@ -0,0 +1,54 @@
+<?php
+
+class AES{
+
+    private static function decodeBytes($hex)
+    {   
+        $str = ''; 
+        for($i=0;$i<strlen($hex);$i+=2){     	
+        	$tmpValue = (((ord($hex[$i]) - ord('a')) & 0xf ) <<4) + ((ord($hex[$i+1])- ord('a')) & 0xf);  
+        	$str .= chr($tmpValue); 
+        }
+        return  $str;
+    }
+    
+    private static function encodeBytes($string)
+    { 
+        $str = ''; 
+        for($i=0;$i<strlen($string);$i++)
+        {
+            $tmpValue = ord($string[$i]); 
+            $ch = ($tmpValue >> 4 & 0xf) + ord('a'); 
+            $str .= chr($ch); 
+            $ch = ($tmpValue & 0xf) + ord('a'); 
+            $str .= chr($ch); 
+        }
+        return $str;
+    }
+    /**
+     * 解密数据
+     * @param String $encryptedText 待解密密文 
+     * @param String $secretKey 密钥
+     * @param String $iv 向量密钥
+     * @return String
+     */
+	public static function encrypt($encryptedText, $secretKey, $iv) {
+		
+        $ciphertext = openssl_encrypt($encryptedText, "AES-128-CBC", $secretKey, OPENSSL_RAW_DATA, $iv);
+        return self::encodeBytes($ciphertext);
+	}
+	/**
+     * 加密数据
+     * @param String $encryptedText 待加密数据
+     * @param String $secretKey 密钥
+     * @param String $iv 向量密钥
+     * @return String
+     */
+	public static function decrypt($encryptedText, $secretKey, $iv) {
+		$encryptedText = self::decodeBytes($encryptedText);
+        $plaintext = openssl_decrypt($encryptedText, "AES-128-CBC", $secretKey, OPENSSL_RAW_DATA, $iv);
+		return $plaintext;
+	}
+	
+}
+?>

+ 70 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【1】请求加密Demo/python AES加密模板.py

@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# -*- coding:utf-8 -*- 
+#@author: rui.xu
+#这里使用pycrypto‎库
+#按照方法:easy_install pycrypto‎
+ 
+from Crypto.Cipher import AES
+from binascii import b2a_hex, a2b_hex
+ 
+class prpcrypt():
+    def __init__(self,key):
+        self.key = key
+        self.mode = AES.MODE_CBC
+     
+    #加密函数,如果text不足16位就用空格补足为16位,
+    #如果大于16当时不是16的倍数,那就补足为16的倍数。
+    def encrypt(self,text):
+        cryptor = AES.new(self.key,self.mode,b'0000000000000000')
+        #这里密钥key 长度必须为16(AES-128),
+        #24(AES-192),或者32 (AES-256)Bytes 长度
+        #目前AES-128 足够目前使用
+		#b'0000000000000000'为16位二进制向量
+        length = 16
+        count = len(text)
+        if count < length:
+            add = (length-count)
+            #\0 backspace
+            text = text + ('\0' * add)
+        elif count > length:
+            add = (length-(count % length))
+            text = text + ('\0' * add)
+        self.ciphertext = cryptor.encrypt(text)
+        #因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
+        #所以这里统一把加密后的字符串转化为16进制字符串
+        return encodeBytes(self.ciphertext)
+     
+    #解密后,去掉补足的空格用strip() 去掉
+    def decrypt(self,text):
+        cryptor = AES.new(self.key,self.mode,b'0000000000000000')
+		#这里密钥key 长度必须为16(AES-128),
		#b'0000000000000000'为16位二进制向量
+		
+        plain_text  = cryptor.decrypt(a2b_hex(text))
+        return plain_text.rstrip('\0')
+	
+	def encodeBytes(hexlist):
+    """
+    2进制转16进制字符串
+    :param bytelist:
+    :return:
+    """
+    in_list = []
+    for h in hexlist:
+        h = int(str(int(h.upper(), 16)))
+        if h > 128:
+            h = ~h ^ 255
+        in_list.append(int(h))
+
+    ret = []
+    for byte in in_list:
+        ret.append(chr(((byte >> 4) & 0xF) + 97))
+        ret.append(chr((byte & 0xF) + 97))
+    return ''.join(ret)
+ 
+if __name__ == '__main__':
+    pc = prpcrypt('keyskeyskeyskeys') #初始化密钥
+    import sys
+    e = pc.encrypt(sys.argv[1]) #加密
+    d = pc.decrypt(e) #解密
+    print "加密:",e
+    print "解密:",d

+ 54 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【2】回调解密Demo/c#回调解密.txt

@@ -0,0 +1,54 @@
+public static byte[] decodeBytes(String str)
+        {
+            byte[] bytes = new byte[str.Length / 2];
+            for (int i = 0; i < str.Length; i += 2)
+            {
+                char c = Convert.ToChar(str.Substring(i,1));
+                bytes[i / 2] = (byte)((c - 'a') << 4);
+                c = Convert.ToChar(str.Substring(i + 1,1));
+                bytes[i / 2] += Convert.ToByte(c - 'a');
+            }
+            return bytes;
+        }
+/// <summary>  
+        /// AES解密
+        /// </summary>  
+        /// <param name="Data">被加密的明文</param>  
+        /// <param name="Key">密钥</param>  
+        /// <param name="Vector">向量</param>  
+        /// <returns>明文</returns>  
+        public static string AES_Decrypt(String Data, String Key, String Vector)
+        {
+            Byte[] encryptedByte = decodeBytes(Data);
+            
+            Byte[] bKey = new Byte[16];
+            Byte[] Iv = new Byte[16];
+            Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
+            Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(Iv.Length)), Iv, Iv.Length);
+
+            MemoryStream mStream = new MemoryStream(encryptedByte);
+            RijndaelManaged aes = new RijndaelManaged();
+            aes.Padding = PaddingMode.PKCS7;
+            aes.Mode = CipherMode.CBC;
+            aes.BlockSize = 128;
+            aes.KeySize = 128;
+            aes.Key = bKey;
+            aes.IV = Iv;
+            CryptoStream cryptoStream = new CryptoStream(mStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
+            try
+            {
+                byte[] tmp = new byte[encryptedByte.Length];
+                int len = cryptoStream.Read(tmp, 0, encryptedByte.Length);
+                byte[] ret = new byte[len];
+                Array.Copy(tmp, 0, ret, 0, len);
+                return Encoding.UTF8.GetString(ret);
+            }
+            finally
+            {
+                cryptoStream.Close();
+                mStream.Close();
+                aes.Clear();
+            }
+        }
+
+

+ 10 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【2】回调解密Demo/java回调解密.txt

@@ -0,0 +1,10 @@
+public static byte[] decodeBytes(String str) {
+		byte[] bytes = new byte[str.length() / 2];
+		for (int i = 0; i < str.length(); i += 2) {
+			char c = str.charAt(i);
+			bytes[i / 2] = (byte) ((c - 'a') << 4);
+			c = str.charAt(i + 1);
+			bytes[i / 2] += (c - 'a');
+		}
+		return bytes;
+	}

+ 24 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【2】回调解密Demo/php回调示例.txt

@@ -0,0 +1,24 @@
+<?php
+	$public_key = "";//公钥
+	$secretKey = "";//AES秘钥
+	$vector = "";//加密向量
+	$content = '{"data":"1oblecdinlapfbjjfbpnbipgkedbkknbghifnlfdkfdfpiaidllfnoojcpcmelndajgcgcibcakdpofcamgbnkelaafndajfbafecllcghiecmfmolfnmliejghojjbhkeeclglnkkeekonofnofcbfmgkdcgcadd","signature":"MCwCFB5J0dohkNzqV5fol/Lz8fz5HBD3AhRFoBE3QK6ZnK5scjeOLW3YYh7AKA=="}';
+	$req =callback($content);
+	echo "<pre>";
+	print_r($req); 
+	//解密回调
+	public function callback($content){
+		$request = json_decode($content,true);
+		$public_key='-----BEGIN PUBLIC KEY-----'.PHP_EOL.wordwrap($public_key, 64, "\n", true) .PHP_EOL.'-----END PUBLIC KEY-----';
+		$res=  openssl_get_publickey($public_key);
+		$ok = (bool)openssl_verify($request['data'], base64_decode($request['signature']), $res);
+		openssl_free_key($res); 
+		if(!$ok){
+			return false;
+		}
+		$code = AES::decrypt($request['data'],$secretKey,$vector);
+		return $code;
+	}
+
+
+?>

+ 128 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【3】回调Demo(明文)/.net&C#回调示例.txt

@@ -0,0 +1,128 @@
+public partial class TYLL : System.Web.UI.Page
+    {
+
+        public Dictionary<string, string> Dic
+        {
+            get
+            {
+                var dicCode = new Dictionary<string, string>();
+                dicCode["00000"] = "客户下单成功/订购成功";
+                dicCode["10229"] = "订购中";
+                dicCode["10001"] = "空号/号码不存在";
+                dicCode["10010"] = "欠费/停机";
+                dicCode["10012"] = "号码已冻结或注销";
+                dicCode["10013"] = "黑名单客户";
+                dicCode["10018"] = "不能重复订购";
+                dicCode["10024"] = "业务互斥";
+                dicCode["10033"] = "在途工单";
+                dicCode["10057"] = "号码归属地信息不正确";
+                dicCode["10058"] = "客户业务受限";
+                dicCode["10063"] = "用户状态异常";
+                dicCode["10074"] = "用户信息不存在";
+                dicCode["10225"] = "无主套餐";
+                dicCode["80004"] = "解析接收报文异常";
+                dicCode["90001"] = "系统异常";
+                dicCode["90003"] = "模拟异常报竣";
+                dicCode["10003"] = "非法参数";
+                dicCode["10006"] = "非法客户";
+                dicCode["10007"] = "非法销售品";
+                dicCode["10008"] = "非法请求流水号";
+                dicCode["10030"] = "非法合同编号";
+                dicCode["10031"] = "销售品未配置";
+                dicCode["10040"] = "服务无权访问";
+                dicCode["10054"] = "销售品配置异常";
+                dicCode["10081"] = "销售品不存在";
+                dicCode["10091"] = "回调地址未配置";
+                dicCode["10109"] = "活动省份不存在";
+                dicCode["10230"] = "重复请求流水号";
+                dicCode["10236"] = "无订购记录,重发失败";
+                dicCode["10237"] = "订购已成功,无需重发";
+                dicCode["80002"] = "网络异常";
+                dicCode["99999"] = "系统未知错误";
+                dicCode["10026"] = "合同授权金额不足";
+                dicCode["10028"] = "合同尚未开始";
+                dicCode["10029"] = "合同已经过期";
+
+                return dicCode;
+            }
+        }
+
+        protected void Page_Load(object sender, EventArgs e)
+        {
+            try
+            {
+               
+                var requeststr = "";
+                if (Request.HttpMethod.Equals("POST"))
+                {
+                    var reader = new StreamReader(Request.InputStream);
+                    requeststr = HttpUtility.UrlDecode(reader.ReadToEnd());
+                }
+                else
+                {
+                    requeststr = Request.QueryString.ToString();
+                }
+                //日志记录 requeststr 
+
+                if (string.IsNullOrEmpty(requeststr))
+                {
+                   //日志记录 "空参数"
+                    return;
+                }
+
+                var param = requeststr.FromJson<Dictionary<string, string>>();
+
+                var data = param["data"];
+                var signature = param["signature"];
+
+				var aesKey = getAesKey();	//获取AES密钥
+				var iv = getIv();		//获取向量
+				var dsaKey = getDsaKey();	//获取DSA密钥												
+
+				if (!DSA.verify(data, dsaKey, signature))	//签名校验
+				{
+				   //日志记录  "校验不通过"
+					return;
+				} 
+				var json = AES.decrypt(json.getString("data"), aesKey, iv);	//解密
+				var param2 = json.FromJson<Dictionary<string, string>>();
+				var requestNo = param2["request_no"];
+				var resultCode = param2["result_code"];
+				
+				var item = getOrder(requestNo);	//查询订单号为requestNo的订单
+				
+                if (item == null)
+                {
+                   //日志记录  requestNo + "回调通知订单不存在");
+                    return;
+                }
+
+                if (item.OrderItemStatus != OrderItemStatusEnum.StartCharge && item.OrderItemStatus != OrderItemStatusEnum.Recharge)
+                {
+                     //日志记录  requestNo + "订单已处理");
+                    return;
+                }               
+                switch (resultCode)
+                {
+                    case "00000":
+                        item.SuccessMe();
+                        break;
+                    default:
+                        var msg = "";
+                        Dic.TryGetValue(resultCode, out msg);
+                        item.FailedMe(msg);
+                        break;
+                }
+
+                Response.Write("1");//回调确认
+
+            }
+            catch (Exception ex)
+            {
+                Response.Write("回调异常");
+                //日志记录    回调异常 
+            }
+        }
+    }
+
+}

+ 42 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【3】回调Demo(明文)/java回调示例.txt

@@ -0,0 +1,42 @@
+public static JSONObject getJSONByRequest(HttpServletRequest request) {
+		
+		BufferedReader br = null;
+		StringBuffer sb = new StringBuffer();
+		try {
+			br = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8"));
+			String line = null;
+			while ((line = br.readLine()) != null) {
+				sb.append(line);
+			}
+			log.info("JSON Request="+sb.toString());
+			JSONObject json = JSONObject.fromObject(sb.toString());
+			if (StringUtil.isEmpty(json.getString("data"))|| StringUtil.isEmpty(json.getString("signature"))){
+				return null;
+			}
+			String aesKey = getAesKey();	//获取AES密钥
+			String iv = getIv();		//获取向量
+			String dsaKey = getDsaKey();	//获取DSA密钥
+			
+			if (!DSA.verify(json.getString("data"), dsaKey, json.getString("signature"))) {	//签名校验
+				log.error("签名校验不通过");
+				return null;
+			}
+			String text = AES.decrypt(json.getString("data"), aesKey, iv);	//解密
+			if (text == null){
+				log.error("解密失败");
+				return null;
+			}
+			return text;
+		} catch (Exception e) {
+			log.error("parseJson io exception " + e.getMessage(), e);
+		} finally {
+			if (br != null) {
+				try {
+					br.close();
+				} catch (IOException e) {
+					log.error("parseJson io finally exception " + e.getMessage(),e);
+				}
+			}
+		}
+		return null;
+	} 

+ 48 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【4】签名校验模板及公钥/Java DSA校验模板.java

@@ -0,0 +1,48 @@
+package com._21cn.fbmp.common.util;
+
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.spec.X509EncodedKeySpec;
+
+import sun.misc.BASE64Decoder;
+
+public class DSA {
+	
+	public static final String KEY_ALGORITHM = "DSA";
+	public static final String SIGNATURE_ALGORITHM = "DSA";
+	
+	/**
+	 * 校验数字签名
+	 * @param text 摘要
+	 * @param publicKey 公钥(签名密钥)
+	 * @param sign 数字签名
+	 * @return
+	 * @throws Exception
+	 */
+	public static boolean verify(String text, String publicKey, String sign) throws Exception {
+		byte[] data = text.getBytes();
+		byte[] keyBytes = decryptBASE64(publicKey); 
+		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
+		PublicKey pubKey = keyFactory.generatePublic(keySpec);
+		
+		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);   
+        signature.initVerify(pubKey); 
+        signature.update(data);
+        
+        return signature.verify(decryptBASE64(sign)); //验证签名
+	}
+	
+	/**
+	 * BASE64Decoder 解密
+	 * @param data 要解密的字符串
+	 * @return 解密后的byte[]
+	 * @throws Exception 
+	 */
+	private static byte[] decryptBASE64(String data) throws Exception {
+		BASE64Decoder decoder = new BASE64Decoder();
+		byte[] buffer = decoder.decodeBuffer(data);
+		return buffer;
+	}
+}

+ 7 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/【2.接口开发用】联调Demo/【4】签名校验模板及公钥/回调参数签名校验公钥.txt

@@ -0,0 +1,7 @@
+校验公钥(正式环境与测试环境相同,请保存好):
+MIIBITCByAYHKoZIzjgEATCBvAJRAMkRGzB6IwsAH4y5HPHKBs4FdroVYilUSI5wMl3KUvMfM6Px
+zK+w8VfSy/ve6PAKIzQxDjKw45GeWf1W3VaVRGphK1PT9ytm67eirycyFVDjAhUAm2DlRf+2Yije
+cGTfZLcvXSsrEIMCUFoyNIHNNMi+zKZS1r+ZwqmBXNU/n95c24iH0WWYsQmQ0hv+SCIQupvaaO6D
+2FzeI62+RbDbyia+WDKLiQcQSKqbwhMwAzlCLyMqcvQRzbgmA1QAAlEAo7A/w25/gARfex0DeDst
+8lcteX3gRuMhqJEjpz1t5F2/Iu+0yOKAuGOzaSC3frY3kLrLTlCT4HtCB5cr3LptO9m+p2XIYv+q
+GETmxxRNKl0=

BIN
helper/refill/api/xyz/tianyi/800系统接口文档/【3.申请参数用】BMS合同参数配置申请操作指引.pdf


BIN
helper/refill/api/xyz/tianyi/800系统接口文档/【4.测试订购失败时看】合作方接口联调常见问题处理指引-2018.7.xlsx


+ 13 - 0
helper/refill/api/xyz/tianyi/800系统接口文档/平台下单地址及出口IP.txt

@@ -0,0 +1,13 @@
+【下单订购接口-正式/测试】
+http://win800.21cn.com/adapter/v1/remote/numberRecognitionUniversal.do(正式)
+https://testapi.800.21cn.com/fps/flowService.do(测试)
+
+【订单查询接口-正式】
+https://api.800.21cn.com/adapter/v1/remote/numberRecognitionCheck.do
+
+【合同余额查询接口】
+http://api.800.21cn.com/fps/queryChargeBalance.do
+
+【我司出口IP】
+42.123.76.4 
+42.123.77.153

BIN
helper/refill/api/xyz/tianyi/800系统接口文档/综合平台订购接口错误编码表及处理建议_2021.11.xlsx


+ 68 - 0
helper/refill/api/xyz/tianyi/RefillCallBack.php

@@ -0,0 +1,68 @@
+<?php
+namespace refill\tianyi;
+
+require_once(BASE_HELPER_RAPI_PATH . '/tianyi/config.php');
+
+use refill;
+class RefillCallBack implements refill\IRefillCallBack
+{
+    public function verify($params): bool
+    {
+        $input = $params;
+        unset($input['sign']);
+        $sign = $this->sign($input);
+        if ($params['sign'] == $sign) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private function sign($params)
+    {
+        ksort($params);
+
+        $content = '';
+        $secret = config::APP_SECRET;
+        foreach ($params as $key => $value) {
+            if($this->check_empty($value) === false) {
+                $content .= "{$key}{$value}";
+            }
+        }
+        $content .= $secret;
+        return md5(urlencode($content));
+    }
+
+    protected function check_empty($value)
+    {
+        if (!isset($value))
+            return true;
+        if ($value === null)
+            return true;
+        if (trim($value) === "")
+            return true;
+
+        return false;
+    }
+
+    public function notify($params)
+    {
+        $status = intval($params['orderStatus']);
+        $order_sn = $params['channelOrderNo'];
+        $order_info = Model('vr_order')->getOrderInfo(['order_sn' => $order_sn]);
+        if (empty($order_info)) {
+            return [false, false, false,false];
+        }
+        $order_id = $order_info['order_id'];
+
+        if ($status === 4) {
+            return [$order_id, true, false,true];
+        }
+        elseif ($status === 5) {
+            return [$order_id, false, true,true];
+        }
+        else {
+            return [$order_id, false, false,false];
+        }
+    }
+}

+ 165 - 0
helper/refill/api/xyz/tianyi/RefillPhone.php

@@ -0,0 +1,165 @@
+<?php
+
+namespace refill\tianyi;
+
+require_once(BASE_HELPER_RAPI_PATH . '/tianyi/config.php');
+
+use refill;
+use Log;
+
+class RefillPhone extends refill\IRefillThird
+{
+    public function __construct($cfgs)
+    {
+        parent::__construct($cfgs);
+    }
+
+    public function goods($quality, int $amount, int $card_type, $regin_no, $other)
+    {
+        [$goods_id, $price] = parent::goods($quality, $amount, $card_type, $regin_no, $other);
+        if ($goods_id <= 0) return [0, 0];
+
+        $store_id = $this->mStoreID;
+        $pcode = $other['product_code'];
+        $thrid_refill = Model('thrid_refill');
+        $product = $thrid_refill->getProviderProduct($store_id, $goods_id, $pcode);
+        if (empty($product)) {
+            Log::record("cannot find provider's produce where name={$this->mName}, goods_id = {$goods_id} pcode={$pcode}", Log::ERR);
+            return [0, 0];
+        } else {
+            return [$goods_id, ncPriceFormat($product['channel_amount'])];
+        }
+    }
+
+    private function getProduct($product_code)
+    {
+        $thrid_refill = Model('thrid_refill');
+        return $thrid_refill->getProduct(['system_code' => $product_code,'opened' => 1]);
+    }
+
+    private function req_params(int $phone, string $order_sn)
+    {
+        $params['partner_no'] = config::PARTNER_NO;
+        $params['request_no'] = $order_sn;
+
+        $params['service_code'] = 'service_code';
+        $params['contract_id'] = 'contract_id';
+        $params['activity_id'] = 'activity_id';
+
+        $params['order_type'] = 1;
+        $params['phone_id'] = $phone;
+
+        $params['plat_offer_id'] = 'plat_offer_id';
+
+        $params['effect_type'] = 0;
+        return $params;
+    }
+
+    public function add($card_no, $card_type, $amount, $input, &$net_errno = 0)
+    {
+        $order_sn = $input['order_sn'];
+
+        $code = $this->req_params($card_no, $order_sn);
+        $params['partner_no'] = config::PARTNER_NO;
+        $params['code'] = config::encrypt(json_encode($code));
+
+        $resp = http_request(config::ORDER_URL, $params, 'GET', false, [], $net_errno);
+
+        if (empty($resp)) {
+            return [false, '网络错误', true];
+        }
+        else
+        {
+            Log::record($resp, Log::DEBUG);
+            $resp = json_decode($resp, true);
+            if (empty($resp)) {
+                return [false, '网络错误', true];
+            } elseif ($resp['result_code'] == '00000') {
+                return [true, $resp['request_no'], false];
+            } else {
+                return [false, $resp['result_code'], false];
+            }
+        }
+    }
+
+    public function query($refill_info)
+    {
+        $params['partner_no'] = config::PARTNER_NO;
+        $params['orderNo'] = $refill_info['ch_trade_no'];
+        $params['timestamp'] = time();
+        $params['sign'] = $this->sign($params);
+
+        $resp = http_request(config::QUERY_URL, $params, 'GET', false, []);
+
+        if (empty($resp)) {
+            return [false, '网络错误'];
+        }
+        else
+        {
+            Log::record($resp, Log::DEBUG);
+            $resp = json_decode($resp, true);
+            if (empty($resp)) {
+                return [false, '网络错误'];
+            }
+            elseif($resp['resultCode'] == 1000)
+            {
+                $status = intval($resp['order']['orderStatus']);
+                if ($status === 4) {
+                    $order_state = ORDER_STATE_SUCCESS;
+                } elseif (in_array($status, [2,5])) {
+                    $order_state = ORDER_STATE_CANCEL;
+                } elseif (in_array($status, [0,1,3])) {
+                    $order_state = ORDER_STATE_SEND;
+                } else {
+                    return [false, $resp['resultReason']];
+                }
+                return [true, $order_state];
+            }
+            else
+            {
+                return [false, $resp['resultReason']];
+            }
+
+        }
+    }
+
+    public function balance()
+    {
+        $params['appkey'] = config::APP_KEY;
+        $params['timestamp'] = time();
+        $params['sign'] = $this->sign($params);
+
+        $resp = http_request(config::BALANCE_URL, $params, 'GET', false, [], $net_errno);
+
+        if (empty($resp)) {
+            return [false, '网络错误'];
+        }
+        else
+        {
+            Log::record($resp, Log::DEBUG);
+            $resp = json_decode($resp, true);
+            if (empty($resp)) {
+                return [false, '网络错误'];
+            } elseif ($resp['resultCode'] == 1000) {
+                return [true, $resp['balance']];
+            } else {
+                return [false, $resp['resultReason']];
+            }
+        }
+    }
+
+    private function sign($params)
+    {
+        ksort($params);
+
+        $content = '';
+        $secret = config::APP_SECRET;
+        foreach ($params as $key => $value) {
+            if($this->check_empty($value) === false) {
+                $content .= "{$key}{$value}";
+            }
+        }
+        $content .= $secret;
+        return md5(urlencode($content));
+    }
+}

+ 1 - 0
helper/refill/api/xyz/tianyi/account.txt

@@ -0,0 +1 @@
+https://800.189.cn/bms

+ 96 - 0
helper/refill/api/xyz/tianyi/config.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace refill\tianyi;
+
+class config
+{
+    const GET_MOBILE_INFO_URL = 'http://pms.liulianggo.com:8051/c/Mobile/getMobileInfo';
+    const GET_PRODUCT_URL = 'http://pms.liulianggo.com:8051/c/Product/getProductList';
+    const ORDER_URL = 'https://api.800.21cn.com/adapter/v1/remote/numberRecognitionUniversal.do';
+    const QUERY_URL = 'https://api.800.21cn.com/adapter/v1/remote/numberRecognitionCheck.do';
+    const BALANCE_URL = 'http://api.800.21cn.com/fps/queryChargeBalance.do';
+
+    const PARTNER_NO = '31d97598f492bae8';
+    const SECRET_KEY = 'b873fe4de54d9aa001238937d7061b65';
+    const IV = '111111';
+    const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_santi.php";
+
+    const Products =
+        [
+            //流量面值、使用范围、使用期限
+            'ST100747' => ['prodValue' => 1024, 'prodScope' => 1, 'validate' => 1],//	30	移动-1G-当月-全国
+            'ST100748' => ['prodValue' => 2048, 'prodScope' => 1, 'validate' => 1],//	50	移动-2G-当月-全国
+            'ST100749' => ['prodValue' => 3072, 'prodScope' => 1, 'validate' => 1],//	70	移动-3G-当月-全国
+            'ST100750' => ['prodValue' => 5120, 'prodScope' => 1, 'validate' => 1],//	100	移动-5G-当月-全国
+            'ST100751' => ['prodValue' => 10240, 'prodScope' => 1, 'validate' => 1],//	150	移动-10G-当月-全国
+            'ST100752' => ['prodValue' => 15360, 'prodScope' => 1, 'validate' => 1],//	200	移动-15G-当月-全国
+            'ST100753' => ['prodValue' => 30720, 'prodScope' => 1, 'validate' => 1],//	300	移动-30G-当月-全国
+
+            'ST100754' => ['prodValue' => 1024, 'prodScope' => 1, 'validate' => 2],//	5	移动-1G-1天-全国
+            'ST100755' => ['prodValue' => 2048, 'prodScope' => 1, 'validate' => 2],//	8	移动-2G-1天-全国
+            'ST100756' => ['prodValue' => 5120, 'prodScope' => 1, 'validate' => 7],//	15	移动-5G-7天-全国
+
+            'ST100757' => ['prodValue' => 1024, 'prodScope' => 1, 'validate' => 1],//	20	联通-1G-当月-全国
+            'ST100758' => ['prodValue' => 4096, 'prodScope' => 1, 'validate' => 1],//	55	联通-4G-当月-全国
+            'ST100759' => ['prodValue' => 20480, 'prodScope' => 1, 'validate' => 1],//	80	联通-20G-当月-全国
+
+            'ST100760' => ['prodValue' => 500, 'prodScope' => 1, 'validate' => 2],//	5	联通-500M-1天-全国
+            'ST100761' => ['prodValue' => 1024, 'prodScope' => 1, 'validate' => 2],//	7	联通-1G-1天-全国
+            'ST100762' => ['prodValue' => 2048, 'prodScope' => 1, 'validate' => 8],//	12	联通-2G-3天-全国
+            'ST100763' => ['prodValue' => 4096, 'prodScope' => 1, 'validate' => 7],//	16	联通-4G-7天-全国
+            'ST100764' => ['prodValue' => 10240, 'prodScope' => 1, 'validate' => 7],//	30	联通-10G-7天-全国
+
+            'ST100765' => ['prodValue' => 500, 'prodScope' => 1, 'validate' => 1],//	15	电信-500M-当月-全国
+            'ST100766' => ['prodValue' => 2048, 'prodScope' => 1, 'validate' => 1],//	30	电信-2G-当月-全国
+            'ST100767' => ['prodValue' => 6144, 'prodScope' => 1, 'validate' => 1],//	60	电信-6G-当月-全国
+            'ST100768' => ['prodValue' => 10240, 'prodScope' => 1, 'validate' => 1],//	80	电信-10G-当月-全国
+
+            'ST100769' => ['prodValue' => 2048, 'prodScope' => 1, 'validate' => 2],//	15	电信-2G-1天-全国
+            'ST100770' => ['prodValue' => 3072, 'prodScope' => 1, 'validate' => 8],//	20	电信-3G-3天-全国
+            'ST100771' => ['prodValue' => 10240, 'prodScope' => 1, 'validate' => 9],//	30	电信-10G-5天-全国
+        ];
+
+
+    private static function decodeBytes($hex)
+    {
+        $str = '';
+        for($i=0;$i<strlen($hex);$i+=2){
+            $tmpValue = (((ord($hex[$i]) - ord('a')) & 0xf ) <<4) + ((ord($hex[$i+1])- ord('a')) & 0xf);
+            $str .= chr($tmpValue);
+        }
+        return  $str;
+    }
+
+    private static function encodeBytes($string)
+    {
+        $str = '';
+        for($i=0;$i<strlen($string);$i++)
+        {
+            $tmpValue = ord($string[$i]);
+            $ch = ($tmpValue >> 4 & 0xf) + ord('a');
+            $str .= chr($ch);
+            $ch = ($tmpValue & 0xf) + ord('a');
+            $str .= chr($ch);
+        }
+        return $str;
+    }
+    /**
+     * 解密数据
+     * @param String $encryptedText 待解密密文
+     * @return String
+     */
+    public static function encrypt(string $encryptedText) {
+
+        $ciphertext = openssl_encrypt($encryptedText, "AES-128-CBC", self::SECRET_KEY, OPENSSL_RAW_DATA, self::IV);
+        return self::encodeBytes($ciphertext);
+    }
+    /**
+     * 加密数据
+     * @param String $encryptedText 待加密数据
+     * @return String
+     */
+    public static function decrypt(string $encryptedText) {
+        $encryptedText = self::decodeBytes($encryptedText);
+        return openssl_decrypt($encryptedText, "AES-128-CBC", self::SECRET_KEY, OPENSSL_RAW_DATA, self::IV);
+    }
+}