Appearance
服务端接入助手
localSign签名
计算本地签名localSign = md5(nt_data+ sign+ md5Key),直接对nt_data、sign、md5Key原文进行拼接即可,无需添加分隔符或对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 ejavascript
// 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;
}
}
}
}