applyHeaderProtection function
Applies Header Protection (XORing the first byte and the Packet Number) using the result of AES-ECB(HP Key, Sample).
Implementation
Uint8List applyHeaderProtection(
Uint8List packet,
int pnOffset,
Uint8List hpKey,
int pnLength,
) {
// QUIC Header Protection Sample is 16 bytes starting at pnOffset + 4
const sampleLength = 16;
if (pnOffset + 4 + sampleLength > packet.length) {
throw Exception("Not enough bytes for header protection sample");
}
// 1. Get sample
final sample = packet.sublist(pnOffset + 4, pnOffset + 4 + sampleLength);
// 2. Encrypt sample using AES-ECB
final maskFull = aesEcbEncrypt(hpKey, sample);
final mask = maskFull.sublist(0, 5); // Use the first 5 bytes of the output
// Create a mutable copy of the packet
final resultPacket = Uint8List.fromList(packet);
// 3. Apply mask to the first byte (Header Type)
final firstByte = resultPacket[0];
final isLongHeader = (firstByte & 0x80) != 0;
if (isLongHeader) {
// Long Header: Only XOR the lowest 4 bits (Version Specific + Reserved + Packet Number Length)
resultPacket[0] ^= (mask[0] & 0x0f);
} else {
// Short Header: Only XOR the lowest 5 bits (Key Phase + Reserved + Packet Number Length)
resultPacket[0] ^= (mask[0] & 0x1f);
}
// 4. Apply mask to the Packet Number field (pnLength bytes)
for (var i = 0; i < pnLength; i++) {
resultPacket[pnOffset + i] ^= mask[1 + i];
}
return resultPacket;
}