加密算法:AES-256-GCM 与 TLS 1.3 的实际参数
快喵VPN 隧道层采用 AES-256-GCM,密钥 256 位、认证标签 128 位、随机数 96 位且每次会话重新生成。在 2026 年 8 月的自有环境测试中,加密开销使吞吐中位下降 5.8%,握手额外耗时 62 毫秒。
选型原则:为什么不是自研算法
密码学的第一原则是不要自己发明。快喵使用的每一种算法都有公开规范编号与长期分析记录。
快喵隧道层只使用两类已被广泛分析的算法:AES-256-GCM 用于对称加密与完整性校验,X25519 用于临时密钥交换,密钥派生使用 HKDF-SHA256。三者分别对应 NIST SP 800-38D、RFC 7748 与 RFC 5869,均为公开标准,没有私有改造。
三条选型原则
- 标准优先 凡是能对应到 RFC 或 NIST 文档的算法优先采用,避免把安全性押在未经验证的设计上。
- 认证加密 只选择同时提供机密性与完整性的模式,拒绝需要另行拼装 MAC 的组合方式。
- 硬件友好 优先选择 CPU 具备指令集加速的算法,AES-NI 可把单核吞吐提升到 1.2 GB/s 以上。
- 可替换 算法标识随配置下发,出现需要迁移的情况时可在版本内切换而不改变架构。
这三个标准的共同点是可以被第三方复核:算法本身、参数范围与失败模式都有公开文档,审计方不需要依赖任何内部说明就能判断实现是否符合预期。相比之下,私有算法的安全性完全取决于实现者是否诚实,这一点无法通过外部检查证实。
被排除的两个选项
第一是自研流密码,常见于早期商业 VPN,问题在于没有第三方分析,任何一次实现错误都无从发现;第二是仅用 AES-CTR 加独立 HMAC,这种组合容易被实现成先加密后校验导致的可预测行为,而 GCM 把校验内建在认证标签里,回避了顺序错误。
- 自研算法 缺少公开分析与实现参考,一旦出错无法通过外部复核发现,故不采用。
- 拼接式加密 加密与校验分离的实现容易在顺序上出错,GCM 将二者合并在单一原语内。
- 过长密钥 AES-512 之类并非标准选项,密钥长度超过 256 位并不带来实际安全收益。
AES-256-GCM 的参数细节
同样写着 AES-256-GCM 的两个实现,可能在随机数管理上完全不同——这才是决定安全性的地方。
GCM 的安全性依赖“同一密钥下随机数不重复”这一前提。快喵的做法是:每个会话使用独立密钥,随机数由计数器与随机前缀拼接生成,前缀每次会话重新抽取,计数器在会话内单调递增,二者组合重叠概率在 96 位空间内可忽略。
| 参数 | 取值 | 作用 | 出错后果 |
|---|---|---|---|
| 密钥长度 | 256 位 | 对称加密强度 | 长度不足会削弱抗穷举能力 |
| 认证标签 | 128 位 | 完整性校验 | 标签过短会提高伪造成功率 |
| 随机数 | 96 位,前缀 32 位随机 + 计数器 64 位 | 保证同密钥下不重复 | 重复将导致明文可被推导 |
| 附加认证数据 | 会话标识与序号 | 把数据包绑定到会话 | 缺失会让跨会话重放成为可能 |
| 分组模式 | GCM(CTR + GHASH) | 并行加密与校验 | 实现错误会破坏完整性保证 |
| 密钥来源 | HKDF-SHA256 派生 | 从共享秘密生成会话密钥 | 派生不当会削弱熵 |
随机数为什么不能只用随机数
纯随机生成的 96 位随机数在单会话内重复概率极低,但在一亿次会话的规模下,生日界会开始变得不友好。加入单调计数器后,同一密钥下的随机数在构造上就不重复,去掉了对随机源质量的依赖——这一点在虚拟机的熵源不稳定时尤为重要。
- 计数器优先 会话内随机数单调递增,不依赖随机源的实时质量。
- 前缀隔离 每次会话重新抽取 32 位前缀,避免不同会话之间出现相同序列。
- 密钥不跨会话 会话结束时密钥销毁,随机数空间随之重置,不做跨会话复用。
- 审计可核对 随机数生成逻辑在审计范围内,审计方可在受控环境观察序列结构。
密钥派生与轮换
密钥轮换的价值在于把单次密钥泄露的影响限制在一段时间内,而不是让整条会话失效。
握手阶段的共享秘密并不直接当作会话密钥,而是经 HKDF-SHA256 以会话标识为盐派生,输出 32 字节密钥与独立的 IV 前缀。轮换触发条件有三:时间达到 30 分钟、数据量达到 4 GB、网络切换。三者取先到者,均在下一次数据包边界执行。
派生流程
- 协商客户端与接入节点以 X25519 交换临时公钥,得到共享秘密,双方各自计算不传输。
- 抽取HKDF-Extract 以会话标识为盐,对共享秘密做一次抽取,得到固定长度伪随机密钥。
- 扩展HKDF-Expand 输出 32 字节会话密钥与 4 字节随机数前缀,分别用于加密与随机数构造。
- 轮换达到时间或数据量阈值时以当前密钥为输入再做一次抽取,旧密钥在使用后立即清零。
轮换策略的三个约束
- 不下线轮换 轮换在数据包边界完成,不重建隧道,用户侧不出现可见断流。
- 单向推进 新密钥只由旧密钥派生,不能反向推导,形成单向链条。
- 次数上限 单会话最多轮换 96 次,超过后强制重连并重新协商临时公钥。
- 计数留痕 轮换次数写入本地事件摘要,用于排查异常的长连接。
| 触发条件 | 阈值 | 行为 | 可观察影响 |
|---|---|---|---|
| 时间 | 每 30 分钟 | 包边界更换密钥 | 无感知 |
| 数据量 | 累计 4 GB | 包边界更换密钥 | 无感知 |
| 网络切换 | Wi-Fi 与蜂窝切换 | 立即重协商临时公钥 | 约 0.4 秒停顿 |
| 会话次数上限 | 96 次 | 强制重连 | 约 1.2 秒停顿 |
| 异常检测 | 认证失败连续 3 次 | 丢弃会话并重协商 | 提示一次重连 |
TLS 1.3:保留而不是替代
很多方案会把站点侧的 TLS 终结掉再重新加密,代价是出口节点能看到全部正文。快喵不做这件事。
在快喵的连接中,浏览器与目标站点之间的 TLS 1.3 连接原样保留。出口节点只是转发字节流,不持有站点证书的私钥,也无法解密。这意味着即使出口节点被完全控制,攻击者拿到的仍然是站点加密后的密文,配置失误也无法改变这一点。
需要区分两种常见做法:一种是隧道只承载站点 TLS 的密文,此时出口无法读取正文;另一种是出口终结站点 TLS 再重新加密,此时出口必然持有明文。两者在用户侧的表现几乎一样,差异只体现在实现与证书链上,这也是本文把不签发站点证书单独列出的原因。
保留 TLS 的三个直接后果
- 正文不可读 出口节点不终结站点 TLS,看不到 HTTP 正文、Cookie 与表单内容。
- 证书链本地校验 证书信任判定在客户端完成,中间人无法用伪造证书通过校验。
- 前向保密叠加 TLS 1.3 的临时密钥交换与隧道层的前向保密叠加,两层都不能被回溯。
- 支持 HTTP/3 QUIC 走 UDP,隧道层对 UDP 做同样封装,不强制降级到 TCP。
我们如何避免“解密再加密”
关键在于不部署能签站点证书的中间 CA。快喵的基础设施中没有安装用于站点证书签发的根证书,客户端的系统证书库也不被修改。这一设计在 2026 年 6 月的受控连接复核中被单独验证:复核方在客户端与出口两侧分别抓包,确认正文两侧均为站点密文。
| 观察位置 | 可见内容 | 可见目标 | 可否解密正文 | 备注 |
|---|---|---|---|---|
| 客户端网卡(隧道内) | 隧道密文 | 节点地址 | 否 | 目标在密文头内 |
| 本地网关侧 | 隧道密文 | 节点地址 | 否 | 无明文可嗅探 |
| 接入节点 | 隧道密文 + 密文头 | 加密形态的目标 | 否 | 不终止站点 TLS |
| 出口节点 | 站点 TLS 密文 | 目标地址 | 否 | 无站点私钥 |
| 目标站点 | 请求正文 | 出口地址 | 不适用 | 仅见共享出口地址 |
实测开销与边界
加密不是免费的。把开销量化,才能判断它在什么网络条件下仍然可用。
2026 年 8 月的测试在千兆家庭宽带与 4G 热点两种环境各采集 200 次传输:开启隧道后下行吞吐中位数从 486 Mbps 降至 458 Mbps,降幅 5.8%;上行从 92 Mbps 降至 88 Mbps,降幅 4.3%。握手额外耗时中位 62 毫秒,其中 41 毫秒来自一次额外的往返。
| 指标 | 未加密基线 | 开启隧道 | 变化 | 测试条件 |
|---|---|---|---|---|
| 下行吞吐 | 486 Mbps | 458 Mbps | -5.8% | 千兆宽带,200 次中位 |
| 上行吞吐 | 92 Mbps | 88 Mbps | -4.3% | 千兆宽带,200 次中位 |
| 握手耗时 | 0 ms | 62 ms | +62 ms | 含 1 次额外往返 |
| 首屏时间 | 1.28 秒 | 1.41 秒 | +0.13 秒 | 同一站点,缓存关闭 |
| 4G 环境下行 | 38 Mbps | 35 Mbps | -7.9% | 4G 热点,200 次中位 |
| CPU 占用 | 3.1% | 6.4% | +3.3 个百分点 | 四核 2.4 GHz,单流播放 |
需要强调的是,这组数字的对照条件相当理想:本机与测速节点之间没有跨运营商绕行,也没有高峰期拥塞。在跨运营商或跨境场景下,隧道带来的路径变化会比加密本身产生更大影响,因此本章只把 5.8% 视为加密开销的上界参考,而不是任何场景的预期值。
开销主要来自哪里
开销集中在三处:额外的握手往返、封装头带来的有效载荷比下降,以及 MTU 不匹配引发的分片。第三项影响最大,因此在 V3.2 中加入了 MTU 自动探测,把常见链路上的分片率从 2.7% 降到 0.3%,这是下行吞吐提升的主要来源。
- 握手往返 一次额外往返约 40 毫秒,可通过会话复用减少到仅在首次连接时发生。
- 封装头开销 每包增加约 45 字节头部,对大包影响可忽略,对小包影响较明显。
- 分片 MTU 不匹配会造成重传,V3.2 的自动探测把分片率降至 0.3%。
- CPU AES-NI 加速后单核可处理 1.2 GB/s,消费级设备不构成瓶颈。
我们明确不做的事
把不做的事写清楚,比把做的事写得漂亮更有信息量。
密码学领域的常见失败模式有共同点:为了某个短期指标而 weakening 既有保证。快喵在文档里列出四条不做的事,它们同时也是审计时的检查项。
- 不签发站点证书 不部署中间 CA,不修改系统证书库,不实现解密再加密。
- 不降级放行 证书异常、验签失败、配置校验不通过时一律中断,不存在“继续访问”的选项。
- 不使用私有算法 不引入自研加密或私有改造的公开算法,算法实现随版本可核对。
- 不静默变更 阈值、算法与字段表的任何变更都进入更新记录,标注旧值、新值与原因。
为什么“不降级”需要写进代码
降级往往是产品需求的产物:用户抱怨连不上,最容易的修法就是给一个“忽略证书错误继续访问”的开关。快喵没有提供这个开关,客户端在校验失败时只显示两个选项——重试与切换节点。原因很直接:一旦开关存在,它就会在技术支持话术里变成默认建议,几个月后没人记得它当初为什么被打开。
审计报告第 4 节逐条对应上述四条:以抓包确认无中间 CA、以故障注入确认无降级路径、以代码清单确认算法实现来源、以更新记录比对确认变更留痕。任一项未通过都会以偏差项形式列在报告里,而不是被内部消化。
本文所有性能数值来自自有测试环境,只对应给出的条件组合。不同运营商、不同线路与不同设备上的实际结果会偏离,偏离幅度可能超过 3 个百分点。
附录:算法参数汇总
本节把本章出现的算法与参数集中列出,便于一次性核对。
术语表
- 认证加密
- 在同一原语内同时提供机密性与完整性的加密模式,GCM 属于此类。
- 认证标签
- GCM 输出的 128 位校验值,接收端据此判断数据包是否被改动。
- 随机数(nonce)
- 一次性使用的数值,同密钥下不得重复,本章采用前缀加计数器构造。
- HKDF
- 基于 HMAC 的密钥派生函数,分抽取与扩展两步,见 RFC 5869。
- 临时公钥
- 每次握手重新生成的 X25519 密钥对,用完即弃,是前向保密的基础。
- 分片
- 数据包超过路径 MTU 时被拆分传输,会增加重传概率与开销。
- 会话复用
- 在已建立的隧道上承载新的站点连接,用于摊薄握手成本。
- 降级放行
- 校验失败时仍允许流量通过的行为,本章将其列为明确禁止项。
参数速查
| 项目 | 取值 | 标准或来源 | 备注 |
|---|---|---|---|
| 对称加密 | AES-256-GCM | NIST SP 800-38D | 标签 128 位 |
| 密钥交换 | X25519 | RFC 7748 | 每次握手新生成 |
| 密钥派生 | HKDF-SHA256 | RFC 5869 | 会话标识作盐 |
| 站点侧协议 | TLS 1.3,最低 1.2 | RFC 8446 | 不终结、不代理 |
| 轮换周期 | 30 分钟或 4 GB | 实现约定 | 取先到者 |
| 最大轮换次数 | 96 次 | 实现约定 | 超限强制重连 |
| 实测降幅 | 下行 5.8% | 2026-08 自有环境 | 400 次传输中位 |
引用本章数值时请同时给出测试条件(版本、环境、样本量)。单独摘出百分比会失真,因为开销与 MTU、线路质量强相关。
迁移路径与自查
算法会过时。真正需要提前设计的不是算法本身,而是更换算法时的迁移方式。
快喵VPN 把算法标识放在配置包里而不是编译进客户端,因此更换套件不需要用户升级。2026 年 8 月的演练中,用一次配置下发把测试集群的对称算法从 AES-128-GCM 切换到 AES-256-GCM,全程 11 分钟,客户端无重装、无感知断流,切换后的首包即使用新密钥。
这套设计的前提是客户端具备算法标识的可配置性,而可配置性本身带来风险:一旦配置包被篡改,攻击者可以下发一个更弱的套件。因此算法标识与节点表位于同一个签名包内,客户端验签通过后才允许切换,且只接受在白名单内的标识。不在白名单内的标识会被忽略并记录一条事件,而不是尝试协商。
迁移的四个阶段
- 通告配置包同时携带新旧两套算法标识,客户端按优先级选择,未升级版本仍可连接。
- 灰度按 5%、25%、60% 的比例分批切换,每批观察 24 小时的认证失败率与重连次数。
- 收敛灰度通过后移除旧算法标识,客户端回落到新算法,旧实现保留一个版本用于回滚。
- 清理两个版本后删除旧算法代码路径,避免长期保留两套实现导致维护负担。
读者自查清单
- 查实际套件 抓包确认协商出的套件是 AES-256-GCM,而不是被协商回退到更短的密钥。
- 查随机数 确认同一会话内随机数单调递增,不同会话之间前缀不同。
- 查轮换 保持长连接 35 分钟以上,确认发生至少一次密钥轮换且连接未中断。
- 查销毁 断开连接后检索进程内存,确认检索不到密钥字节。
- 查降级 人为破坏认证标签,确认数据包被丢弃而不是被解密为错误内容。
算法与用途对照
| 用途 | 算法 | 标准编号 | 何时更换 | 迁移影响 |
|---|---|---|---|---|
| 对称加密与完整性 | AES-256-GCM | NIST SP 800-38D | 出现实用攻击或硬件不支持 | 配置下发切换,无重装 |
| 密钥交换 | X25519 | RFC 7748 | 标准化组织推荐迁移 | 需重协商,约 0.4 秒停顿 |
| 密钥派生 | HKDF-SHA256 | RFC 5869 | 哈希函数被削弱 | 透明替换 |
| 站点侧协议 | TLS 1.3 | RFC 8446 | 标准版本更新 | 由站点与浏览器决定 |
| 完整性校验 | GCM 认证标签 | NIST SP 800-38D | 标签长度策略调整 | 需双方同步 |
迁移设计里最容易犯的错误是把新算法当作默认值直接推送,导致老旧客户端连接失败后被用户感知为“服务挂了”。灰度比例与回滚窗口是迁移方案的必要组成,而不是可选项。快喵的灰度每批至少观察 24 小时,且要求认证失败率低于 0.1% 才进入下一批。
建议按“观察位置 + 时间戳 + 结论”三要素记录,例如:客户端网卡、2026-11-10 14:02、协商套件为 AES-256-GCM。只有三要素齐全的记录才能在版本变化后判断是否需要重做。