|
|
@@ -0,0 +1,69 @@
|
|
|
+"""Verified six-bit encoding used for the CQ2 TCP wire header.
|
|
|
+
|
|
|
+The table is the first 256 bytes of the archived client extraction
|
|
|
+``Encode6BitBuf_替换表.bin`` (SHA-256:
|
|
|
+bd8e0d6b48cff81a2e25e497a86e5e5ef33fedab7cb4af6a1e0db05ddd59fe1e).
|
|
|
+It is embedded so the runtime never depends on reverse-engineering artifacts.
|
|
|
+"""
|
|
|
+from __future__ import annotations
|
|
|
+
|
|
|
+
|
|
|
+ENC_TABLE = bytes.fromhex(
|
|
|
+ "8c870d85d46463e5ba7eb8689d9ff5bca0e33a2219213978ee27361574c797c9"
|
|
|
+ "cee27b4c98a1c25941c01e2e95ebde691d5b53daf40a4fbbb724330fc8842989"
|
|
|
+ "3c1c0849c6fecc233ee14e8b13e71a5dcfb1478fd8724b936e734d94dd8214a7"
|
|
|
+ "03f9f1c58d792ac4dc605fd762b5e9b3b612a832d9c36a754aa20c26915aad6d"
|
|
|
+ "4410b4461b668120fd7f88259c71d3e680e4fa429b3701fcdb456bfb56f0af9a"
|
|
|
+ "bfabd6cd02f27caab292ff572f86a67d351734d50e65090528ca48318e2ddf52"
|
|
|
+ "f61fa450764018048a162bae433fd0cb6c5554969930675e2cace07ae85890be"
|
|
|
+ "a56fb070ec615c063b77c107eaa9f811bdf300ed83ef3da3519e38f70bb9d2d1"
|
|
|
+)
|
|
|
+
|
|
|
+_inverse = bytearray(256)
|
|
|
+for _plain, _encoded in enumerate(ENC_TABLE):
|
|
|
+ _inverse[_encoded] = _plain
|
|
|
+INV_TABLE = bytes(_inverse)
|
|
|
+
|
|
|
+
|
|
|
+def encode6(src: bytes) -> bytes:
|
|
|
+ """Encode bytes into the client's printable 6-bit alphabet."""
|
|
|
+ dst = bytearray()
|
|
|
+ accumulator = 0
|
|
|
+ pending_bits = 0
|
|
|
+ for byte in src:
|
|
|
+ substituted = ENC_TABLE[byte] ^ 9
|
|
|
+ next_pending_bits = pending_bits + 2
|
|
|
+ accumulator |= substituted >> next_pending_bits
|
|
|
+ dst.append((accumulator & 0x3F) + 0x3C)
|
|
|
+ accumulator = (substituted << ((6 - pending_bits) & 0xFF)) >> 2 & 0x3F
|
|
|
+ if pending_bits >= 4:
|
|
|
+ dst.append(accumulator + 0x3C)
|
|
|
+ accumulator = 0
|
|
|
+ pending_bits = 0
|
|
|
+ else:
|
|
|
+ pending_bits = next_pending_bits
|
|
|
+ if pending_bits:
|
|
|
+ dst.append(accumulator + 0x3C)
|
|
|
+ return bytes(dst)
|
|
|
+
|
|
|
+
|
|
|
+def decode6(data: bytes, *, expected_size: int | None = None) -> bytes:
|
|
|
+ """Decode a printable 6-bit client header, validating its wire alphabet."""
|
|
|
+ bits = 0
|
|
|
+ bit_count = 0
|
|
|
+ substituted = bytearray()
|
|
|
+ for character in data:
|
|
|
+ value = character - 0x3C
|
|
|
+ if not 0 <= value <= 0x3F:
|
|
|
+ raise ValueError(f"byte outside 6-bit wire range: 0x{character:02x}")
|
|
|
+ bits = (bits << 6) | value
|
|
|
+ bit_count += 6
|
|
|
+ while bit_count >= 8:
|
|
|
+ bit_count -= 8
|
|
|
+ substituted.append((bits >> bit_count) & 0xFF)
|
|
|
+ decoded = bytes(INV_TABLE[byte ^ 9] for byte in substituted)
|
|
|
+ if expected_size is not None and len(decoded) != expected_size:
|
|
|
+ raise ValueError(
|
|
|
+ f"decoded header size mismatch: expected {expected_size}, got {len(decoded)}"
|
|
|
+ )
|
|
|
+ return decoded
|