"""
Creates a compressed PCAP with KEXINIT packets for server and client with non-matching
algorithms. The resulted in quadratic runtime in a) the parser and b) script land to
find a match. Also includes lists larger than 500 entries for the other algorithms
(hostkey, encryption, compression, mac) and languages.

Generated by GPT 5.5 (CODEX) and updated to use different lengths for the
different namelists, added languages and use gzip compression by default
for the pcap.
"""

import gzip
from pathlib import Path

from scapy.all import IP, TCP, Raw, wrpcap


def pkt(src, dst, sport, dport, seq, ack, flags, payload=b""):
    p = IP(src=src, dst=dst) / TCP(
        sport=sport, dport=dport, seq=seq, ack=ack, flags=flags
    )
    if payload:
        p = p / Raw(payload)
    return p


def namelist(prefix, n):
    return ",".join(f"{prefix}{i}" for i in range(n)).encode()


def kexinit(prefix, n):
    lists = [
        namelist(prefix + "k", n),
        namelist(prefix + "h", n + 10),
        namelist(prefix + "ecs", n + 20),
        namelist(prefix + "esc", n + 30),
        namelist(prefix + "mcs", n + 40),
        namelist(prefix + "msc", n + 50),
        namelist(prefix + "ccs", n + 60),
        namelist(prefix + "csc", n + 70),
        namelist(prefix + "lcs", n + 80),
        namelist(prefix + "lsc", n + 90),
        b"",
        b"",
    ]
    payload = (
        bytes([20])
        + b"0123456789abcdef"
        + b"".join(len(x).to_bytes(4, "big") + x for x in lists)
        + b"\x00"
        + (0).to_bytes(4, "big")
    )
    pad_len = (8 - ((1 + len(payload)) % 8)) % 8
    if pad_len < 4:
        pad_len += 8
    pad = b"\x00" * pad_len
    packet_length = 1 + len(payload) + len(pad)
    return packet_length.to_bytes(4, "big") + bytes([len(pad)]) + payload + pad


def main():
    n = 500
    cseq = 1000
    sseq = 5000
    cs = cseq + 1
    ss = sseq + 1
    pkts = [
        pkt("10.0.1.1", "10.0.1.2", 12345, 22, cseq, 0, "S"),
        pkt("10.0.1.2", "10.0.1.1", 22, 12345, sseq, cseq + 1, "SA"),
        pkt("10.0.1.1", "10.0.1.2", 12345, 22, cs, ss, "A"),
    ]

    for payload, orig in [
        (b"SSH-2.0-CodexClient\r\n", True),
        (b"SSH-2.0-CodexServer\r\n", False),
        (kexinit("a", n), True),
        (kexinit("b", n), False),
    ]:
        if orig:
            pkts.append(pkt("10.0.1.1", "10.0.1.2", 12345, 22, cs, ss, "PA", payload))
            cs += len(payload)
            pkts.append(pkt("10.0.1.2", "10.0.1.1", 22, 12345, ss, cs, "A"))
        else:
            pkts.append(pkt("10.0.1.2", "10.0.1.1", 22, 12345, ss, cs, "PA", payload))
            ss += len(payload)
            pkts.append(pkt("10.0.1.1", "10.0.1.2", 12345, 22, cs, ss, "A"))

    for i, p in enumerate(pkts):
        p.time = 1782914726.0 + i / 1000.0

    # Compress the pcap. wrpcap() supports gz=1, but that's not reproducible,
    # so pass a GzipFile instance with mtime=0 that makes it reproducible.
    with gzip.GzipFile(Path(__file__).with_suffix(".gz"), "wb", mtime=0) as f:
        wrpcap(f, pkts)


if __name__ == "__main__":
    main()
