摘要

  • 10 月 1 日发布的 draft-ietf-tcpm-tcp-ao-algs-08 明确指出,KMAC256-KDF 遵循 NIST SP 800-56C Revision 2 的 KMAC# 变体,而不能只按 SP 800-185 中通用 KMAC 的名称理解。
  • 因此,两个设备界面上同时出现 KMAC256 只是配置坐标;互通证明必须继续覆盖变体、公开参数、编码、连接上下文、测试向量结果与实际 TCP-AO 选项字节。

一次上线窗口里,甲端显示 KMAC256,乙端也显示 KMAC256。两组工程师确认名称相同,于是把算法差异从排障清单中删去。会话却没有建立。此时最危险的结论,不是怀疑密码原语,而是认为“同名已经排除了算法不一致”。

第 08 版草案把这个判断边界写得更清楚。它说明,KMAC256 及其参数最初见于 NIST SP 800-185;SP 800-56C Revision 2 又定义了一个参数集合不同的 KMAC256 变体 KMAC#。草案所称的 KMAC256-KDF 明确遵循后者。新版还补充:以网络字节序编码的 32 位整数 1 表示该 KDF 的版本。

这不是安全漏洞公告,也不是互通事故复盘。该文件仍是 TCPM 工作组的活跃 Internet-Draft,目标状态为 Standards Track。工作组页面把提交 IESG 的里程碑列在 2026 年 11 月,但里程碑不等于已经提交,更不等于批准。当前抓取的 IANA TCP-AO 算法注册表仍只有 SHA1 与 AES128;草案只是请求加入 HMAC-SHA256-128 与 KMAC256-128。

真正需要双方共同执行的 KDF 契约并不长。草案给出 132 字节全零 salt;按网络字节序表示的 32 位计数器 1;作为 TCP-AO 主密钥的 Z;作为连接上下文的 FixedInfo;256 位输出长度;以及 ASCII 字节串 KDF 作为定制字符串。输出长度恰好等于所需流量密钥长度,所以只调用一次 KMAC256。

随后计算报文认证码时,契约又发生一次切换。KMAC256-128 使用上一步得到的 256 位流量密钥,以 TCP-AO 指定的报文为输入,定制字符串为空,并直接请求 128 位 KMAC 输出。这个 16 字节结果连同 Kind、Length、KeyID 与 RNextKeyID,使完整 TCP-AO 选项占用 40 字节 TCP 选项空间中的 20 字节。KDF 阶段的 KDF 与 MAC 阶段的空字符串不能被当成同一个默认值。

FixedInfo 也不是随意附加的标签。RFC 5925 把源地址、目的地址、双方端口与初始序列号组合成 KDF 上下文。流量密钥具有方向性。SYN 尚不知道对端初始序列号时,相应位置用零;后续报文在已知时使用双方序列号。任何一处方向、字段顺序或编码不同,都可能让双方在输入主密钥相同的情况下得到不同结果。

抓包本身也不会把全部配置事实告诉观察者。TCP-AO 选项携带 Kind、Length、KeyID、RNextKeyID 与 MAC,却不在选项里声明 MAC 算法。算法与 KDF 由带外配置的 Master Key Tuple 关联。相同 KeyID 在两个端点可以被绑定到不同的本地配置,这正是为什么线上的失败还需要回到配置证据,而不能只看一个字段。

适合运营审计的对象应是一份“算法实例凭证”。它记录草案版本、KDF 与 MAC 标识、所依据的 NIST 文档版本、salt 长度和值、计数器数值与字节序、输出长度、两个阶段各自的定制字符串、Master Key Tuple 的非秘密标识、实现与构建版本,以及已约定测试向量结果的哈希。然后再把这些内容与抓到的 TCP-AO 选项字节、对端验证结果、TCP 状态和上层协议结果连接起来。

凭证不应记录主密钥或生产流量密钥。密钥标识可以说明使用了哪一份受控配置,而不泄露秘密;已公开测试向量的结果可供双方比较。为了“可观测”而把生产秘密写进日志,只是用一种控制失败替换另一种控制失败。

草案附录已经提供 IPv4 与 IPv6 的 KMAC 测试向量,并分别覆盖“包含其他 TCP 选项”和“不包含其他 TCP 选项”的情况。实现通过向量,证明它在那组固定输入下复现了预期计算;它不能顺带证明现场两端加载了同一 Master Key Tuple、使用同一连接方向、选择同一 KeyID,或对同一组字节进行了认证。

所以证据必须分层。一条能力声明只能说明软件宣称支持该算法。测试向量一致说明某个受控算例一致。一个报文通过验证说明接收端在当时状态下接受了那段报文。TCP 进入 Established 是另一层。BGP OPEN、Keepalive 或其他应用交换成功还要再上一层。把这些层都压缩成“支持 KMAC256”,会让故障定位在最需要精度时失去精度。

这正好落在 Heng Lu 所说的 Minimum Initial Specification 边界内。共同层只规定独立实现必须共享的内容,但“最小”绝不等于模糊。函数变体、参数角色、编码、上下文和输出长度,是算出相同字节所必需的最小共同事实。软件库、密钥存储、接口设计和监控系统可以由各方自行选择;数学输入契约不能各自解释。

Running-Code Primacy 又把证明顺序倒过来:草案名称与配置标签只是坐标,可复现的向量和运行系统实际产生、接受的字节才是更强证据。Reality Layers 则要求分别看待草案、注册表请求、本地配置、导出密钥的一致、单个认证报文、TCP 会话和应用结果。这是 Daniel Kade 对 Heng Lu 方法的编辑性运用,不是 IETF、TCPM 或 NIST 的立场。

证据也要求克制。第 08 版没有说 KMAC 或 TCP-AO 已被攻破,没有证明第 07 版实现互相冲突,也没有指出任何厂商调用了错误接口。早期 Security Directorate 评审曾询问新算法组合的收益、更长输出及 TCP 选项空间取舍,但现有公开材料不能证明那次评审导致了本次文字补充。

这条新闻的价值因此不在“算法升级”,而在“互通对象被重新看清”。被配置的不是一个名字,而是一整个函数实例。保存这个实例,运营团队才能把变体不一致、密钥不一致、上下文不一致、报文拒绝与上层协议失败分开。只保存 KMAC256,等于保存了目录标题,却没有保存正文。

来源