IPsec Encapsulating Security Payload (ESP) header encoding and decoding (RFC 4303).

An ESP packet opens with an 8-byte unencrypted header followed by the encrypted payload:

 0      7 8     15 16    23 24    31
+--------+--------+--------+--------+
|      Security Parameters Index    |
|               (SPI)               |
+--------+--------+--------+--------+
|           Sequence Number         |
+--------+--------+--------+--------+
|                                   |
~           Payload Data            ~
|                                   |
+-----------------------------------+

RFC 4303 defines further structure inside the payload — padding, a pad length, a next-header field, and an Integrity Check Value trailer — but all of it lives inside the encrypted (and often authenticated) region. None of it can be located or interpreted without performing the actual decryption, which is out of scope for a binary-structure coder. This package therefore stops at the 8-byte header: payloadData is handed back as opaque bytes, rest-of-buffer, for the caller to decrypt with whatever crypto library and security association it has on hand.

Examples

Round-trip an ESP header with an opaque payload

import { assertEquals } from "@std/assert";
import { espPacket } from "@binstruct/esp";

const coder = espPacket();
const packet = {
  spi: 0x12345678,
  sequenceNumber: 1,
  payloadData: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),
};

const buffer = new Uint8Array(64);
const written = coder.encode(packet, buffer);
const [decoded, read] = coder.decode(buffer.subarray(0, written));

assertEquals(written, read);
assertEquals(decoded.spi, packet.spi);
assertEquals(decoded.sequenceNumber, packet.sequenceNumber);
assertEquals(decoded.payloadData, packet.payloadData);