This commit is contained in:
2026-05-27 16:57:43 +08:00
commit 8c1a09f075
195 changed files with 73506 additions and 0 deletions

View File

@@ -0,0 +1,282 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Net.Http;
using System.Threading.Tasks;
public class Program
{
// ==================== 配置区域 ====================
// 请根据实际情况修改以下配置参数
// AES加密密钥 (16进制字符串32位)
// API接口配置
private const string InterfaceName = "XXXXXXXX"; // 接口编号
private const string AccessId = "XXXXXXXXXXX"; // 访问ID
private const string EncryptionKey = "XXXXXXXXXXXXXXXXXXX"; // 加密密钥
private const string BaseUrl = "https://api.haiyudata.com"; // API基础URL
// 测试数据配置
private const string TestMobileNo = "13700000000"; // 测试手机号
private const string TestIdCard = "XXXXXXXXXXXXX"; // 测试身份证号
private const string TestName = "XXXXXXXX"; // 测试姓名
private const string TestAuthDate = "20250318-20270318"; // 测试授权日期
// HTTP请求配置
private const int RequestTimeout = 30000; // 请求超时时间(毫秒)
// ==================== 主程序 ====================
public static async Task Main()
{
Console.WriteLine("===== AES CBC 加密解密演示 =====");
// 1. 创建一个JSON对象
var data = new
{
mobile_no = TestMobileNo
};
// 将JSON对象序列化为字符串
string jsonString = JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine("\n原始JSON:");
Console.WriteLine(jsonString);
// 2. 加密JSON
Console.WriteLine("\n开始加密...");
string encryptedJson = Encrypt(jsonString);
Console.WriteLine($"加密成功! 加密后Base64:");
Console.WriteLine(encryptedJson);
// 3. 解密JSON
Console.WriteLine("\n开始解密...");
string decryptedJson = Decrypt(encryptedJson);
Console.WriteLine($"解密成功! 解密后的原始JSON:");
Console.WriteLine(decryptedJson);
// 4. 验证加解密一致性
Console.WriteLine("\n验证结果:");
if (jsonString == decryptedJson)
{
Console.WriteLine("✅ 加解密前后内容完全一致");
// 验证原始数据是否可用
Console.WriteLine("\n尝试解析解密后的JSON:");
try
{
var deserializedObject = JsonSerializer.Deserialize(decryptedJson, typeof(object));
Console.WriteLine($"✅ JSON解析成功类型: {deserializedObject.GetType()}");
}
catch (Exception ex)
{
Console.WriteLine($"❌ JSON解析失败: {ex.Message}");
}
}
else
{
Console.WriteLine("❌ 加解密前后内容不一致!");
Console.WriteLine("原始长度: " + jsonString.Length);
Console.WriteLine("解密后长度: " + decryptedJson.Length);
// 找出第一个不同的位置
for (int i = 0; i < Math.Min(jsonString.Length, decryptedJson.Length); i++)
{
if (jsonString[i] != decryptedJson[i])
{
Console.WriteLine($"第一个差异在位置 {i}:");
Console.WriteLine($"原始字符: '{jsonString[i]}' ({(int)jsonString[i]})");
Console.WriteLine($"解密字符: '{decryptedJson[i]}' ({(int)decryptedJson[i]})");
break;
}
}
}
// 5. 演示API调用流程可选
Console.WriteLine("\n===== 演示API调用流程 =====");
await DemonstrateApiCall();
}
// ==================== AES加密解密方法 ====================
/// <summary>
/// AES CBC 加密函数
/// 使用PKCS7填充随机IV返回Base64编码的密文
/// </summary>
/// <param name="plainText">要加密的明文</param>
/// <returns>Base64编码的密文</returns>
public static string Encrypt(string plainText)
{
byte[] key = HexToBytes(EncryptionKey);
using Aes aes = Aes.Create();
aes.Key = key;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.GenerateIV();
byte[] iv = aes.IV;
using ICryptoTransform encryptor = aes.CreateEncryptor();
using MemoryStream ms = new();
// 先写入IV
ms.Write(iv, 0, iv.Length);
using (CryptoStream cs = new(ms, encryptor, CryptoStreamMode.Write))
using (StreamWriter sw = new(cs))
{
sw.Write(plainText);
}
return Convert.ToBase64String(ms.ToArray());
}
/// <summary>
/// AES CBC 解密函数
/// 从Base64密文中提取IV和密文数据进行解密
/// </summary>
/// <param name="cipherText">Base64编码的密文</param>
/// <returns>解密后的明文</returns>
public static string Decrypt(string cipherText)
{
byte[] key = HexToBytes(EncryptionKey);
byte[] fullData = Convert.FromBase64String(cipherText);
// 提取前16字节作为IV
byte[] iv = new byte[16];
Buffer.BlockCopy(fullData, 0, iv, 0, iv.Length);
// 实际密文数据
byte[] cipherData = new byte[fullData.Length - 16];
Buffer.BlockCopy(fullData, 16, cipherData, 0, cipherData.Length);
using Aes aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
using ICryptoTransform decryptor = aes.CreateDecryptor();
using MemoryStream ms = new(cipherData);
using CryptoStream cs = new(ms, decryptor, CryptoStreamMode.Read);
using StreamReader sr = new(cs);
return sr.ReadToEnd();
}
/// <summary>
/// 将16进制字符串转换为字节数组
/// </summary>
/// <param name="hex">16进制字符串</param>
/// <returns>字节数组</returns>
private static byte[] HexToBytes(string hex)
{
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < hex.Length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
// ==================== API调用演示方法 ====================
/// <summary>
/// 演示完整的API调用流程
/// 包括:参数构建、加密、发送请求、接收响应、解密响应
/// </summary>
private static async Task DemonstrateApiCall()
{
try
{
// 构建完整的API URL
string url = $"{BaseUrl}/api/v1/{InterfaceName}";
// 构建请求参数
var apiParams = new
{
mobile_no = TestMobileNo,
id_card = TestIdCard,
auth_date = TestAuthDate,
name = TestName
};
// 将参数转换为JSON字符串并加密
string jsonStr = JsonSerializer.Serialize(apiParams);
Console.WriteLine($"请求参数: {jsonStr}");
string encryptedData = Encrypt(jsonStr);
Console.WriteLine($"加密后的数据: {encryptedData}");
// 构建请求体
var payload = new { data = encryptedData };
string requestBody = JsonSerializer.Serialize(payload);
Console.WriteLine($"发送请求到: {url}");
// 发送HTTP请求
using (var httpClient = new HttpClient())
{
// 设置请求头
httpClient.DefaultRequestHeaders.Add("Access-Id", AccessId);
httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json");
// 设置超时时间
httpClient.Timeout = TimeSpan.FromMilliseconds(RequestTimeout);
var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(url, content);
Console.WriteLine($"响应状态码: {response.StatusCode}");
if (response.IsSuccessStatusCode)
{
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine($"API响应: {responseBody}");
// 解析响应
try
{
var responseData = JsonSerializer.Deserialize<JsonElement>(responseBody);
if (responseData.TryGetProperty("code", out var codeElement))
{
int code = codeElement.GetInt32();
string message = responseData.TryGetProperty("message", out var msgElement) ? msgElement.GetString() : "";
string encryptedResponse = responseData.TryGetProperty("data", out var dataElement) ? dataElement.GetString() : "";
Console.WriteLine($"API响应码: {code}");
Console.WriteLine($"API消息: {message}");
if (code == 0 && !string.IsNullOrEmpty(encryptedResponse))
{
// 解密响应数据
try
{
string decryptedResponse = Decrypt(encryptedResponse);
Console.WriteLine($"解密后的响应: {decryptedResponse}");
}
catch (Exception ex)
{
Console.WriteLine($"解密响应数据失败: {ex.Message}");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"解析响应失败: {ex.Message}");
}
}
else
{
Console.WriteLine($"请求失败: {response.StatusCode}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"API调用异常: {ex.Message}");
}
}
}

305
public/examples/go/demo.go Normal file
View File

@@ -0,0 +1,305 @@
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// ==================== 配置区域 ====================
// 请根据实际情况修改以下配置参数
const (
// API接口配置
InterfaceName = "XXXXXXXX" // 接口编号
AccessID = "XXXXXXXXXXX"
EncryptionKey = "XXXXXXXXXXXXXXXXXXXXX"
BaseURL = "https://api.haiyudata.com"
// 测试数据配置
TestName = "XXXXXXXX"
TestIDCard = "XXXXXXXXXXXXX"
TestMobileNo = "XXXXXXXXXXXXXXXXXXXX"
TestAuthDate = "20250318-20270318"
// HTTP请求配置
RequestTimeout = 30 * time.Second
)
// API响应结构体
type APIResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Data string `json:"data"`
}
// 请求参数结构体
type RequestParams struct {
MobileNo string `json:"mobile_no"`
IDCard string `json:"id_card"`
AuthDate string `json:"auth_date"`
Name string `json:"name"`
}
// 请求载荷结构体
type RequestPayload struct {
Data string `json:"data"`
}
// 结果结构体
type Result struct {
Code int `json:"code"`
Success bool `json:"success"`
Message string `json:"message"`
EncryptedResponse string `json:"encrypted_response"`
DecryptedResponse interface{} `json:"decrypted_response"`
}
// ==================== AES加密解密方法 ====================
// AES CBC 加密函数,返回 Base64
func aesEncrypt(plaintext, key string) (string, error) {
keyBytes, err := hex.DecodeString(key)
if err != nil {
return "", err
}
block, err := aes.NewCipher(keyBytes)
if err != nil {
return "", err
}
// 生成随机IV
iv := make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
// 填充数据
paddedData := pkcs7Pad([]byte(plaintext), aes.BlockSize)
// 加密
ciphertext := make([]byte, len(iv)+len(paddedData))
copy(ciphertext, iv)
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[len(iv):], paddedData)
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
// AES CBC 解密函数,返回解密后的明文
func aesDecrypt(encryptedText, key string) (string, error) {
keyBytes, err := hex.DecodeString(key)
if err != nil {
return "", err
}
ciphertext, err := base64.StdEncoding.DecodeString(encryptedText)
if err != nil {
return "", err
}
block, err := aes.NewCipher(keyBytes)
if err != nil {
return "", err
}
if len(ciphertext) < aes.BlockSize {
return "", fmt.Errorf("密文太短")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
if len(ciphertext)%aes.BlockSize != 0 {
return "", fmt.Errorf("密文长度不是块大小的倍数")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)
// 去除填充
unpaddedData, err := pkcs7Unpad(ciphertext)
if err != nil {
return "", err
}
return string(unpaddedData), nil
}
// PKCS7填充
func pkcs7Pad(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padtext...)
}
// PKCS7去除填充
func pkcs7Unpad(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, fmt.Errorf("数据为空")
}
unpadding := int(data[length-1])
if unpadding > length {
return nil, fmt.Errorf("无效的填充")
}
return data[:length-unpadding], nil
}
// ==================== API调用方法 ====================
// 调用API函数
func callAPI(name, idCard, mobileNo, authDate string) *Result {
// 构建完整的API URL
url := fmt.Sprintf("%s/api/v1/%s", BaseURL, InterfaceName)
// 构建请求参数
params := RequestParams{
MobileNo: mobileNo,
IDCard: idCard,
AuthDate: authDate,
Name: name,
}
// 将参数转换为JSON字符串并加密
jsonStr, err := json.Marshal(params)
if err != nil {
return &Result{
Success: false,
Message: fmt.Sprintf("JSON序列化失败: %v", err),
}
}
fmt.Printf("请求参数: %s\n", string(jsonStr))
encryptedData, err := aesEncrypt(string(jsonStr), EncryptionKey)
if err != nil {
return &Result{
Success: false,
Message: fmt.Sprintf("加密失败: %v", err),
}
}
fmt.Printf("加密后的数据: %s\n", encryptedData)
// 构建请求载荷
payload := RequestPayload{
Data: encryptedData,
}
// 序列化请求载荷
requestBody, err := json.Marshal(payload)
if err != nil {
return &Result{
Success: false,
Message: fmt.Sprintf("请求载荷序列化失败: %v", err),
}
}
fmt.Printf("发送请求到: %s\n", url)
// 发送HTTP请求
client := &http.Client{
Timeout: RequestTimeout,
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
if err != nil {
return &Result{
Success: false,
Message: fmt.Sprintf("创建请求失败: %v", err),
}
}
// 设置请求头
req.Header.Set("Access-Id", AccessID)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
return &Result{
Success: false,
Message: fmt.Sprintf("请求失败: %v", err),
}
}
defer resp.Body.Close()
// 读取响应
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return &Result{
Success: false,
Message: fmt.Sprintf("读取响应失败: %v", err),
}
}
// 解析响应
var apiResp APIResponse
if err := json.Unmarshal(respBody, &apiResp); err != nil {
return &Result{
Success: false,
Message: fmt.Sprintf("解析响应失败: %v", err),
}
}
fmt.Printf("API响应: %s\n", string(respBody))
// 处理响应
result := &Result{
Code: apiResp.Code,
Success: apiResp.Code == 0,
Message: apiResp.Message,
EncryptedResponse: apiResp.Data,
}
// 如果有返回data尝试解密
if apiResp.Data != "" {
decryptedData, err := aesDecrypt(apiResp.Data, EncryptionKey)
if err != nil {
fmt.Printf("解密响应数据失败: %v\n", err)
result.DecryptedResponse = nil
} else {
var decryptedJSON interface{}
if err := json.Unmarshal([]byte(decryptedData), &decryptedJSON); err != nil {
fmt.Printf("解析解密后的JSON失败: %v\n", err)
result.DecryptedResponse = decryptedData
} else {
result.DecryptedResponse = decryptedJSON
}
}
}
return result
}
// ==================== 主程序 ====================
func main() {
fmt.Println("===== 个人涉诉详版 =====")
// 调用API
result := callAPI(TestName, TestIDCard, TestMobileNo, TestAuthDate)
fmt.Println("\n===== 结果 =====")
if result.Success {
fmt.Println("请求成功!")
if result.DecryptedResponse != nil {
decryptedJSON, _ := json.MarshalIndent(result.DecryptedResponse, "", " ")
fmt.Printf("解密后的响应: %s\n", string(decryptedJSON))
} else {
fmt.Println("未能获取或解密响应数据")
}
} else {
fmt.Printf("请求失败: %s\n", result.Message)
}
}

View File

@@ -0,0 +1,129 @@
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Random;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.json.JSONObject;
public class Demo {
// 加密
public static String aesEncrypt(String plainText, String hexKey) throws Exception {
byte[] keyBytes = hexStringToByteArray(hexKey);
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
// 拼接 IV 和密文
byte[] encryptedData = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, encryptedData, 0, iv.length);
System.arraycopy(encrypted, 0, encryptedData, iv.length, encrypted.length);
return Base64.getEncoder().encodeToString(encryptedData);
}
// 解密
public static String aesDecrypt(String encryptedText, String hexKey) throws Exception {
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
byte[] keyBytes = hexStringToByteArray(hexKey);
byte[] iv = new byte[16];
System.arraycopy(encryptedBytes, 0, iv, 0, 16);
byte[] encryptedData = new byte[encryptedBytes.length - 16];
System.arraycopy(encryptedBytes, 16, encryptedData, 0, encryptedData.length);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
byte[] decrypted = cipher.doFinal(encryptedData);
return new String(decrypted, StandardCharsets.UTF_8);
}
// Helper 方法,将 16 进制字符串转为字节数组
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
return data;
}
// 发送 HTTP POST 请求
public static String sendPostRequest(String urlString, String data, String accessId) throws Exception {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Access-Id", accessId);
connection.setDoOutput(true);
// 构造请求体
String jsonInputString = "{\"data\":\"" + data + "\"}";
try (OutputStream os = connection.getOutputStream()) {
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
}
// 读取响应
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
return response.toString();
}
public static void main(String[] args) {
try {
// 设置 URL、密钥和请求参数
String url = "https://api.haiyudata.com/api/v1/IVYZ5733";
String accessId = "XXXXXXXXXXXXX";
String key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// 请求参数
JSONObject requestParams = new JSONObject();
requestParams.put("name", "李四");
requestParams.put("id_card", "110101199003076534");
// 将请求参数转为 JSON 字符串
String jsonStr = requestParams.toString();
// 加密请求数据
String encryptedData = aesEncrypt(jsonStr, key);
// 发送 HTTP POST 请求并获取响应
String response = sendPostRequest(url, encryptedData, accessId);
// 解析响应数据
JSONObject responseData = new JSONObject(response);
String encryptedResponseData = responseData.optString("data");
// 解密返回的加密数据
if (encryptedResponseData != null) {
String decryptedResponseData = aesDecrypt(encryptedResponseData, key);
System.out.println("Decrypted Response Data: " + decryptedResponseData);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,266 @@
/**
* 短信发送接口签名示例(浏览器版本)
*
* 本示例演示如何在浏览器中为短信发送接口生成HMAC-SHA256签名
*
* 安全提示:
* 1. 密钥应该通过代码混淆、字符串拆分等方式隐藏
* 2. 不要在前端代码中直接暴露完整密钥
* 3. 建议使用构建工具进行代码混淆和压缩
* 4. 可以考虑将签名逻辑放在后端代理接口中
*/
/**
* 获取签名密钥(通过多种方式混淆,增加破解难度)
* 注意:这只是示例,实际使用时应该进一步混淆
*/
function getSecretKey() {
// 方式1: 字符串拆分和拼接
const part1 = 'HyApi2026'
const part2 = 'SMSSecret'
const part3 = 'Key!@#$%^'
const part4 = '&*()_+QWERTY'
const part5 = 'UIOP'
// 方式2: 使用数组和join增加混淆
const arr = [part1, part2, part3, part4, part5]
return arr.join('')
// 方式3: 字符数组拼接(更复杂的方式)
// const chars = ['T', 'y', 'A', 'p', 'i', '2', '0', '2', '4', ...];
// return chars.join('');
// 方式4: 使用atob解码如果密钥经过base64编码
// const encoded = 'base64_encoded_string';
// return atob(encoded);
}
/**
* 生成随机字符串用于nonce
*/
function generateNonce(length = 16) {
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
let result = ''
const array = new Uint8Array(length)
crypto.getRandomValues(array)
for (let i = 0; i < length; i++) {
result += chars[array[i] % chars.length]
}
return result
}
/**
* 使用Web Crypto API生成HMAC-SHA256签名
*
* @param {Object} params - 请求参数对象
* @param {string} secretKey - 签名密钥
* @param {number} timestamp - 时间戳(秒)
* @param {string} nonce - 随机字符串
* @returns {Promise<string>} 签名字符串hex编码
*/
async function generateSignature(params, secretKey, timestamp, nonce) {
// 1. 构建待签名字符串按key排序拼接成 key1=value1&key2=value2 格式
const keys = Object.keys(params)
.filter((k) => k !== 'signature') // 排除签名字段
.sort()
const parts = keys.map((k) => `${k}=${params[k]}`)
// 2. 添加时间戳和随机数
parts.push(`timestamp=${timestamp}`)
parts.push(`nonce=${nonce}`)
// 3. 拼接成待签名字符串
const signString = parts.join('&')
// 4. 使用Web Crypto API计算HMAC-SHA256签名
const encoder = new TextEncoder()
const keyData = encoder.encode(secretKey)
const messageData = encoder.encode(signString)
// 导入密钥
const cryptoKey = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign'],
)
// 计算签名
const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData)
// 转换为hex字符串
const hashArray = Array.from(new Uint8Array(signature))
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
return hashHex
}
/**
* 自定义编码字符集(与后端保持一致)
*/
const CUSTOM_ENCODE_CHARSET =
'0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz!@#$%^&*()_+-=[]{}|;:,.<>?'
/**
* 自定义Base64编码使用自定义字符集
*/
function customBase64Encode(data) {
if (data.length === 0) return ''
// 将字符串转换为UTF-8字节数组
const encoder = new TextEncoder()
const bytes = encoder.encode(data)
const charset = CUSTOM_ENCODE_CHARSET
let result = ''
// 将3个字节24位编码为4个字符
for (let i = 0; i < bytes.length; i += 3) {
const b1 = bytes[i]
const b2 = i + 1 < bytes.length ? bytes[i + 1] : 0
const b3 = i + 2 < bytes.length ? bytes[i + 2] : 0
// 组合成24位
const combined = (b1 << 16) | (b2 << 8) | b3
// 分成4个6位段
result += charset[(combined >> 18) & 0x3f]
result += charset[(combined >> 12) & 0x3f]
if (i + 1 < bytes.length) {
result += charset[(combined >> 6) & 0x3f]
} else {
result += '=' // 填充字符
}
if (i + 2 < bytes.length) {
result += charset[combined & 0x3f]
} else {
result += '=' // 填充字符
}
}
return result
}
/**
* 应用字符偏移混淆
*/
function applyCharShift(data, shift) {
const charset = CUSTOM_ENCODE_CHARSET
const charsetLen = charset.length
let result = ''
for (let i = 0; i < data.length; i++) {
const c = data[i]
if (c === '=') {
result += c // 填充字符不变
continue
}
const idx = charset.indexOf(c)
if (idx === -1) {
result += c // 不在字符集中,保持不变
} else {
// 应用偏移
const newIdx = (idx + shift) % charsetLen
result += charset[newIdx]
}
}
return result
}
/**
* 自定义编码请求数据
*/
function encodeRequest(data) {
// 1. 使用自定义Base64编码
const encoded = customBase64Encode(data)
// 2. 应用字符偏移混淆偏移7个位置
const confused = applyCharShift(encoded, 7)
return confused
}
/**
* 发送短信验证码(带签名)- 方式2编码后传输推荐更安全
* 将所有参数(包括签名)使用自定义编码方案编码后传输,隐藏参数结构
*
* @param {string} phone - 手机号
* @param {string} scene - 场景register/login/change_password/reset_password等
* @param {string} apiBaseUrl - API基础URL
* @returns {Promise<Object>} 响应结果
*/
async function sendSMSWithEncodedSignature(phone, scene, apiBaseUrl = 'http://localhost:8080') {
// 1. 准备参数
const timestamp = Math.floor(Date.now() / 1000) // 当前时间戳(秒)
const nonce = generateNonce(16) // 生成随机字符串
const params = {
phone: phone,
scene: scene,
}
// 2. 生成签名
const secretKey = getSecretKey()
const signature = await generateSignature(params, secretKey, timestamp, nonce)
// 3. 构建包含所有参数的JSON对象
const allParams = {
phone: phone,
scene: scene,
timestamp: timestamp,
nonce: nonce,
signature: signature,
}
// 4. 将JSON对象转换为字符串然后使用自定义编码方案编码
const jsonString = JSON.stringify(allParams)
const encodedData = encodeRequest(jsonString)
// 5. 构建请求体只包含编码后的data字段
const requestBody = {
data: encodedData,
}
// 6. 发送请求
try {
const response = await fetch(`${apiBaseUrl}/api/v1/users/send-code`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
})
const result = await response.json()
return result
} catch (error) {
console.error('发送短信失败:', error)
throw error
}
}
// 如果在浏览器环境中使用,可以导出到全局
if (typeof window !== 'undefined') {
window.SMSSignature = {
sendSMSWithEncodedSignature,
generateSignature,
generateNonce,
encodeRequest,
}
}
// 如果在Node.js环境中使用需要安装crypto-js等库
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
sendSMSWithEncodedSignature,
generateSignature,
generateNonce,
getSecretKey,
encodeRequest,
}
}

