# ANVIL 在线加密 API

Base URL：`https://anvil.xueyuanpie.com/`

统一入口 `/api.php`，用 `?act=` 区分接口。除 `sys.*` 与 `auth.verify` 外，所有接口都需要令牌。

- 编码：请求/响应均为 UTF-8。
- 响应：HTTP 200，正文统一 `{"code":"1"|"-1","info":"...","data":{...}}`。
- 算法：ANVIL-1（纯自建，不使用 AES / RSA / SHA / Base64 / HMAC 等任何公开算法）。
- 引擎：服务端以 PHP 字节码产物执行；若开启 FFI 则自动切换到 `libanvil.so`，两者输出逐字节一致。

## 鉴权

1. **取令牌**：`POST /api.php?act=auth.verify`，表单 `app_id` + `app_secret`，返回 `data.token`。
2. **带令牌**：后续请求任选其一
   - 请求头 `X-Auth-Token: <token>`
   - 表单/查询参数 `auth_token=<token>`
3. 令牌默认 **24 小时**有效；过期后重新验证。

> `app_id` / `app_secret` 由站点管理员用 `php tools/addapp.php 应用名` 生成，写入 `config.local.php`。

## 接口总览

| 接口 | 方法 | 鉴权 | 说明 |
|---|---|---|---|
| `sys.health` | GET | 无 | 健康检查：引擎版本、运行模式、时间 |
| `sys.info` | GET | 无 | 接口清单与限额 |
| `auth.verify` | POST | 无 | app 凭证换令牌 |
| `auth.info` | GET/POST | 令牌 | 查配额与到期 |
| `crypto.keygen` | POST | 令牌 | 生成 32 字节密钥 |
| `crypto.encrypt` | POST | 令牌 | 明文 → 令牌 |
| `crypto.decrypt` | POST | 令牌 | 令牌 → 明文 |
| `crypto.derive` | POST | 令牌 | 口令 → 密钥 |
| `crypto.sign` | POST | 令牌 | 小数据 MAC（≤64KB） |
| `pack.run` | POST | 令牌 | **源码混淆 + 打包**（上传 .php/.zip，返回 zip 令牌） |
| `pack.download` | GET | 令牌 | 取回受保护 zip |

---

## sys.health

```bash
curl "https://anvil.xueyuanpie.com/api.php?act=sys.health"
```

```json
{"code":"1","info":"ok","data":{"status":"up","engine":"ANVIL-1/bytecode","mode":"bytecode","time":"2026-10-20T20:27:53+08:00","uptime":9}}
```

## sys.info

返回接口清单与限额（字段含义见“限额”一节）。

## auth.verify

| 参数 | 必填 | 说明 |
|---|---|---|
| app_id | 是 | 应用 ID |
| app_secret | 是 | 应用密钥（64 位十六进制） |

```bash
curl -X POST "https://anvil.xueyuanpie.com/api.php?act=auth.verify" \
  -d "app_id=anvil_xxxxxxxxxxxx" \
  -d "app_secret=64位十六进制"
```

```json
{"code":"1","info":"验证成功","data":{"token":"<64位十六进制>","expires_in":86400,"app":{"app_id":"anvil_xxxxxxxxxxxx","name":"demo"}}}
```

## auth.info

```bash
curl -X POST "https://anvil.xueyuanpie.com/api.php?act=auth.info" \
  -H "X-Auth-Token: $TOKEN"
```

`data.quota` 返回 `{day, used, limit, left}`（按明文/密文字节累计）。

## crypto.keygen

```json
{"code":"1","info":"ok","data":{"key":"8d11...2acb","format":"hex(64)"}}
```

密钥只返回一次，服务端不保存。丢失无法找回。

## crypto.encrypt

| 参数 | 必填 | 说明 |
|---|---|---|
| key | 是 | 64 位十六进制（32 字节） |
| data | 二选一 | 文本明文（表单字段） |
| file | 二选一 | 文件上传（二进制安全，≤8MB） |
| nonce | 否 | 32 位十六进制；不传则服务端随机生成 |

输出 `data.token`：两字符一字节的 `[A-Za-z0-9]` 令牌，可直接入库、放 URL、进 JSON。

```bash
curl -X POST "https://anvil.xueyuanpie.com/api.php?act=crypto.encrypt" \
  -H "X-Auth-Token: $TOKEN" \
  -d "key=$KEY" \
  -d "data=订单 #2026：金额 1280 元"
```

```json
{"code":"1","info":"加密成功","data":{"token":"YhGhScKe...","bytes_in":30,"bytes_out":132,"quota":{"day":"20261020","used":30,"limit":67108864,"left":67108834}}}
```

令牌结构：`魔数(4) ‖ nonce(16) ‖ 封条(16) ‖ 密文`，再整体编码成两字符一字节。

## crypto.decrypt

| 参数 | 必填 | 说明 |
|---|---|---|
| key | 是 | 64 位十六进制 |
| token | 二选一 | 文本令牌 |
| file | 二选一 | 令牌文件 / 二进制信封 |

明文为合法 UTF-8 时返回 `data.data`；二进制时 `data.utf8=false`，明文放在 `data.data_hex`。

认证失败（密钥错 / 被篡改）返回：

```json
{"code":"-1","info":"认证失败：密钥错误或数据被篡改","data":{"errcode":"E_TAG"}}
```

