在同一台网关上测试两份配置,一份加密、一份不加密,而加密的那份并不更慢。有时它反而更快,这通常会引发一场关于测试是否做对的长时间争论。结果说得通,因为一个数据包的成本并不是配置里写了几个密码学术语。它是实现真正执行的操作集合,取决于它手里的硬件,以及它选择的缓冲区布局。

症状:慢的并不是加密那份配置

假设一个历史测试拿 AEAD 密码与「不加密」模式比较,而后者仍然为每个数据包单独计算一个认证码。第二份配置隐藏了载荷内容,却保留了逐包哈希;在没有该哈希硬件加速的处理器上,它的开销可能超过它本应胜过的那种一体化结构。

配置里的标签写着「加密」,而绝大多数比较只看这个标签。数据包路径说的却是另一回事:一份配置执行的是 CPU 有指令支持的合并操作,另一份执行的是 CPU 没有指令支持的单独操作。只读配置文件永远看不出这个差别,因为两条记录看起来都只是一行。只有协商后的模式以及它背后的代码路径才能解释结果。

这就是全部解释,它并不需要断言哪种原语在任何情况下都更快。两者都可以很快,也都可以很慢,先后顺序取决于机器和代码。

数操作,而不是数标签

如 RFC 5116 所述,AEAD 结构给实现提供单一接口,同时返回密文和标签。AES-GCM 就是一个例子:计数器模式加密与 Galois 认证器组合在一起。这个接口并没有让完整性变成免费,它让组合有了明确定义,从而让实现可以把这两半当作一个整体来优化。

Separate authentication path:
  payload -> independent HMAC -> framed packet

AEAD path:
  payload -> authenticated encryption with tag -> framed packet

这些是处理流程的示意,不是配置建议。前者没有机密性,却仍然在认证上花 CPU,这正是「关掉加密」不等同于「关掉密码学工作」的原因。

后者可能更便宜,因为处理器为这两半都提供了指令:AES 轮运算,以及 Galois 域使用的无进位乘法。库还会并行处理彼此独立的缓冲区,让这些指令保持忙碌,而不是等内存。

协商后的模式究竟启用了什么

在 Community OpenVPN 中,使用 AEAD 数据密码意味着 auth 选项不再贡献它自己单独的数据通道 HMAC。加密选项的参考文档描述了这一范围,这也是文本文件里看起来相似的两种配置会在每包开销上出现差异的原因。

要读协商后的模式,而不是愿望清单。允许的密码列表和 TLS 套件名称并不会告诉你载荷上跑了哪些操作,而旧的 cipher 那行也可能没有描述当前连接实际选了什么。

openvpn --show-ciphers | head -20
sudo grep -E 'cipher|auth' /etc/openvpn/server.conf

第一条命令列出该二进制支持的密码,那是能力清单,不是协商结果。第二条显示服务器实际要求的是什么。连接日志才是确认最终选择的地方,因为客户端可能回落到服务器允许、却没人想要的东西上。

测量你真正在跑的负载

密码学微基准测试测的是某个原语在它自己条件下的表现。VPN 传输还要复制缓冲区、调度线程或中断、检查策略,并穿越网络。这些部分往往占主导,所以更快的原语并不总能带来更快的隧道。

openssl speed -evp aes-256-gcm
openssl speed -evp sha1

这两条命令给你的是眼前这台机器上各原语的大致本地比较,它们也很诚实地说明自己是微基准测试。它们完全不能代表你隧道的吞吐量,绝不该被当作吞吐量来引用。

然后测量真正重要的负载,其他条件保持不变:同一端点、同样的包大小、同样的传输方式、同样的压缩策略。如果换配置同时改变了传输方式或处理位置,那结果描述的是那一整套变化,而不是密码学。

也要把目标放在视野里。即使数据路径还有多余的密码学算力,也可能因为应用在等往返而受延迟限制,而批量容量的提升并不能治好话多的协议。要把受支持且经策略批准的配置作为一个整体来测量,并把「盒子更少就一定更快」当作它本来的假设来看待。有用的问题不是加密有没有成本,而是这项成本会不会出现在你真正关心的测量里。

相关文章