Client-side SCP80 decryption: pure-JS 3DES/AES with user-supplied keys

Adds optional decryption of ciphered secured packets, entirely in the
browser — the key never leaves the frontend.

- decode.py: _decode_secured_packet exposes 'cipher_block' (the
  contiguous on-wire ciphered octets CNTR..end, ready for CBC) and
  raw kic/kid bytes for algorithm selection. Additive only.
- index.html: pure-JS DES/3DES core (FIPS 46-3 bit-array tables,
  parity ignored) + CBC; AES-CBC via native SubtleCrypto; both with
  zero IV per TS 102 225. decryptSecured() picks the algorithm from
  the KIc nibble (02 AES-CBC, 05 3DES-2K, 09 3DES-3K, 01 DES) with
  key-length validation.
- UI: ciphered packets show a key-hex input + Decrypt strip below the
  detail table; keys are memoized per key-set for the session in an
  in-memory OTA_KEYS map — never sent to the server, never persisted.
- Decrypted results cached by cipher_block (survive live-polling
  re-renders); plaintext rows rendered as CNTR/PCNTR/RC/Secured data
  (decrypted) alongside the ciphertext; wrong-key guard via the
  decrypted padding counter (PCNTR > remaining → "invalid padding").
- 3DES implementation validated byte-identical against openssl
  des-ede3-cbc (3-key, 2-key ×3 random vectors, single-key).

No CC verification (out of scope). Tests: +2 (cipher_block
contiguity, AES registry guard) — 350 total. Version 1.19.0,
SW cache simtrace-analyser-v27.
This commit is contained in:
catarrh committed 2026-08-24 21:12:24 +03:00
1 parent 840e233baf
commit d21997764f
7 files changed
+253 -5

No files matched your search

+6
View File
@@ -2335,6 +2335,12 @@ def _decode_secured_packet(body):
'cntr': cntr.hex().upper(),
'pcntr': pcntr,
'data': data.hex().upper(),
# Contiguous ciphered on-wire octets (CNTR ‖ PCNTR ‖ RC/CC/DS ‖
# secured data + padding) — the block a client-side decryptor
# feeds to 3DES/AES-CBC with a zero IV (TS 102 225 Table 2 n.1).
'cipher_block': body[10:].hex().upper(),
'kic_raw': kic,
'kid_raw': kid,
}
kic_algo = _KIC_ALGO.get(kic & 0x0F, 'reserved')
if not (spi1 & 0x04): # SPI says no ciphering → KIc unused