# Accela Signal -- Solution ## Overview A LoRa-like Chirp Spread Spectrum (CSS) IQ stream containing two types of frames: beacon (cleartext) and data (XOR-encrypted flag). Players must implement CSS demodulation from scratch to decode the frames. ## Steps ### 1. Capture IQ Stream Connect to TCP port 9002. A text banner appears first, followed by raw IQ data. ```bash nc HOST 9002 > capture.raw # Or use the solve script ``` The banner tells you: `IQ baseband, 8000 sps, int16 LE interleaved`. ### 2. Analyze the Signal Open the IQ data in a spectrogram tool (e.g., inspectrum, Python matplotlib, or GNU Radio). You'll see: - Characteristic **chirp** patterns: frequency sweeps from low to high - Repeating preambles (identical chirps) - Gaps of noise between transmissions This is **Chirp Spread Spectrum (CSS)**, the modulation used by LoRa. ### 3. Determine Parameters - Each chirp spans 128 samples → **N = 128** - Since N = 2^SF → **SF = 7** (spreading factor) - Bandwidth = sample rate = 8000 Hz (baseband at Nyquist) - 7 bits per symbol ### 4. Implement Dechirping The key to CSS demodulation is **dechirping**: 1. Generate the base upchirp (symbol 0): ``` x0[n] = exp(j * π * n²/N) for n = 0..127 ``` 2. To decode a received chirp, multiply by the **conjugate** of the base chirp: ``` dechirped[n] = received[n] * conj(x0[n]) ``` 3. Take the **DFT/FFT** of the dechirped signal. The peak bin = symbol value. ### 5. Detect Frames Frame structure: ``` [Preamble: 8× symbol 0] [Sync: 2× downchirp] [Header: 1 symbol] [Payload: L symbols] ``` - **Preamble**: 8 consecutive chirps all decoding to symbol 0 - **Sync**: 2 downchirps (conjugate of upchirps) - **Header**: 1 symbol = payload length in bytes (Gray-coded) - **Payload**: L symbols encoding the data bytes ### 6. Gray Decoding Symbol values are **Gray-coded** (like real LoRa). After finding the FFT peak bin, apply inverse Gray code: ```python def gray_decode(val): mask = val while mask: mask >>= 1 val ^= mask return val ``` ### 7. Symbol-to-Byte Unpacking Each symbol carries 7 bits (SF=7). Concatenate all bits from decoded symbols, then group into 8-bit bytes. ### 8. Parse Frame Payload Payload format: `[type:1] [data:L] [crc16:2]` - Type 0x01 = beacon (ASCII text, for verification) - Type 0x02 = data (XOR-encrypted flag) - CRC-16 CCITT validates the payload ### 9. Decrypt Flag The data frame's content is XOR'd with the repeating key `"L41N"` (4 bytes). ```python xor_key = b"L41N" flag = bytes(b ^ xor_key[i % 4] for i, b in enumerate(encrypted_data)) ``` ## Key Insights - CSS/LoRa modulation encodes data as cyclic frequency shifts of a chirp signal - The dechirp + FFT technique converts the frequency-domain problem into a simple peak detection - Gray coding ensures that adjacent symbols (close FFT bins) differ by only 1 bit, reducing errors - The 7-bit symbol → 8-bit byte packing is standard for non-byte-aligned symbol sizes - The banner hints at CSS ("Chirp Spread Spectrum detected") to point players in the right direction ## Flag `ESPILON{4cc3l4_ch1rp_spr34d_w1r3d}` ## Author Eun0us