QUIC使用秘钥(过段时间更换一次)对应用数据加密后,需要单独对包头加密。
1、格式
长报头加密字段:
±±±±±±±±+
|1|1|T T|E E E E|
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±+
| Version -> Length Fields …
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±+
短报头加密字段:
±±±±±±±±+
|0|1|S|E E E E E|
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±+
| Destination Connection ID (0/32…144) …
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±+
普通字段:
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±+
|E E E E E E E E E Packet Number (8/16/24/32) E E E E E E E E…
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±+
| [Protected Payload (8/16/24)] …
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±+
| Sampled part of Protected Payload (128) …
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±+
| Protected Payload Remainder (*) …
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±+
报文示例:
Initial Packet {
Header Form (1) = 1,
Fixed Bit (1) = 1,
Long Packet Type (2) = 0,
Reserved Bits (2), # Protected
Packet Number Length (2), # Protected
Version (32),
DCID Len (8),
Destination Connection ID (0…160),
SCID Len (8),
Source Connection ID (0…160),
Token Length (i),
Token (…),
Length (i),
Packet Number (8…32), # Protected
Protected Payload (0…24), # Skipped Part
Protected Payload (128), # Sampled Part
Protected Payload (…) # Remainder
}
1-RTT Packet {
Header Form (1) = 0,
Fixed Bit (1) = 1,
Spin Bit (1),
Reserved Bits (2), # Protected
Key Phase (1), # Protected
Packet Number Length (2), # Protected
Destination Connection ID (0…160),
Packet Number (8…32), # Protected
Protected Payload (0…24), # Skipped Part
Protected Payload (128), # Sampled Part
Protected Payload (…), # Remainder
}
2、抽样
因为接收端收到报文解密时,提取抽样需要跟发送端一致才能正确解密,而包编号的长度不是固定值,所以解密假设包编号长度为4字节,那么发送端抽样需要从4字节后开始,所以会出现跳过部分(即Protected Payload (0…24), # Skipped Part),用于补足4字节。
使用秘钥+抽样进行加密,个人猜测是因为应对侧信道攻击,因为包头保护的秘钥在连接期间不能改变,需要加入抽样扰乱每个数据包的加密能量规律。
3、加密过程
先根据秘钥和抽样由特定的加密算法(建链协商决定)得到mask,mask使用异或保护报头字段。分组的第一字节的最低有效位被mask第一个字节的最低有效位加密,包编号用剩余字节加密:
mask = AES-ECB(hp_key, sample)
pn_length = (packet[0] & 0x03) + 1
if (packet[0] & 0x80) == 0x80:
#长报头: 4 bits masked
packet[0] ^= mask[0] & 0x0f
else:
# 短报头: 5 bits masked
packet[0] ^= mask[0] & 0x1f
# pn_offset是包编号字段的起始位置.
packet[pn_offset:pn_offset+pn_length] ^= mask[1:1+pn_length]