View File

@@ -0,0 +1,11 @@
# ESLint 忽略配置 - 忽略示例代码目录下的所有语法错误
# 这些是示例代码文件,不需要进行 ESLint 语法检查
# 忽略当前目录下的所有 .js 文件
*.js
# 忽略当前目录下的所有文件
*
# 忽略子目录
*/

View File

@@ -0,0 +1,131 @@
#!/usr/bin/env node
const crypto = require('crypto')
// ==================== API配置 ====================
const ACCESS_ID = 'XXXXXXXXX' // 替换为您的ACCESS_ID
const APP_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXX' // 替换为您的app_secret
const BASE_URL = 'https://api.haiyudata.com'
// ==================== 测试参数 ====================
const API_CODE = 'FLXG0V4B' // 替换为您的API编号
const PARAMS = {
name: 'XXXX',
id_card: 'XXXXXXXXXXXXXXX',
auth_date: '20250722-20250923',
}
// ==================== 加密解密函数 ====================
function encrypt_data(data) {
const key = Buffer.from(APP_SECRET, 'hex')
const iv = crypto.randomBytes(16)
const cipher = crypto.createCipheriv('aes-128-cbc', key, iv)
cipher.setAutoPadding(true)
let encrypted = cipher.update(data, 'utf8')
encrypted = Buffer.concat([iv, encrypted, cipher.final()])
return encrypted.toString('base64')
}
function decrypt_data(encrypted_data) {
const key = Buffer.from(APP_SECRET, 'hex')
const encryptedBuffer = Buffer.from(encrypted_data, 'base64')
const iv = encryptedBuffer.slice(0, 16)
const ciphertext = encryptedBuffer.slice(16)
const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv)
decipher.setAutoPadding(true)
let decrypted = decipher.update(ciphertext)
decrypted = Buffer.concat([decrypted, decipher.final()])
return decrypted.toString('utf8')
}
// ==================== 主测试函数 ====================
async function test_api() {
try {
console.log(`=== 测试API: ${API_CODE} ===`)
console.log(`请求参数: ${JSON.stringify(PARAMS, null, 2)}`)
// 加密参数
const params_json = JSON.stringify(PARAMS)
const encrypted_data = encrypt_data(params_json)
// 构建请求
const headers = {
'Content-Type': 'application/json',
'Access-Id': ACCESS_ID,
}
const url = `${BASE_URL}/api/v1/${API_CODE}`
const request_data = { data: encrypted_data, options: { json: true } }
console.log(`请求URL: ${url}`)
console.log(`请求头: ${JSON.stringify(headers, null, 2)}`)
// 发送请求
const start_time = Date.now()
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(request_data),
signal: AbortSignal.timeout(30000), // 30秒超时
})
const elapsed_time = Date.now() - start_time
console.log(`\n=== 响应信息 ===`)
console.log(`状态码: ${response.status}`)
console.log(`耗时: ${elapsed_time}ms`)
if (response.status !== 200) {
console.log(`请求失败: ${response.status} ${response.statusText}`)
return
}
// 解析响应
try {
const response_json = await response.json()
console.log(`原始响应: ${JSON.stringify(response_json, null, 2)}`)
// 检查响应格式
if (!('code' in response_json)) {
console.log('直接返回业务数据')
return
}
// 标准格式处理
const api_code = response_json.code
const api_message = response_json.message || ''
const encrypted_response = response_json.data || ''
console.log(`API响应码: ${api_code}`)
console.log(`API消息: ${api_message}`)
if (api_code !== 0) {
console.log(`API错误: ${api_message}`)
return
}
if (!encrypted_response) {
console.log('无加密数据返回')
return
}
// 解密数据
try {
const decrypted_data = decrypt_data(encrypted_response)
const result_data = JSON.parse(decrypted_data)
console.log(`\n=== 解密后的数据 ===`)
console.log(JSON.stringify(result_data, null, 2))
} catch (e) {
console.log(`解密失败: ${e.message}`)
}
} catch (e) {
console.log(`响应不是JSON格式: ${e.message}`)
}
} catch (e) {
console.log(`测试异常: ${e.message}`)
}
}
// 运行测试
test_api()

