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.
Round-trip an ESP header with an opaque payload
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);