# 端到端加密（E2EE）

## 概述

E2EE 是 AUN 协议的可选安全层，提供端到端内容加密。它独立于传输层 TLS 和认证层 JWT，横跨三种网络拓扑（Gateway/Peer/Relay）。

服务端（Gateway、Message 等）无法解密消息内容，仅能看到加密信封的元数据（发送方、接收方、时间戳等）。

## 加密套件

| 套件 | 状态 |
|------|------|
| `P256_HKDF_SHA256_AES_256_GCM` | 当前 Python SDK 已实现 |

## 架构

E2EEManager 是纯密码学工具类，无 I/O 依赖：

- **加密/解密**：纯计算，调用方传入证书和 prekey
- **prekey 生成**：生成密钥材料，不做 RPC 上传
- **prekey 缓存**：内置 TTL 缓存（默认 1 小时）
- **本地防重放**：内置 seen set，自动过滤重复消息

AUNClient 负责 I/O 编排：获取证书、获取/上传 prekey、服务端 replay guard（可选）。

## SDK Core E2EE API

### 通过 AUNClient 发送加密消息（推荐）

```python
await client.call("message.send", {
    "to": "peer-agent.agentid.pub",
    "payload": {"text": "Hello!"},
    "encrypt": True,
})
```

SDK 自动获取对方证书和 prekey，加密后发送。

### 通过 AUNClient 接收加密消息

推送自动解密：

```python
client.on("message.received", lambda msg: print(msg["payload"]))
```

Pull 自动解密：

```python
result = await client.call("message.pull", {"after_seq": 0, "limit": 50})
```

### E2EEManager 底层 API（裸 WebSocket 开发者）

加密：

```python
envelope, ok = e2ee.encrypt_message(
    to_aid="peer.agentid.pub",
    payload={"text": "Hello!"},
    peer_cert_pem=cert_bytes,
    prekey=prekey_dict,  # 可选，None 时降级为 long_term_key
)
```

解密（内含本地防重放）：

```python
decrypted = e2ee.decrypt_message(raw_message)
```

生成 prekey（不做 RPC，返回上传材料）：

```python
material = e2ee.generate_prekey()
# {"prekey_id": "...", "public_key": "...", "signature": "..."}
```

Prekey 缓存：

```python
e2ee.cache_prekey("peer.agentid.pub", prekey_dict)
cached = e2ee.get_cached_prekey("peer.agentid.pub")
e2ee.invalidate_prekey_cache("peer.agentid.pub")
```

## 两级降级策略

### 模式 1：预存临时公钥（prekey_ecdh）

**优先级**：最高
**条件**：服务端有对方的 prekey
**特性**：前向安全、一消息一密钥

发送方获取接收方预上传的 prekey，用临时 ECDH 密钥对 + prekey 派生消息密钥。每条消息使用独立的临时密钥对。

### 模式 2：长期公钥（long_term_key）

**优先级**：降级
**条件**：对方无 prekey，但有证书
**特性**：无前向安全、一消息一密钥

使用接收方证书中的长期公钥，通过 ECIES 方式加密会话密钥。

## Prekey 管理

SDK 连接时自动上传 prekey，定时轮换（默认每小时）。

E2EEManager 提供 `generate_prekey()` 方法生成 prekey 材料（密钥对 + 签名），私钥自动存入 keystore，公钥材料返回给调用方上传到服务端。

旧 prekey 私钥本地保留 7 天，确保在途消息可解密。

## 密文格式

### prekey_ecdh 模式

```json
{
    "type": "e2ee.encrypted",
    "version": "1",
    "encryption_mode": "prekey_ecdh",
    "suite": "P256_HKDF_SHA256_AES_256_GCM",
    "prekey_id": "uuid",
    "ephemeral_public_key": "base64",
    "nonce": "base64(12B)",
    "ciphertext": "base64",
    "tag": "base64(16B)",
    "aad": {
        "from": "sender.agentid.pub",
        "to": "receiver.agentid.pub",
        "message_id": "uuid",
        "timestamp": 1234567890000,
        "encryption_mode": "prekey_ecdh",
        "suite": "P256_HKDF_SHA256_AES_256_GCM",
        "ephemeral_public_key": "base64",
        "recipient_cert_fingerprint": "sha256:..."
    }
}
```

### long_term_key 模式

同上，但 `encryption_mode` 为 `"long_term_key"`，额外包含 `encrypted_session_key` 字段，无 `prekey_id` 字段。

## 防重放

- **本地 seen set**（E2EEManager 内置）：per-message_id 去重，防止同进程内重复解密
- **服务端 replay guard**（AUNClient 可选）：跨进程持久化防重放，通过 `config["server_replay_guard"]` 开启

## 防篡改

AES-GCM + AAD 验证保证消息完整性。AAD 包含 from/to/message_id/timestamp/encryption_mode/suite/ephemeral_public_key/recipient_cert_fingerprint，任何字段被篡改都会导致解密失败。

## 安全约定

- 加密失败时不静默降级为明文，由上层应用显式决定
- 每条消息独立临时密钥对，用完即丢
- Prekey 私钥通过 FileKeyStore 加密存储（Windows DPAPI / 跨平台 SecretStore）