View File

@@ -0,0 +1,287 @@
/**
* 短信发送接口签名示例
*
* 本示例演示如何为短信发送接口生成HMAC-SHA256签名
*
* 安全提示:
* 1. 密钥应该通过代码混淆、字符串拆分等方式隐藏
* 2. 不要在前端代码中直接暴露完整密钥
* 3. 建议使用构建工具进行代码混淆
*/
const crypto = require('crypto')
/**
* 获取签名密钥(通过多种方式混淆,增加破解难度)
* 注意:这只是示例,实际使用时应该进一步混淆
*/
function getSecretKey() {
// 方式1: 字符串拆分和拼接
const part1 = 'HyApi2026'
const part2 = 'SMSSecret'
const part3 = 'Key!@#$%^'
const part4 = '&*()_+QWERTY'
const part5 = 'UIOP'
// 方式2: Base64解码可选增加一层混淆
// const encoded = Buffer.from('some_base64_string', 'base64').toString();
// 方式3: 字符数组拼接
const chars = [
'T',
'y',
'A',
'p',
'i',
'2',
'0',
'2',
'4',
'S',
'M',
'S',
'S',
'e',
'c',
'r',
'e',
't',
'K',
'e',
'y',
'!',
'@',
'#',
'$',
'%',
'^',
'&',
'*',
'(',
')',
'_',
'+',
'Q',
'W',
'E',
'R',
'T',
'Y',
'U',
'I',
'O',
'P',
]
const fromChars = chars.join('')
// 组合多种方式实际密钥HyApi2026SMSSecretKey!@#$%^&*()_+QWERTYUIOP
return part1 + part2 + part3 + part4 + part5
}
/**
* 生成随机字符串用于nonce
*/
function generateNonce(length = 16) {
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
let result = ''
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length))
}
return result
}
/**
* 生成HMAC-SHA256签名
*
* @param {Object} params - 请求参数对象
* @param {string} secretKey - 签名密钥
* @param {number} timestamp - 时间戳(秒)
* @param {string} nonce - 随机字符串
* @returns {string} 签名字符串hex编码
*/
function generateSignature(params, secretKey, timestamp, nonce) {
// 1. 构建待签名字符串按key排序拼接成 key1=value1&key2=value2 格式
const keys = Object.keys(params)
.filter((k) => k !== 'signature') // 排除签名字段
.sort()
const parts = keys.map((k) => `${k}=${params[k]}`)
// 2. 添加时间戳和随机数
parts.push(`timestamp=${timestamp}`)
parts.push(`nonce=${nonce}`)
// 3. 拼接成待签名字符串
const signString = parts.join('&')
// 4. 使用HMAC-SHA256计算签名
const signature = crypto.createHmac('sha256', secretKey).update(signString).digest('hex')
return signature
}
/**
* 自定义编码字符集(与后端保持一致)
*/
const CUSTOM_ENCODE_CHARSET =
'0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz!@#$%^&*()_+-=[]{}|;:,.<>?'
/**
* 自定义Base64编码使用自定义字符集
*/
function customBase64Encode(data) {
if (data.length === 0) return ''
const bytes = Buffer.from(data, 'utf8')
const charset = CUSTOM_ENCODE_CHARSET
let result = ''
// 将3个字节24位编码为4个字符
for (let i = 0; i < bytes.length; i += 3) {
const b1 = bytes[i]
const b2 = i + 1 < bytes.length ? bytes[i + 1] : 0
const b3 = i + 2 < bytes.length ? bytes[i + 2] : 0
// 组合成24位
const combined = (b1 << 16) | (b2 << 8) | b3
// 分成4个6位段
result += charset[(combined >> 18) & 0x3f]
result += charset[(combined >> 12) & 0x3f]
if (i + 1 < bytes.length) {
result += charset[(combined >> 6) & 0x3f]
} else {
result += '=' // 填充字符
}
if (i + 2 < bytes.length) {
result += charset[combined & 0x3f]
} else {
result += '=' // 填充字符
}
}
return result
}
/**
* 应用字符偏移混淆
*/
function applyCharShift(data, shift) {
const charset = CUSTOM_ENCODE_CHARSET
const charsetLen = charset.length
let result = ''
for (let i = 0; i < data.length; i++) {
const c = data[i]
if (c === '=') {
result += c // 填充字符不变
continue
}
const idx = charset.indexOf(c)
if (idx === -1) {
result += c // 不在字符集中,保持不变
} else {
// 应用偏移
const newIdx = (idx + shift) % charsetLen
result += charset[newIdx]
}
}
return result
}
/**
* 自定义编码请求数据
*/
function encodeRequest(data) {
// 1. 使用自定义Base64编码
const encoded = customBase64Encode(data)
// 2. 应用字符偏移混淆偏移7个位置
const confused = applyCharShift(encoded, 7)
return confused
}
/**
* 发送短信验证码(带签名)- 方式2编码后传输推荐更安全
* 将所有参数(包括签名)使用自定义编码方案编码后传输,隐藏参数结构
*
* @param {string} phone - 手机号
* @param {string} scene - 场景register/login/change_password/reset_password等
* @param {string} apiBaseUrl - API基础URL
* @returns {Promise<Object>} 响应结果
*/
async function sendSMSWithEncodedSignature(phone, scene, apiBaseUrl = 'http://localhost:8080') {
// 1. 准备参数
const timestamp = Math.floor(Date.now() / 1000) // 当前时间戳(秒)
const nonce = generateNonce(16) // 生成随机字符串
const params = {
phone: phone,
scene: scene,
}
// 2. 生成签名
const secretKey = getSecretKey()
const signature = generateSignature(params, secretKey, timestamp, nonce)
// 3. 构建包含所有参数的JSON对象
const allParams = {
phone: phone,
scene: scene,
timestamp: timestamp,
nonce: nonce,
signature: signature,
}
// 4. 将JSON对象转换为字符串然后使用自定义编码方案编码
const jsonString = JSON.stringify(allParams)
const encodedData = encodeRequest(jsonString)
// 5. 构建请求体只包含编码后的data字段
const requestBody = {
data: encodedData,
}
// 6. 发送请求
try {
const response = await fetch(`${apiBaseUrl}/api/v1/users/send-code`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
})
const result = await response.json()
return result
} catch (error) {
console.error('发送短信失败:', error)
throw error
}
}
// 使用示例
if (require.main === module) {
console.log('=== 发送短信验证码(使用自定义编码) ===')
// 示例发送注册验证码使用自定义编码方案只传递data字段
sendSMSWithEncodedSignature('13800138000', 'register', 'http://localhost:8080')
.then((result) => {
console.log('发送成功:', result)
})
.catch((error) => {
console.error('发送失败:', error)
})
}
module.exports = {
sendSMSWithEncodedSignature,
generateSignature,
generateNonce,
getSecretKey,
encodeRequest,
}

