# API Key 解密说明 调用 `/api/public/prices` 接口时,返回数据中每个模型的 `api_key` 字段是加密后的密文。本文档说明如何在你的应用中解密还原出原始 API Key。 --- ## 所需信息 | 项目 | 值 | |------|-----| | 加密密钥 | `25e9e87b18cf40d0ed0f102b8d2ec3a8` | | 算法 | XOR 密钥流 + 字节循环位移 + Base64 URL-safe | | 依赖 | 无第三方库,纯标准库实现 | > ⚠️ 请妥善保管加密密钥,不要泄露给未授权方。 --- ## 算法说明 ### 加密流程(服务端) ``` 明文 UTF-8 字节 → 与密钥流逐字节 XOR → 每字节循环左移 (i % 5 + 1) 位 → Base64 URL-safe 编码(无 = 填充) → 密文字符串 ``` ### 解密流程(客户端,完全对称) ``` 密文字符串 → Base64 URL-safe 解码 → 每字节循环右移 (i % 5 + 1) 位 → 与相同密钥流逐字节 XOR → UTF-8 解码 → 原始 API Key ``` ### 密钥流派生方式 对 `SECRET_KEY + 块索引(4字节大端)` 反复做 SHA-256,拼接直到长度够用: ``` block_0 = SHA-256(key_bytes + 0x00000000) # 32 字节 block_1 = SHA-256(key_bytes + 0x00000001) # 32 字节 block_2 = SHA-256(key_bytes + 0x00000002) # 32 字节 ... keystream = block_0 + block_1 + block_2 + ... 取前 N 字节 ``` --- ## 各语言解密实现 ### JavaScript / TypeScript 适用于浏览器和 Node.js(18+),使用内置 `crypto.subtle`。 ```javascript async function deriveKeystream(key, length) { const enc = new TextEncoder(); const keyBytes = enc.encode(key); const stream = []; let block = 0; while (stream.length < length) { const blockBytes = new Uint8Array(4); new DataView(blockBytes.buffer).setUint32(0, block, false); // big-endian const input = new Uint8Array([...keyBytes, ...blockBytes]); const hash = await crypto.subtle.digest('SHA-256', input); stream.push(...new Uint8Array(hash)); block++; } return stream.slice(0, length); } function rotr8(byte, n) { n = n % 8; return ((byte >>> n) | (byte << (8 - n))) & 0xFF; } function base64urlDecode(str) { str = str.replace(/-/g, '+').replace(/_/g, '/'); while (str.length % 4) str += '='; return Uint8Array.from(atob(str), c => c.charCodeAt(0)); } async function decryptApiKey(ciphertext, secretKey) { const data = base64urlDecode(ciphertext); const keystream = await deriveKeystream(secretKey, data.length); const result = new Uint8Array(data.length); for (let i = 0; i < data.length; i++) { const unshifted = rotr8(data[i], i % 5 + 1); result[i] = unshifted ^ keystream[i]; } return new TextDecoder().decode(result); } // 使用示例 const SECRET_KEY = '25e9e87b18cf40d0ed0f102b8d2ec3a8'; const apiKey = await decryptApiKey(model.api_key, SECRET_KEY); console.log(apiKey); // sk-xxxxxxxxxxxxxxxx ``` --- ### Python 使用标准库 `hashlib` + `base64`,无需安装任何包。 ```python import base64 import hashlib def decrypt_api_key(ciphertext: str, secret_key: str) -> str: # 1. Base64 URL-safe 解码 rem = len(ciphertext) % 4 if rem: ciphertext += '=' * (4 - rem) data = base64.urlsafe_b64decode(ciphertext) # 2. 派生密钥流 stream, block = bytearray(), 0 key_bytes = secret_key.encode('utf-8') while len(stream) < len(data): stream.extend( hashlib.sha256(key_bytes + block.to_bytes(4, 'big')).digest() ) block += 1 keystream = bytes(stream[:len(data)]) # 3. 循环右移 + XOR result = bytearray(len(data)) for i, byte in enumerate(data): n = i % 5 + 1 unshifted = ((byte >> n) | (byte << (8 - n))) & 0xFF result[i] = unshifted ^ keystream[i] return result.decode('utf-8') # 使用示例 SECRET_KEY = '25e9e87b18cf40d0ed0f102b8d2ec3a8' api_key = decrypt_api_key(model['api_key'], SECRET_KEY) print(api_key) # sk-xxxxxxxxxxxxxxxx ``` --- ### Java 使用 JDK 内置 `MessageDigest` + `Base64`,无需第三方依赖。 ```java import java.util.Base64; import java.security.MessageDigest; import java.nio.charset.StandardCharsets; public class ApiKeyDecryptor { private static final String SECRET_KEY = "25e9e87b18cf40d0ed0f102b8d2ec3a8"; private static byte[] deriveKeystream(String key, int length) throws Exception { MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8); byte[] stream = new byte[length]; int pos = 0, block = 0; while (pos < length) { sha256.reset(); sha256.update(keyBytes); sha256.update(new byte[]{ (byte)(block >> 24), (byte)(block >> 16), (byte)(block >> 8), (byte) block }); byte[] hash = sha256.digest(); int toCopy = Math.min(hash.length, length - pos); System.arraycopy(hash, 0, stream, pos, toCopy); pos += toCopy; block++; } return stream; } private static int rotr8(int b, int n) { n = n % 8; return ((b >>> n) | (b << (8 - n))) & 0xFF; } public static String decrypt(String ciphertext) throws Exception { // 1. Base64 URL-safe 解码 String padded = ciphertext.replace('-', '+').replace('_', '/'); while (padded.length() % 4 != 0) padded += "="; byte[] data = Base64.getDecoder().decode(padded); // 2. 派生密钥流 byte[] keystream = deriveKeystream(SECRET_KEY, data.length); // 3. 循环右移 + XOR byte[] result = new byte[data.length]; for (int i = 0; i < data.length; i++) { int unshifted = rotr8(data[i] & 0xFF, i % 5 + 1); result[i] = (byte)(unshifted ^ keystream[i]); } return new String(result, StandardCharsets.UTF_8); } // 使用示例 public static void main(String[] args) throws Exception { String encrypted = "..."; // 从 API 返回的 api_key 字段 String apiKey = decrypt(encrypted); System.out.println(apiKey); // sk-xxxxxxxxxxxxxxxx } } ``` --- ### Go ```go package main import ( "crypto/sha256" "encoding/base64" "fmt" ) const secretKey = "25e9e87b18cf40d0ed0f102b8d2ec3a8" func deriveKeystream(key string, length int) []byte { keyBytes := []byte(key) stream := make([]byte, 0, length+32) for block := 0; len(stream) < length; block++ { blockBytes := []byte{ byte(block >> 24), byte(block >> 16), byte(block >> 8), byte(block), } h := sha256.Sum256(append(keyBytes, blockBytes...)) stream = append(stream, h[:]...) } return stream[:length] } func rotr8(b byte, n int) byte { n = n % 8 return (b >> n) | (b << (8 - n)) } func decryptApiKey(ciphertext string) (string, error) { // Base64 URL-safe 解码 rem := len(ciphertext) % 4 if rem != 0 { for i := 0; i < 4-rem; i++ { ciphertext += "=" } } data, err := base64.URLEncoding.DecodeString(ciphertext) if err != nil { return "", err } keystream := deriveKeystream(secretKey, len(data)) result := make([]byte, len(data)) for i, b := range data { unshifted := rotr8(b, i%5+1) result[i] = unshifted ^ keystream[i] } return string(result), nil } func main() { encrypted := "..." // 从 API 返回的 api_key 字段 apiKey, err := decryptApiKey(encrypted) if err != nil { panic(err) } fmt.Println(apiKey) // sk-xxxxxxxxxxxxxxxx } ``` --- ## 完整使用示例 请求 `/api/public/prices` 后,遍历 `models` 数组,对每个有 `api_key` 的模型解密: ```javascript const SECRET_KEY = '25e9e87b18cf40d0ed0f102b8d2ec3a8'; const res = await fetch('https://your-api.com/api/public/prices', { headers: { 'Referer': 'https://your-domain.com' } }); const data = await res.json(); for (const model of data.models) { if (model.api_key) { model.api_key_plain = await decryptApiKey(model.api_key, SECRET_KEY); } } ``` --- ## 注意事项 - `api_key` 字段为 `null` 时表示该模型未配置 API Key,无需解密 - 密钥更换后,旧密文将无法解密,需重新请求接口获取新密文 - 建议将 `SECRET_KEY` 存储在环境变量中,不要硬编码在源码里