Skip to content

服务端接入助手

localSign签名

计算本地签名localSign = md5(nt_data+ sign+ md5Key),直接对nt_datasignmd5Key原文进行拼接即可,无需添加分隔符或对nt_data解码。

nt_data解码

参数nt_data解码后为XML格式,使用callbackKey可进行解码。

解码参考代码:

java
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NTDataUtil {

    private static final Pattern PATTERN = Pattern.compile("\\d+");
    private static final String CHARSET = "utf-8";

    // src传入nt_data,key传入callbackKey
    public static String decode(String src, String key) {
        if (src == null || key == null || src.isEmpty() || key.isEmpty()) {
            throw new IllegalArgumentException("Source string and key must not be null or empty.");
        }

        Matcher matcher = PATTERN.matcher(src);
        List<Integer> numbers = new ArrayList<>();
        while (matcher.find()) {
            numbers.add(Integer.parseInt(matcher.group()));
        }

        if (numbers.isEmpty()) {
            return src;
        }

        try {
            byte[] data = new byte[numbers.size()];
            byte[] keys = key.getBytes(CHARSET);

            for (int i = 0; i < data.length; i++) {
                data[i] = (byte) (numbers.get(i) - (0xff & keys[i % keys.length]));
            }
            return new String(data, CHARSET);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Unsupported charset: " + CHARSET, e);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid encoded string format.", e);
        }
    }
}
php
class NTDataUtil
{
    // $strEncode传入nt_data,$keys传入callbackKey
    public function decode($strEncode, $keys)
    {
        if (empty($strEncode)) {
            return $strEncode;
        }

        preg_match_all('/\\d+/', $strEncode, $matches);
        $list = $matches[0] ?? [];

        if (!empty($list)) {
            $keys = self::getBytes($keys);
            $keyCount = count($keys);
            $data = [];

            foreach ($list as $i => $value) {
                $keyVar = $keys[$i % $keyCount];
                $data[] = $value - (0xff & $keyVar);
            }

            return self::toStr($data);
        }

        return $strEncode;
    }

    private static function getBytes($string)
    {
        $bytes = [];
        for ($i = 0, $len = strlen($string); $i < $len; $i++) {
            $bytes[] = ord($string[$i]);
        }
        return $bytes;
    }

    private static function toStr(array $bytes)
    {
        return implode('', array_map('chr', $bytes));
    }
}
cpp
#pragma once
#include <string>
#include <regex>
#include <sstream>
#include <vector>

using namespace std;

class NTDataUtil {
public:
    // src传入nt_data,key传入callbackKey 
    static string decode(const string& src, const string& key) {
        if (src.empty()) {
            return src;
        }

        const regex pattern("(\\d+)");
        smatch matchResult;
        vector<int> list;

        const sregex_token_iterator end;
        for (sregex_token_iterator i(src.begin(), src.end(), pattern); i != end; ++i) {
            int n = stoi(i->str());
            list.push_back(n);
        }

        string data;
        for (size_t i = 0; i < list.size(); i++) {
            char c = list[i] - (0xff & key[i % key.size()]);
            data.append(1, c);
        }

        return data;
    }
};
python
class NTDataUtil:
    def get_bytes(self, data: str) -> list[int]:
        """将字符串转为字节列表"""
        return [ord(s) for s in data]

    def get_chars(self, byte_list: list[int]) -> str:
        """将字节列表转为字符串"""
        return ''.join(chr(n) for n in byte_list)

    # data传入nt_data,key传入callbackKey
    def decrypt_data(self, data: str, key: str) -> str:
        """解密数据"""
        try:
            data_parts = data.split("@")
            if not data_parts or data_parts[0] != '':
                raise ValueError("Invalid encrypted data format.")

            encrypted_values = map(int, data_parts[1:])
            key_bytes = self.get_bytes(key)
            key_len = len(key_bytes)

            decrypted = [
                value - (0xFF & key_bytes[i % key_len])
                for i, value in enumerate(encrypted_values)
            ]
            return self.get_chars(decrypted)
        except Exception as e:
            raise ValueError("Failed to decrypt data.") from e
javascript
// str传入nt_data,key传入callbackKey
function decode(str, key) {
  if (!str) return ''

  const matches = str.match(/\d+/g)
  if (!matches || matches.length === 0) return ''

  const keysBytes = stringToBytes(key)
  const dataBytes = matches.map(
    (num, i) => parseInt(num) - (keysBytes[i % keysBytes.length] & 0xff)
  )

  return dataBytes.length > 0 ? bytesToString(dataBytes) : ''
}

function stringToBytes(str) {
  const bytes = []
  for (let i = 0; i < str.length; i++) {
    let charCode = str.charCodeAt(i)
    const temp = []
    do {
      temp.unshift(charCode & 0xff)
      charCode >>= 8
    } while (charCode)
    bytes.push(...temp)
  }
  return bytes
}

function bytesToString(bytes) {
  return String.fromCharCode(...bytes)
}
csharp
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace NTDataUtil
{ 
    public class NTDataUtil
    {
        // src传入nt_data,key传入callbackKey
        public static string Decode(string src, string key)
        {
            if (string.IsNullOrEmpty(src) || string.IsNullOrEmpty(key))
            {
                return src;
            }

            try
            {
                var matches = Regex.Matches(src, "\\d+");
                var numbers = new List<int>();

                foreach (Match match in matches)
                {
                    numbers.Add(int.Parse(match.Value));
                }

                if (numbers.Count > 0)
                {
                    byte[] decodedData = new byte[numbers.Count];
                    byte[] keyBytes = Encoding.UTF8.GetBytes(key);

                    for (int i = 0; i < decodedData.Length; i++)
                    {
                        decodedData[i] = (byte)(numbers[i] - (0xff & keyBytes[i % keyBytes.Length]));
                    }

                    return Encoding.UTF8.GetString(decodedData);
                }

                return src;
            }
            catch
            {
                return src;
            }
        }
    }
}

坚果互娱(天津)网络科技有限公司