跳到主要内容

5. 数据包保护

QUIC 与 TCP 上的 TLS 一样, 使用从 TLS 握手派生出的密钥保护数据包, 并使用 TLS 协商出的 AEAD 算法. 不同类型的 QUIC packet 具有不同保护属性: Version Negotiation packet 没有密码保护; Retry packet 使用固定的 AEAD_AES_128_GCM 保护以防意外修改并限制可生成有效 Retry 的实体; Initial packet 使用从客户端首个 Initial packet 的 Destination Connection ID 派生出的密钥; 其他 packet 使用 TLS 协商出的强机密性和完整性保护.

每个加密级别在两个方向上都有独立的 traffic secret. 除 Initial 级别外, 这些 secret 由 TLS 派生, QUIC 再通过 TLS 提供的 KDF 计算 packet protection key、IV 和 header protection key. TLS 1.3 中使用 HKDF-Expand-Label, QUIC 标签包括 "quic key", "quic iv""quic hp".

Initial secret 使用固定 salt 和客户端首个 Initial packet 的 Destination Connection ID 通过 HKDF-Extract 计算, 再分别派生客户端和服务器方向的 Initial secret. 由于 Initial key 容易由观察者计算, Initial packet 不被视为提供真正的机密性或完整性.

构造 packet 时, 先应用 AEAD, 再应用 header protection. 未保护的 packet header 作为 associated data 参与认证. 接收 packet 时, 端点先移除 header protection, 恢复 packet number, 再用 packet protection key 和 IV 验证并解密负载.

Header protection 使用单独派生的 key 保护首字节的低位以及 Packet Number 字段, 使路径上的设备无法观察这些字段. AES-GCM、AES-CCM 和 ChaCha20-Poly1305 分别定义了相应的 header protection 算法. Retry 和 Version Negotiation packet 不包含受此过程保护的字段.

端点在接收受保护 packet 时, 如果某个 packet 看起来触发 key update 但无法成功解保护, 必须丢弃该 packet. 0-RTT key 只能用于 0-RTT packet, 且必须考虑早期数据可能被重放的风险. 对乱序到达的受保护 packet, 实现需要能够在允许范围内保留或生成合适的接收密钥.