applyHeaderProtection function

Uint8List applyHeaderProtection(
  1. Uint8List packet,
  2. int pnOffset,
  3. Uint8List hpKey,
  4. int pnLength,
)

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;
}