ike

package
v0.577.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 6, 2026 License: AGPL-3.0 Imports: 4 Imported by: 0

Documentation

Overview

Package ike decodes IKEv2 (Internet Key Exchange version 2) messages per RFC 7296. IKEv2 is the control-plane protocol that negotiates the IPsec Security Associations (SAs) consumed by ESP (RFC 4303, covered by `esp_decode`) and AH (RFC 4302, covered by `ah_decode`). Without IKE the SPIs + keys + algorithms ESP/AH need come from nowhere; with IKEv2 we decode the negotiation that produces them.

IKEv2 is universal on every site-to-site VPN + IPsec remote-access deployment — StrongSwan, OpenSwan/Libreswan, Cisco AnyConnect IPsec mode, FortiGate, pfSense, OPNsense, Windows IPsec, macOS IKEv2 client. Runs on UDP destination port 500, or UDP 4500 with a 4-byte all-zeros marker when behind NAT (NAT-T per RFC 3947 / 3948).

Wrap-vs-native judgement

Native. RFC 7296 is fully public. IKEv2 has a tight
28-byte fixed header followed by a chained list of
payloads (each a 4-byte header + body). The first
exchange (IKE_SA_INIT) is sent unencrypted so SA
proposals, KE shares, nonces, and NAT-T markers are
decoded fully; from IKE_AUTH onwards the payload bodies
are wrapped in an Encrypted (SK) payload whose
plaintext is opaque without the IKE-derived keys
(surfaced as hex; full decryption would require an
IKE-state-aware iteration).

