本文说明 KENI 如何加密你的数据、密钥存在哪、服务端看得到什么、看不到什么, 以及我们刻意做的取舍。写给真正会读白皮书的人 —— 简洁、不带营销。
1. 威胁模型
我们假设网络是敌对的、我们的基础设施已被攻破。目标是:即便攻击者对我们的 数据库有完全读权限,再加上客户端与服务端之间的流量抓包,也读不到你的 1:1 私聊文字。(群消息和你在 1:1 里发送的媒体按设计是服务端可读的 —— 见 §5。)
我们不防御你自己设备上的恶意软件、被攻陷的对端(你朋友的手机), 或针对我们合规归档的合法传票(见 §5)。如果你的威胁模型要求对抗有传票权力的 国家级行为体,Signal 才是正确答案 —— KENI 做了不同的选择,并会诚实说明。
2. 密钥生成
首次安装时,客户端在设备本地生成两对密钥:
- 身份密钥:X25519,用于长期对端身份标识。 公钥上传到服务器;私钥仅存设备本地 —— iOS 放在 Keychain(kSecAttrAccessibleAfterFirstUnlock,已关闭 iCloud 同步), Android 放在 EncryptedSharedPreferences(已排除 allowBackup)。它绝不同步到 iCloud 或 Google 云备份。
- 预密钥(Prekey):X25519,会轮换。用于异步 会话建立,使离线的对端也能收到你的第一条消息。
私钥绝不传到我们服务器。可选的 passphrase 备份(§4)是私钥离开设备的唯一途径, 且那份副本用一个由 passphrase 派生、我们永远看不到的密钥加密。
3. 按房间会话
两位用户开始 1 对 1 聊天时:
- 客户端 A 从服务器取 B 的身份公钥。
- 两端本地各自跑 X25519 ECDH,派生一个 32 字节共享密钥。
- 共享密钥用于播种初始的棘轮 root key。每条消息用一个全新的 12 字节 nonce 以 AES-256-GCM 封装;传输密文 + nonce + 棘轮头。
- 群聊默认走服务端加密 + 一份合规副本(见 §5)。一个使用 Sender Keys 协议的端到端群聊模式(每位发送者一把轮换密钥,经各成员的成对会话分发) 对每个群都已开放;新建的群从服务端可读开始,由群主自行开启该模式。
1:1 会话跑的是简化版 Signal Double Ratchet。每次 DH 棘轮步骤都会生成一把新的临时 X25519 密钥,每条消息在密文旁携带一个棘轮头。由此获得前向保密 —— 棘轮步骤之前的消息密钥无法再被推导出来 —— 以及break-in recovery:一旦收到对端新的棘轮公钥,之后的消息密钥便与此前泄露的任何密钥无关。
边界也直说。这是简化版棘轮,不是逐行照搬的 Signal 实现。另外,棘轮上线之前发出的消息 不带棘轮头,仍走原来的静态 X25519-ECDH 路径解密 —— 对那段历史,前向保密不会追溯生效。
同一账号的多台设备按设备处理,而不是按账号。每台设备 各自发布自己的密钥,也各自收到一份属于自己的消息副本。分发查询只返回已批准的设备 —— 未获批准的设备拿不到任何它能解开的东西,这道闸是 fail-closed 而非 fail-open。你的第一台 设备自我批准;之后每一台都从 pending 开始,必须由你已批准过的某台设备来批。你与联系人 比对的安全码覆盖对方整个已批准设备集,所以对方账号上 多出一台设备,会表现为安全码变化,而不是悄无声息地加进去。
4. 身份备份(零知识)
丢手机不该丢掉聊天历史。用户可选启用一个由 passphrase 守护的密钥托管:
- 用户输入一个 passphrase(≥ 8 字符),仅在设备本地录入。
- 客户端生成一个随机 16 字节 salt。
- 客户端跑 PBKDF2-SHA256,60 万次迭代,salt + passphrase → 256 位 KEK。在这个次数调高之前写下的备份会记录自己的迭代数,读取时按各自的值还原。
- 客户端用 KEK + 全新 nonce,以 AES-256-GCM 把 { identity_priv, identity_pub, prekey_priv, prekey_pub } 作为 JSON 加密。
- 客户端把 { version, salt, ciphertext } 上传到服务器。
服务器只存不透明密文。没有 passphrase 我们派生不出 KEK;没有 KEK 我们解不开。 passphrase 丢了 = 备份永久丢失。我们不会替你"重置"身份,因为我们做不到。
5. 合规归档(请知悉)
1:1 消息文字仅端到端加密 —— 没有合规副本,没有任何我们能解开的东西,连我们也不行。 群消息会保留一份用 KENI 平台公钥加密的合规副本(群聊按设计服务端可读;端到端群聊模式已开放, 由各群群主自行开启)。这份群合规副本存在有两个原因:
- 合法披露令。没有它,即便法律要求我们也无法响应传票。有些 app 选择从设计上 就不配合 —— 那是一个站得住的立场;我们做了不同的选择。
- CSAM 检测。图片在投递前会用 Microsoft PhotoDNA 与已知 CSAM 库做哈希比对(见 安全页)。这需要服务端短暂看到图像字节。
平台私钥存于 HSM 级密钥库。访问需多方授权并记录理由。我们不会把归档拿去做产品分析、 广告或训练数据。如果这个取舍不符合你的威胁模型,请用 Signal —— 我们不会介意。
6. AI 功能(哪些数据离开你的设备)
AI 功能(KENI 助手、意图路由、摘要)不是端到端加密的。云端 LLM 必须读到你的提问才能 回答。我们的做法:
- 出境前 PII 自动脱敏:基于正则把手机号、邮箱、信用卡、身份证号、IP 替换为占位符, LLM 回包后再还原。
- 首次进入任一 AI 入口弹一次性同意框。可在「设置 → 隐私」撤回,撤回即禁用全部 AI 功能。
- 可选本地模式:下载小 GGUF 模型(Qwen2.5 或 Llama 3.2,约 280MB 起)在设备本地跑;语音转文字 可切到 Whisper 完全离线。两条路径都不把音频或 prompt 发给任何人。
7. TURN / WebRTC 媒体
语音/视频用 WebRTC。信令经我们的 WS 网关(SDP 本身不是消息内容)。NAT 允许时媒体走 点对点;在对称 NAT 后则经我们自建的 coturn 中继(turn.hikeni.com)。中继看到的 是加密的 SRTP 包 —— 无法解密媒体。每次会话用网关以仅服务端密钥签发的 HMAC-SHA1 短期 TURN 凭证(24h TTL);用户从不接触永久 TURN 密码。
8. 我们刻意不做的事
- 不用任何给用户画像的分析 SDK(没有 Mixpanel、没有 Amplitude)。崩溃上报仅用 Firebase Crashlytics,范围限于堆栈。
- 不用任何第三方广告 SDK。不采集 IDFA / GAID。
- 不上传通讯录。联系人发现在客户端对手机号做哈希(对 E.164 做 SHA-256),只上传 哈希列表;我们从不接触你的原始通讯录。
- 没有后台定位。实时位置是按房间显式 opt-in,且自动过期。
9. 待解问题与路线图
- 已经没有任何一台已批准设备时,如何重新拿回多设备访问。批准必须来自你已批准过的 设备(§3),所以唯一那台一旦丢失或被抹掉,就没有东西可以用来批准了,恢复只能回落到 passphrase 加密的身份备份(§4)。身份密钥刻意不经 iCloud Keychain 自动同步 —— 正是这个选择让备份成为恢复路径,也是我们最该把警告说清楚的那个取舍。
- NCMEC ESP 注册待批;在上线前,CSAM 命中会以 status=pending_retry 入队
ncmec_reports。 - 合规归档第三方审计。我们是小团队,尚未做。在此之前,代码(
backend/handlers/ecdh.go、handlers/moderation.go)是 source of truth。
10. 联系
在我们的密码学里发现 bug?想就上面某个取舍辩论?邮件 safety@hikeni.com。 我们每封都读,5 个工作日内回复。