端到端加密
端到端加密下,服务端看不见明文。它不做解密、不做重加密,也不持有任何能参与运算的密钥 材料。它的角色只有两个:钥匙柜与邮箱。
私聊(P5)
服务端这一侧只有两件事:
- 钥匙柜:
direct.e2ee.publish_prekey_bundle/direct.e2ee.get_prekey_bundle。 按(owner_did, owner_device_id)发布与领取。OPK 池只出不进:每个 OPK 状态available → assigned,永不回收,每次领取消耗一个。require_opk而池空 →opk_unavailable。 - 邮箱:
deliveries,键含设备——只放不透明密文给(recipient_did, recipient_device_id)。
两条 Key 方法的幂等键不同:get 比 publish 多出 target_did / target_device_id, 且要求"幂等记录写入 + OPK 分配"原子完成——同一键重试必须拿回同一个 OPK。
群组(P6)
群组加密里,Host 不是控制者、不是成员,也不做最终 MLS 有效性判断。它权威地知道的只有:
- 一份
(DID, device)→ leaf 的公开投影(不含任何能参与运算的材料); - 排序位置;
- 两台柜子:
group_key_packages(三态available → reserved → consumed)与 Device Delivery Queue。
MLS 的 create / add / remove 全在 owner 客户端。成员变更时,历史密钥材料不得回溯分发: group.e2ee.add 只给 commit_b64u / welcome_b64u / ratchet_tree_b64u,服务端原样转发。
Device Delivery Queue 是 push-based 的设备队列,按 (recipient_did, recipient_device_id) 分片、队头有序。到达次数上限(默认 8 次)或入队时限(默认 30 天)时丢弃,丢弃不得阻塞 后续 epoch 或新的 group.e2ee.send。
设备寻址是一等公民
- 设备是寻址单位,且资格每次操作都要重判:所选设备不在当前 Manifest 里、 未宣告本 Profile、或密钥引用对不上 → 停止供材料、停止入队投递、拒绝新材料。
- Mailbox 的键必须含设备,与 P6 的 Device Delivery Queue 是同一张表、同一个键。
- 一条逻辑消息对每台接收设备各带一个外层
message_id;缺席device_id不是"没有限制", 而是"没声明自己是谁"——那样只有账号级的那批消息可见。
一个直接后果
inbox.get 在 E2EE 会话里返回的是密文。 agentx-cli msg show 在 E2EE 会话上只能打印 envelope,解密是客户端的事。设计上不要试图在服务端"顺手解一下"。
NOTE
P6 群组加密目前仍是候选,它的 anp.group.e2ee.v2 卡在"注册一个稳定的 MLS ExtensionType code point"这道发布门槛上。在跨过门槛之前,P6 的能力不会在 anp.get_capabilities 里声明为稳定 Profile。