What this package covers

  • **28-byte fixed header** (RFC 7296 §3.1):

  • bytes 0-7: Initiator SPI (uint64 BE; the SA's initiator-side identifier).

  • bytes 8-15: Responder SPI (uint64 BE; zero in the first IKE_SA_INIT request, set in the reply).

  • byte 16: Next Payload (first payload's type code).

  • byte 17: Version (4-bit Major / 4-bit Minor; 2/0 for IKEv2).

  • byte 18: **Exchange Type** with **4-entry name table** (RFC 7296 §3.1): 34 IKE_SA_INIT, 35 IKE_AUTH, 36 CREATE_CHILD_SA, 37 INFORMATIONAL.

  • byte 19: **Flags** decoded into **3 named bits**: R (Response — 0x20), V (Version — 0x10; only set by responders), I (Initiator — 0x08).

  • bytes 20-23: Message ID (uint32 BE; per-SA monotonic; matches request/reply).

  • bytes 24-27: Length (uint32 BE; total message length including this header).

  • **Payload walker** — chained list driven by the Next Payload field of the previous payload (or of the IKE header for the first). Each payload header is 4 bytes: Next Payload (1B) + Critical (1B; high bit only) + Payload Length (uint16 BE; total including this 4-byte header). Walker terminates when Next Payload = 0.

  • **~15-entry payload type name table** (RFC 7296 §3.2 + IANA "IKEv2 Payload Types" registry): 33 SA (Security Association proposal/transform tree) / 34 KE (Key Exchange — DH/ECDH public value) / 35 IDi (Identification - Initiator) / 36 IDr (Identification - Responder) / 37 CERT (Certificate) / 38 CERTREQ (Certificate Request) / 39 AUTH (Authentication — signature/PSK proof) / 40 Ni or Nr (Nonce) / 41 N (Notify — error / status / capability) / 42 D (Delete — tear down SAs) / 43 V (Vendor ID — feature negotiation) / 44 TSi (Traffic Selector - Initiator) / 45 TSr (Traffic Selector - Responder) / 46 SK (Encrypted and Authenticated — wraps inner payloads from IKE_AUTH onwards) / 47 CP (Configuration — remote-access settings like IP allocation) / 48 EAP (Extensible Authentication Protocol).

  • **N (Notify) payload body** (Type 41; RFC 7296 §3.10): 1-byte Protocol ID (0 IKE / 2 AH / 3 ESP)

  • 1-byte SPI Size + 2-byte **Notify Message Type** resolved via a **~30-entry name table** covering the most common error / status codes: **Errors**: 1 UNSUPPORTED_CRITICAL_PAYLOAD / 4 INVALID_IKE_SPI / 5 INVALID_MAJOR_VERSION / 7 INVALID_SYNTAX / 9 INVALID_MESSAGE_ID / 11 INVALID_SPI / 14 NO_PROPOSAL_CHOSEN / 17 INVALID_KE_PAYLOAD / 24 AUTHENTICATION_FAILED / 34 SINGLE_PAIR_REQUIRED / 35 NO_ADDITIONAL_SAS / 36 INTERNAL_ADDRESS_FAILURE / 37 FAILED_CP_REQUIRED / 38 TS_UNACCEPTABLE / 39 INVALID_SELECTORS / 43 TEMPORARY_FAILURE / 44 CHILD_SA_NOT_FOUND. **Status**: 16384 INITIAL_CONTACT / 16385 SET_WINDOW_SIZE / 16386 ADDITIONAL_TS_POSSIBLE / 16387 IPCOMP_SUPPORTED / 16388 NAT_DETECTION_SOURCE_IP / 16389 NAT_DETECTION_DESTINATION_IP / 16390 COOKIE / 16391 USE_TRANSPORT_MODE / 16393 REKEY_SA / 16395 NON_FIRST_FRAGMENTS_ALSO / 16404 MOBIKE_SUPPORTED / 16407 NO_NATS_ALLOWED / 16408 AUTH_LIFETIME / 16431 SIGNATURE_HASH_ALGORITHMS.

  • **SK (Encrypted) payload** (Type 46) — surfaced with the encrypted body as opaque hex pending the IKE-derived keys. The body wraps inner payloads (the Next Payload of the SK header names the type of the first inner payload).

What this package does NOT cover (deliberately out of scope)

  • UDP framing — feed IKE bytes after the UDP header strip. IKE runs on UDP destination port 500 (or 4500 with a 4-byte all-zeros marker prefix when behind NAT, per RFC 3948 NAT-T).

  • SA proposal/transform tree deep dissection — the SA payload (Type 33) contains a nested list of Proposals + Transforms (encryption / integrity / PRF / DH algorithms negotiated); surfaced as opaque hex; would warrant a separate iteration.

  • KE / Ni / Nr / IDi / IDr / AUTH / CERT body dissection — surfaced as opaque hex; per-body decoders are future work.

  • SK payload decryption — requires the SK_e/SK_a keys derived from the IKE_SA_INIT KE + Nonce exchange; surfaced as opaque hex with an encryption note.

  • IKEv1 (RFC 2409) — different header (8-byte SPIs

  • Initiator Cookie / Responder Cookie naming + Exchange Type code 1-5 mapping to Identity Protection / Aggressive / Authentication Only / Informational / Quick Mode); long-deprecated but still seen in legacy deployments; would warrant its own Spec.

  • NAT-T marker stripping — when the 4-byte all-zeros marker is present (UDP port 4500), the operator must strip it before feeding bytes into this decoder. ESP-in-UDP (RFC 3948) doesn't have the all-zeros marker, so the demux is unambiguous.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DecodeOpts

type DecodeOpts struct {
	// MaxPayloadBodyBytes caps the per-payload body hex
	// preview (default 256). Zero shows the full body.
	MaxPayloadBodyBytes int
}

DecodeOpts tunes the walker for output size.

func DefaultDecodeOpts

func DefaultDecodeOpts() DecodeOpts

DefaultDecodeOpts returns a 256-byte body preview cap.

type NotifyBody

type NotifyBody struct {
	ProtocolID          int    `json:"protocol_id"`
	ProtocolIDName      string `json:"protocol_id_name"`
	SPISize             int    `json:"spi_size"`
	NotifyMessageType   int    `json:"notify_message_type"`
	NotifyMessageName   string `json:"notify_message_name"`
	NotifyMessageClass  string `json:"notify_message_class"`
	SPIHex              string `json:"spi_hex,omitempty"`
	NotificationDataHex string `json:"notification_data_hex,omitempty"`
}

NotifyBody is the decoded body of an N (Notify) payload.

type Payload

type Payload struct {
	Type     int    `json:"type"`
	TypeName string `json:"type_name"`
	NextType int    `json:"next_type"`
	Critical bool   `json:"critical"`
	Length   int    `json:"length"`
	BodyHex  string `json:"body_hex,omitempty"`

	// Decoded forms populated for known payload types.
	Notify    *NotifyBody `json:"notify,omitempty"`
	Encrypted *SKBody     `json:"encrypted,omitempty"`
}

Payload is one (Next Payload, Critical, Length, Body) record from the payload walker.

type Result

type Result struct {
	InitiatorSPI     uint64    `json:"initiator_spi"`
	InitiatorSPIHex  string    `json:"initiator_spi_hex"`
	ResponderSPI     uint64    `json:"responder_spi"`
	ResponderSPIHex  string    `json:"responder_spi_hex"`
	FirstPayloadType int       `json:"first_payload_type"`
	FirstPayloadName string    `json:"first_payload_name"`
	VersionMajor     int       `json:"version_major"`
	VersionMinor     int       `json:"version_minor"`
	ExchangeType     int       `json:"exchange_type"`
	ExchangeTypeName string    `json:"exchange_type_name"`
	FlagResponse     bool      `json:"flag_response"`
	FlagVersion      bool      `json:"flag_version"`
	FlagInitiator    bool      `json:"flag_initiator"`
	MessageID        uint32    `json:"message_id"`
	Length           uint32    `json:"length"`
	Payloads         []Payload `json:"payloads"`
	TotalBytes       int       `json:"total_bytes"`
	Notes            []string  `json:"notes,omitempty"`
}

Result is the top-level decoded view of an IKEv2 message.

func Decode

func Decode(hexStr string, opts DecodeOpts) (*Result, error)

Decode parses a single IKEv2 message from hex.

type SKBody

type SKBody struct {
	EncryptedBytes int    `json:"encrypted_bytes"`
	EncryptedHex   string `json:"encrypted_hex,omitempty"`
	Note           string `json:"note"`
}

SKBody is the decoded view of an SK (Encrypted) payload.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL