Files
KAT/docs/porsche_touareg.md
T
KaraZajac 48ee413c9b v1.2.0: Add 4 new protocols, fix 5 existing, port Kia V6 encoder
New protocols (from ProtoPirate):
- Mazda V0: 433MHz, pair-based decoding, XOR deobfuscation
- Mitsubishi V0: 868MHz, PWM, bit negation + XOR unscrambling
- Porsche Touareg: 433/868MHz, sync preamble, 24-bit rotate cipher
- Fiat V1 (Magneti Marelli BSI): 433MHz, auto-detected timing variants

Protocol fixes aligned with ProtoPirate reference:
- Kia V1: Fix Manchester level mapping (inverted convention), off-by-one
  bit count, CRC4 simplified to 7 bytes + offset 1
- Kia V2: Fix CRC byte layout (was double-counting nibbles), off-by-one
  bit count, preamble short-HIGH handling
- Fiat V0: Fix endbyte transform (remove (<<1)|1), standard Manchester
  encoder (was differential), 7 btn bits (was 6), gap path fallback
- PSA: Fix modified TEA (XTEA-like dynamic key selection), XOR decrypt
  byte mapping, critical key2_low construction bug, encoder polarity and
  preamble, add key1_high nibble validation, dual preamble patterns
- Ford V0: Add calculate_checksum (sums all serial+count bytes) for encoder

Kia V6 encoder ported:
- Forward AES-128 (SubBytes, ShiftRows, MixColumns, encrypt)
- encrypt_payload: build plaintext, AES encrypt, pack into 3 parts
- Two-pass Manchester upload (640 + 38 preamble pairs)
- fx_field extraction stored in DecodedSignal.extra for encode roundtrip

Updated README, protocol docs, and version bump to 1.2.0.
2026-03-22 12:05:01 -04:00

2.4 KiB

layout
layout
default

Porsche Touareg Protocol

Rust module: src/protocols/porsche_touareg.rs Reference: REFERENCES/ProtoPirate/protocols/porsche_touareg.c

Overview

Porsche Touareg uses PWM encoding with very long timing (1680/3370 us). 64-bit frame with a sync preamble (at least 15 sync pulses at 3370 us). Counter is recovered via brute-force using a 24-bit rotation cipher. Originally designed for the Porsche Cayenne.

Timing

Parameter Value Notes
Short 1680 us +/-500 us
Long 3370 us +/-500 us
Sync 3370 us Same as long
Gap 5930 us +/-500 us
Sync min 15 pulses
Min bits 64

PWM Bit Encoding

Pair (LOW, HIGH) Bit
Short LOW + Long HIGH 0
Long LOW + Short HIGH 1

Frame Layout (64 bits = 8 bytes)

Byte Content
pkt[0] (button << 4) | (frame_type & 0x07)
pkt[1] serial bits [23:16]
pkt[2] serial bits [15:8]
pkt[3] serial bits [7:0]
pkt[4..7] Encrypted counter/rolling code
  • Serial: 24 bits from pkt[1..3]
  • Button: 4 bits (pkt[0] >> 4)
  • Frame type: 3 bits (pkt[0] & 0x07): 0x02=First, 0x01=Cont, 0x04=Final

Counter Recovery (Brute-Force)

Counter is not in plaintext. The decoder tries counter values 1-256, calling compute_frame() for each, and checks if computed bytes [4..7] match received bytes [4..7].

Compute Frame Algorithm (24-bit Rotate Cipher)

  1. Initialize 24-bit rotate register from serial bytes: r_h=b3, r_m=b1, r_l=b2.
  2. ROTATE24: circular left shift across 3 bytes (h<-m, m<-l, l<-h).
  3. Rotate 4 times + counter_low more times.
  4. Compute encrypted bytes a9a/a9b/a9c from rotated values XOR'd with inverted counter bits.
  5. Assemble pkt[4..7] using bitfield packing.

Decoder Steps

  1. Reset -- Wait for LOW pulse matching sync (3370 us).
  2. Sync -- Count sync pulses (both HIGH and LOW). When count >= 15 and gap detected (5930 us), transition to GapHigh or GapLow.
  3. GapHigh -- Expect HIGH gap (5930 us); init data on match.
  4. GapLow -- Expect LOW gap (5930 us); init data on match.
  5. Data -- Decode bit pairs (LOW saved, HIGH completes). At 64 bits, parse data and brute-force counter.

Encoder

Not supported (decode-only).

Frequencies

433.92 MHz, 868.35 MHz.