View File

@@ -0,0 +1,176 @@
<?php
/**
* AES CBC 加密函数,返回 Base64
* @param string $plainText 要加密的明文
* @param string $key 16进制密钥
* @return string 加密后的Base64字符串
*/
function aesEncrypt($plainText, $key) {
// 将16进制的密钥转换为二进制
$keyBin = hex2bin($key);
// 生成随机IV
$blockSize = 16; // AES 块大小
$iv = openssl_random_pseudo_bytes($blockSize);
// 加密
$encrypted = openssl_encrypt(
$plainText,
'AES-128-CBC',
$keyBin,
OPENSSL_RAW_DATA,
$iv
);
// 将IV和加密数据拼接后进行Base64编码
return base64_encode($iv . $encrypted);
}
/**
* AES CBC 解密函数,返回解密后的明文
* @param string $encryptedText Base64编码的加密文本
* @param string $key 16进制密钥
* @return string 解密后的明文
*/
function aesDecrypt($encryptedText, $key) {
// 将16进制的密钥转换为二进制
$keyBin = hex2bin($key);
// 解码Base64
$encryptedBin = base64_decode($encryptedText);
// 提取IV和加密数据
$blockSize = 16;
$iv = substr($encryptedBin, 0, $blockSize);
$encryptedData = substr($encryptedBin, $blockSize);
// 解密
$decrypted = openssl_decrypt(
$encryptedData,
'AES-128-CBC',
$keyBin,
OPENSSL_RAW_DATA,
$iv
);
return $decrypted;
}
/**
* 调用API函数
*/
function callApi($name, $id_card, $mobile_no, $auth_date) {
// API相关配置
$interface_name = "XXXXXXXX"; // 接口编号
$access_id = "XXXXXXXXXXX";
$key = "XXXXXXXXXXXXXXXXXXXXX";
$url = "https://api.haiyudata.com/api/v1/{$interface_name}";
// 构建请求参数
$params = array(
"mobile_no" => $mobile_no,
"id_card" => $id_card,
"auth_date" => $auth_date,
"name" => $name
);
// 将参数转换为JSON字符串并加密
$json_str = json_encode($params, JSON_UNESCAPED_UNICODE);
echo "请求参数: {$json_str}\n";
$encrypted_data = aesEncrypt($json_str, $key);
echo "加密后的数据: {$encrypted_data}\n";
// 发送请求
$headers = array(
"Access-Id: {$access_id}",
"Content-Type: application/json"
);
$payload = array(
"data" => $encrypted_data
);
echo "发送请求到: {$url}\n";
try {
// 使用PHP原生HTTP请求方式
$context = stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => implode("\r\n", $headers),
'content' => json_encode($payload),
'timeout' => 30
)
));
$response = file_get_contents($url, false, $context);
if ($response === false) {
throw new Exception("HTTP请求失败");
}
$response_data = json_decode($response, true);
echo "API响应: " . json_encode($response_data, JSON_UNESCAPED_UNICODE) . "\n";
// 处理响应
$code = $response_data['code'] ?? null;
$message = $response_data['message'] ?? '';
$encrypted_response_data = $response_data['data'] ?? '';
$result = array(
"code" => $code,
"success" => $code == 0,
"message" => $message,
"encrypted_response" => $encrypted_response_data
);
// 如果有返回data尝试解密
if ($encrypted_response_data) {
try {
$decrypted_data = aesDecrypt($encrypted_response_data, $key);
$result["decrypted_response"] = json_decode($decrypted_data, true);
} catch (Exception $e) {
echo "解密响应数据失败: {$e->getMessage()}\n";
$result["decrypted_response"] = null;
}
}
return $result;
} catch (Exception $e) {
echo "请求失败: {$e->getMessage()}\n";
return array("success" => false, "message" => "请求失败: {$e->getMessage()}");
}
}
/**
* 主函数
*/
function main() {
echo "===== 个人涉诉详版 =====\n";
// 直接设置手机号和姓名
$name = "XXXXXXXX";
$id_card = "XXXXXXXXXXXXX";
$mobile_no = "XXXXXXXXXXXXXXXXXXXX";
$auth_date = "20250318-20270318";
$result = callApi($name, $id_card, $mobile_no, $auth_date);
echo "\n===== 结果 =====\n";
if ($result["success"]) {
echo "请求成功!\n";
if (isset($result["decrypted_response"])) {
echo "解密后的响应: " . json_encode($result['decrypted_response'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
} else {
echo "未能获取或解密响应数据\n";
}
} else {
echo "请求失败: " . ($result['message'] ?? '未知错误') . "\n";
}
}
// 运行主函数
main();
?>

View File

@@ -0,0 +1,124 @@
import requests
import json
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import os
# AES CBC 加密函数,返回 Base64
def aes_encrypt(plaintext, key):
# 将16进制密钥转换为字节
key_bytes = bytes.fromhex(key)
# 生成随机IV
iv = os.urandom(16)
# 创建加密器
cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
# 对明文进行填充并加密
padded_data = pad(plaintext.encode('utf-8'), AES.block_size)
encrypted_data = cipher.encrypt(padded_data)
# 连接IV和加密后的数据
result = iv + encrypted_data
# 转换为Base64编码
return base64.b64encode(result).decode('utf-8')
# AES CBC 解密函数,返回解密后的明文
def aes_decrypt(encrypted_text, key):
# 将Base64编码的加密数据转换为字节
encrypted_bytes = base64.b64decode(encrypted_text)
# 将16进制密钥转换为字节
key_bytes = bytes.fromhex(key)
# 从加密数据中提取IV和加密数据
iv = encrypted_bytes[:16]
encrypted_data = encrypted_bytes[16:]
# 创建解密器
decipher = AES.new(key_bytes, AES.MODE_CBC, iv)
# 解密并去除填充
padded_data = decipher.decrypt(encrypted_data)
return unpad(padded_data, AES.block_size).decode('utf-8')
def CallApi(name,id_card,mobile_no,auth_date):
# API相关配置
interface_name = "XXXXXXXX" #接口编号
access_id = "XXXXXXXXXXX"
key = "XXXXXXXXXXXXXXXXXXXXX"
url = f"https://api.haiyudata.com/api/v1/{interface_name}"
# 构建请求参数
params = {
"mobile_no": mobile_no,
"id_card": id_card,
"auth_date": auth_date,
"name": name,
}
# 将参数转换为JSON字符串并加密
json_str = json.dumps(params)
print(f"请求参数: {json_str}")
encrypted_data = aes_encrypt(json_str, key)
print(f"加密后的数据: {encrypted_data}")
# 发送请求
headers = {
"Access-Id": access_id,
"Content-Type": "application/json"
}
payload = {
"data": encrypted_data
}
print(f"发送请求到: {url}")
try:
response = requests.post(url, json=payload, headers=headers)
response_data = response.json()
print(f"API响应: {response_data}")
# 处理响应
code = response_data.get("code")
message = response_data.get("message")
encrypted_response_data = response_data.get("data")
result = {
"code": code,
"success": code == 0,
"message": message,
"encrypted_response": encrypted_response_data
}
# 如果有返回data尝试解密
if encrypted_response_data:
try:
decrypted_data = aes_decrypt(encrypted_response_data, key)
result["decrypted_response"] = json.loads(decrypted_data)
except Exception as e:
print(f"解密响应数据失败: {e}")
result["decrypted_response"] = None
return result
except Exception as e:
print(f"请求失败: {e}")
return {"success": False, "message": f"请求失败: {e}"}
def main():
print("===== 个人涉诉详版 =====")
# 直接设置手机号和姓名
name = "XXXXXXXX"
id_card = "XXXXXXXXXXXXX"
mobile_no = "XXXXXXXXXXXXXXXXXXXX"
auth_date = "20250318-20270318"
result = CallApi(name,id_card,mobile_no,auth_date)
print("\n===== 结果 =====")
if result["success"]:
print("请求成功!")
if result.get("decrypted_response"):
print(f"解密后的响应: {json.dumps(result['decrypted_response'], ensure_ascii=False, indent=2)}")
else:
print("未能获取或解密响应数据")
else:
print(f"请求失败: {result.get('message', '未知错误')}")
if __name__ == "__main__":
main()