207 lines
5.3 KiB
Markdown
207 lines
5.3 KiB
Markdown
# Tencent Hunyuan 3D API Reverse Engineering Document
|
|
|
|
## Project Overview
|
|
|
|
This project reverse-engineers the frontend signing algorithm of Tencent Hunyuan 3D (https://3d.hunyuan.tencent.com/), enabling **pure Python HTTP calls** without a browser environment for features like image-to-3D generation and quota queries.
|
|
|
|
---
|
|
|
|
## Core Achievements
|
|
|
|
### 1. Signing Algorithm Cracked
|
|
|
|
**Algorithm Location**: webpack Chunk 3057, Module 47436
|
|
|
|
**Signing Flow**:
|
|
```
|
|
1. nonce generation: 16 iterations of Math.random(), selecting from 62-char set (A-Za-z0-9)
|
|
2. timestamp: Math.floor(Date.now() / 1000) (second-level timestamp)
|
|
3. key derivation: hardcoded byte array → XOR → circular left shift → permutation → truncation
|
|
4. signature: HMAC-SHA256(sorted query param string, derived key) → Hex
|
|
```
|
|
|
|
**Key Constants**:
|
|
```python
|
|
C = bytes([122, 59, 92, 165, 30, 79, 166, 139, 142, 129, 139, 89, 219, 131, 101, 204])
|
|
D = bytes([122, 59, 92, 45, 30, 79, 106, 139, 156, 13, 46, 63, 74, 91, 108, 125])
|
|
U = [3, 5, 2, 7, 1, 4, 6, 2, 5, 3, 1, 4, 2, 6, 3, 5] # left shift bits
|
|
M = [14, 11, 13, 9, 15, 10, 12, 8, 6, 3, 5, 1, 7, 2, 4, 0] # permutation table
|
|
```
|
|
|
|
**Derived Key**: `Hf6d6KFB3D` (10 characters)
|
|
|
|
### 2. Signing Scope (Important Finding)
|
|
|
|
⚠️ **The signature only covers URL query parameters, NOT the request body**
|
|
|
|
Actual browser request:
|
|
```
|
|
POST /api/3d/creations/generations?timestamp=xxx&nonce=yyy&sign=zzz
|
|
Body: {"sceneType":"playGround3D-2.0",...}
|
|
```
|
|
|
|
Signature computation:
|
|
```python
|
|
# Only sign query params (timestamp + nonce)
|
|
param_str = "nonce=yyy×tamp=xxx"
|
|
sign = HMAC-SHA256(param_str, key="Hf6d6KFB3D")
|
|
```
|
|
|
|
### 3. Image URL Format
|
|
|
|
Must use Tencent's internal resource format:
|
|
```
|
|
https://3d.hunyuan.tencent.com/api/3d/resource/download?resourceId=<32-digit-hex>
|
|
```
|
|
|
|
You cannot directly use a COS URL; you must upload through the browser to obtain a resourceId.
|
|
|
|
---
|
|
|
|
## File Reference
|
|
|
|
| File | Description |
|
|
|------|-------------|
|
|
| `hunyuan3dweb/sign.py` | Signing algorithm in pure Python |
|
|
| `hunyuan3dweb/api.py` | Pure Python API client |
|
|
| `hunyuan3dweb/browser/login.py` | Browser automation login tool |
|
|
| `doc/api.md` | API endpoint documentation |
|
|
|
|
---
|
|
|
|
## Usage Flow
|
|
|
|
### 1. Login to Obtain Cookie
|
|
|
|
```bash
|
|
hunyuan3dweb-login
|
|
# Follow prompts to enter email and verification code
|
|
# Login state is automatically saved to ~/.config/hunyuan3dweb/profile
|
|
```
|
|
|
|
### 2. Pure Python 3D Generation
|
|
|
|
```python
|
|
from hunyuan3dweb import Hunyuan3DAPI
|
|
|
|
api = Hunyuan3DAPI()
|
|
|
|
# Check quota
|
|
quota = api.get_quota_info()
|
|
|
|
# Generate 3D model
|
|
result = api.generate_3d(
|
|
image_url="https://3d.hunyuan.tencent.com/api/3d/resource/download?resourceId=...",
|
|
scene_type="playGround3D-2.0",
|
|
model_type="image2ModelV3.1"
|
|
)
|
|
|
|
# Query status
|
|
status = api.get_generation_status(result["creationsId"])
|
|
```
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
| Feature | Method | Endpoint | Signature Scope |
|
|
|---------|--------|----------|-----------------|
|
|
| User info | GET | `/getuserinfo` | Query params |
|
|
| Quota query | POST | `/quotainfo` | Query params |
|
|
| Generate 3D | POST | `/creations/generations` | Query params |
|
|
| Query status | GET | `/creations/detail` | Query params |
|
|
|
|
---
|
|
|
|
## Technical Details
|
|
|
|
### Signing Algorithm Implementation
|
|
|
|
```python
|
|
def derive_key(c: bytes) -> str:
|
|
"""Derive signing key from hardcoded constants"""
|
|
# 1. XOR with D
|
|
t = bytearray(16)
|
|
for i in range(16):
|
|
t[i] = c[i] ^ D[i]
|
|
|
|
# 2. Circular left shift
|
|
o = bytearray(16)
|
|
for i in range(16):
|
|
n = U[i]
|
|
val = t[i]
|
|
o[i] = (val << n | val >> (8 - n)) & 0xFF
|
|
|
|
# 3. Permutation
|
|
n = bytearray(16)
|
|
for i in range(16):
|
|
n[i] = o[M[i]]
|
|
|
|
# 4. Truncate (find first zero byte)
|
|
try:
|
|
r = n.index(0)
|
|
except ValueError:
|
|
r = 16
|
|
|
|
return n[:r].decode('utf-8')
|
|
```
|
|
|
|
### Request Signing
|
|
|
|
```python
|
|
def sign(params: dict) -> dict:
|
|
result = dict(params)
|
|
result["timestamp"] = int(time.time())
|
|
result["nonce"] = generate_nonce(16)
|
|
|
|
# Sort and join (JSON format for lists/dicts)
|
|
sorted_items = sort_params(result)
|
|
param_str = join_params(sorted_items)
|
|
|
|
# HMAC-SHA256
|
|
key = derive_key(C)
|
|
signature = hmac.new(
|
|
key.encode('utf-8'),
|
|
param_str.encode('utf-8'),
|
|
hashlib.sha256
|
|
).hexdigest()
|
|
|
|
result["sign"] = signature
|
|
return result
|
|
```
|
|
|
|
---
|
|
|
|
## Verification Results
|
|
|
|
| Test Item | Browser Signature | Python Signature | Match |
|
|
|-----------|-------------------|------------------|-------|
|
|
| Fixed params | `2214e55a...` | `2214e55a...` | ✅ |
|
|
| Quota query | Works | Works | ✅ |
|
|
| Generate request | Works | Works | ✅ |
|
|
| Status query | Works | Works | ✅ |
|
|
|
|
---
|
|
|
|
## Limitations and Notes
|
|
|
|
1. **Image Upload**: Still requires a browser environment to upload images and obtain resourceId (Tencent COS requires temporary signatures)
|
|
2. **Cookie Expiration**: Login sessions expire and need periodic re-login
|
|
3. **Quota Limit**: Each account has a generation quota limit (default 20/day)
|
|
4. **Rate Limiting**: Frequent calls may trigger anti-bot measures
|
|
|
|
---
|
|
|
|
## Dependencies
|
|
|
|
```
|
|
requests
|
|
cloakbrowser (for login and upload)
|
|
```
|
|
|
|
---
|
|
|
|
## Legal Notice
|
|
|
|
This project is for educational and research purposes only. Use of this code is subject to Tencent Hunyuan 3D's Terms of Service. Do not use for commercial purposes or large-scale automated calling.
|