调用 /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 字节
适用于浏览器和 Node.js(18+),使用内置 crypto.subtle。
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
使用标准库 hashlib + base64,无需安装任何包。
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
使用 JDK 内置 MessageDigest + Base64,无需第三方依赖。
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
}
}
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 的模型解密:
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 存储在环境变量中,不要硬编码在源码里