**先验封条再解密**：失败时服务端不产生任何明文，也不区分“密钥错”与“数据坏”。

## crypto.derive

| 参数 | 必填 | 说明 |
|---|---|---|
| password | 是 | 口令 |
| salt | 是 | 盐（建议 ≥16 字节，每个用途唯一） |
| iter | 否 | 迭代数，默认 1200，范围 1..200000 |

返回 `data.key`（64 位十六进制）。同一组 `(password, salt, iter)` 结果恒定，可直接当密钥用。

## crypto.sign

对 ≤64KB 数据出 MAC（取 ANVIL 信封中的封条，16 字节）。

| 参数 | 必填 | 说明 |
|---|---|---|
| key | 是 | 64 位十六进制（签名密钥） |
| nonce | 是 | 32 位十六进制（一次性，防重放由调用方维护） |
| data | 是 | 待签名数据（≤64KB） |

```json
{"code":"1","info":"ok","data":{"sign":"abaac1...d197","format":"hex(32)"}}
```

调用方复算方式：用同一 `key`/`nonce` 调 `crypto.encrypt`，取令牌解码后第 20..35 字节。

---

## 错误码

`code=-1` 时 `data.errcode` 给出机器可读原因：

| errcode | 含义 |
|---|---|
| E_PARAM | 参数缺失或格式错 |
| E_KEY | `key` 不是 64 位十六进制 |
| E_TOKEN | 令牌缺失 / 非法 / 过期 |
| E_AUTH | 应用凭证无效或已停用 |
| E_RATE | 触发限流 |
| E_QUOTA | 当日额度用尽 |
| E_SIZE | 请求体/文件超限 |
| E_TAG | 认证失败（密钥错或数据被篡改） |
| E_UPLOAD | 上传失败 |
| E_ACT | 未知接口 |
| E_ENGINE | 服务内部错误 |

## 限额

| 项 | 默认值 |
|---|---|
| 单次请求体 | 8 MB |
| 每 app 每日字节额度 | 64 MB（可按 app 覆盖） |
| 每 IP 每分钟请求 | 120 |
| 每令牌每分钟请求 | 240 |
| 令牌有效期 | 24 小时 |
| 签名数据上限 | 64 KB |

## 调用示例（PHP）

```php
$base = 'https://anvil.xueyuanpie.com/api.php';

function api(string $url, array $post, string $token = ''): array {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $post,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => $token ? ["X-Auth-Token: $token"] : [],
        CURLOPT_TIMEOUT => 30,
    ]);
    $r = curl_exec($ch);
    curl_close($ch);
    return json_decode((string)$r, true) ?: [];
}

// 1) 取令牌
$v = api($base . '?act=auth.verify', ['app_id' => APP_ID, 'app_secret' => APP_SECRET]);
$token = $v['data']['token'] ?? '';

// 2) 加密
$e = api($base . '?act=crypto.encrypt', ['key' => $keyHex, 'data' => $plain], $token);
$cipher = $e['data']['token'] ?? '';

// 3) 解密
$d = api($base . '?act=crypto.decrypt', ['key' => $keyHex, 'token' => $cipher], $token);
$plain2 = $d['data']['data'] ?? null;
```

## 安全说明

- 全站强制 HTTPS；接口只返回 JSON，无 CORS 头（服务端调用）。
- 服务端**不保存**明文与密钥；审计日志只记 `act / app / 字节数 / IP / 时间`。
- `data/`、`src/`、`engine/`、`tools/`、`config*.php` 在 nginx 层返回 404。
- 令牌比较、密钥比较均为定时安全实现；限流以 `REMOTE_ADDR` 为准，不信任 `X-Forwarded-For`。
- 自建算法未经第三方密码学审计，适用于业务数据保护；不建议用于国家秘密或支付核心链路。

---

## pack.run（源码混淆 + 打包）

云端执行（AST / nikic-php-parser）：跨文件符号分析 → 类/函数/私有方法/私有属性改名（PUA 三套变种）→ 字符串与常量变种 → 每函数体扁平化 → 死代码 →
deflate + 一次性掩码（密钥由 libanvil.so 现场随机生成）。

| 参数 | 必填 | 说明 |
|---|---|---|
| file | 是 | multipart 上传，`.php` 或 `.zip` |
| name | 否 | 原始文件名（仅用于注释） |

```bash
curl -X POST "https://anvil.xueyuanpie.com/api.php?act=pack.run" \
  -H "X-Auth-Token: $TOKEN" -F "file=@app.zip"
```

```json
{"code":"1","info":"加密完成","data":{"down":"f80a6102f01c","files":2,"obf":2,"failed":[],
 "bytes_in":216,"bytes_out":1002,"notes":["已应用：注释清除 / 字符串编码 / 逐函数 PUA 改名 / 控制流扁平化 / 死代码"]}}
```

## pack.download

```bash
curl -H "X-Auth-Token: $TOKEN" \
  "https://anvil.xueyuanpie.com/api.php?act=pack.download&down=f80a6102f01c" -o out.zip
```

产物为自包含受保护 PHP：`<?php eval('?>'.(gzuncompress('<enc>'^'<pad>')));`
—— 无可读解密代码、无 loader；目标机只需 zlib（PHP 默认自带）。
结果保留 2 小时。
