5 个版本 (3 个重大更新)
0.4.0 | 2022年11月27日 |
---|---|
0.3.0 | 2021年7月25日 |
0.2.1 | 2021年7月3日 |
0.2.0 | 2021年5月17日 |
0.1.0 | 2021年5月10日 |
#1254 in 密码学
40KB
742 行
quinn quic 实现的 Noise 加密库
握手模式
使用可选的 psk 与 IK 握手模式相结合。psk 允许使用预共享密钥构建私有 P2P 网络。在 P2P 环境中,静态密钥是已知的,IK 握手允许 0-rtt 加密。在许多 P2P 网络中,身份隐藏不是问题。
IKpsk1:
<- s
...
-> e, es, s, ss, psk || client transport parameters || 0rtt-data
<- e, ee, se || server transport parameters || 1rtt-data
身份和密钥交换
签名密钥在 P2P 网络中用作身份。由于 IK 握手需要提前知道握手密钥,因此签名密钥被用于密钥交换。使用与 libsodium 实现的相同算法,ed25519 密钥被转换为 x25519 密钥。
注意:虽然重用密钥进行签名和 Diffie-Hellman 可能是可行的,但强烈建议不要将密钥用于其他协议,如 VRF 或门限签名。
加密算法
使用 xoodyak(NIST 轻量级加密竞赛的决赛选手),执行以下操作以推导 0rtt-key、1rtt-key 和 next-1rtt-key。为了快速认证加密,使用 chacha8poly1305 密文。
会话
会话转储初始化为协议标识符。将客户端临时密钥和服务器静态公钥以及 es dh 吸收到会话转储中。从该会话转储中提取会话标识符,该标识符用于根据 xoodyak 论文第 3.3 节初始化密钥会话转储,以使用公共密钥进行认证加密。将加密的客户端静态公钥、ss dh 和 psk(如果没有提供,默认为 [0; 32])添加到会话转储中。然后将用于标识应用程序协议的加密 ALPN 字符串和根据 quic 规范定义的加密客户端传输参数添加到转储中。常见的 ALPN 字符串是 h3
(用于 Web)或 libp2p
(用于 libp2p 应用程序)。最后,从加密的密钥帧和 0-rtt 密钥中提取认证标签。
初始数据包的加密帧包含协议标识符、客户端临时公钥、加密的客户端静态公钥、加密的 ALPN 标识符、加密的客户端传输参数和认证标签。在初始数据包之后,可以使用提取的 0-rtt 密钥发送 0-rtt 数据包,而不必等待服务器响应。
Initial:
| Cyclist({}, {}, {})
p | Absorb("Noise_IKpsk1_Edx25519_ChaCha8Poly")
p | Absorb(e)
| Absorb(s)
| Absorb(es)
| key = Squeeze(32)
| Cyclist(key, {}, {})
c | Encrypt(s)
| Absorb(ss)
| Absorb(psk)
c | Encrypt(alpn)
c | Encrypt(client_transport_parameters)
t | Squeeze(16)
| initiator-0rtt-key = SqueezeKey(32)
| responder-0rtt-key = SqueezeKey(32)
在接收到初始数据包后,服务器生成一个握手数据包,包含加密的服务器临时公钥和加密的服务器传输参数。在握手数据包之后,可以发送1-rtt数据包。一旦所有0-rtt数据包都被确认,则丢弃密钥。
Handshake:
c | Encrypt(e)
| Absorb(ee)
| Absorb(se)
c | Encrypt(server_transport_parameters)
t | Squeeze(16)
| initiator-1rtt-key = SqueezeKey(32)
| responder-1rtt-key = SqueezeKey(32)
在传输会话期间,可能需要轮换1-rtt密钥。这发生在接近发送u64::MAX
个数据包或连接强制要求时。有关详细信息,请参阅QUIC规范。
Key rotation:
| Ratchet()
| initiator-next-1rtt-key = SqueezeKey(32)
| responder-next-1rtt-key = SqueezeKey(32)
QUIC版本
为quinn-noise
保留的版本是0xf0f0f2f[0-f]
[0]。目前只有0xf0f0f2f0
是有效的quinn-noise
版本。
头部保护
头部保护/混淆旨在防止中间盒子读取头部。由于头部作为关联数据传递给加密算法,因此修改是不可能的。设想在未来的QUIC版本中,如果头部发生变化,中间盒子可能会丢弃数据包,因为它们无法读取头部。但是头部保护/混淆只是使其更难,而不是不可能。由于对它是否达到目的存在疑问,因此决定不应用头部混淆。
重试机制
重试机制与quic-tls规范中指定的机制相同。
许可证
MIT OR Apache-2.0
依赖项
~13MB
~330K SLoC