From 166cf4ed0fb0cff4629b0dfc3b733d73d2fe4b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Mon, 17 Aug 2026 21:40:12 +0300 Subject: [PATCH] Decode KIc/KID algorithms unconditionally; expand packet-length labels --- frontend/index.html | 4 ++-- simtrace2_pysniff/server/decode.py | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index d9b418a..7833d04 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -664,7 +664,7 @@ function cmdRows(cmd) { const sec = t.secured; if (sec && !sec.raw) { - rows.push(['Secured packet', 'CPL ' + sec.cpl + ' · CHL ' + sec.chl]); + rows.push(['Secured packet', 'Command Packet Length ' + sec.cpl + ' · Command Header Length ' + sec.chl]); const s = sec.spi || {}; rows.push(['SPI', '0x' + (s.hex || '') + ' — ' + (s.counter || '') + (s.ciphering ? ', ciphering' : '') + ', ' + (s.rc_cc_ds || '') + ', ' + (s.por || '')]); @@ -679,7 +679,7 @@ function cmdRows(cmd) { const rp = t.response_packet; if (rp && !rp.raw) { - rows.push(['Response packet', 'RPL ' + rp.rpl + ' · RHL ' + rp.rhl]); + rows.push(['Response packet', 'Response Packet Length ' + rp.rpl + ' · Response Header Length ' + rp.rhl]); rows.push(['TAR', '0x' + rp.tar]); rows.push(['CNTR', '0x' + rp.cntr]); rows.push(['PCNTR', rp.pcntr]); diff --git a/simtrace2_pysniff/server/decode.py b/simtrace2_pysniff/server/decode.py index b86a138..c815053 100644 --- a/simtrace2_pysniff/server/decode.py +++ b/simtrace2_pysniff/server/decode.py @@ -1727,7 +1727,7 @@ _OTA_POR = {0: 'no PoR', 1: 'PoR required', 2: 'PoR only on error'} # TS 102 225 §5.1.2 / §5.1.3 — KIc / KID algorithms (low nibble) _KIC_ALGO = {0: 'implicit', 1: 'DES', 2: 'AES-CBC', 5: '3DES-CBC (2 keys)', 9: '3DES-CBC (3 keys)'} -_KID_CC_ALGO = {0: 'implicit', 1: 'DES', 5: '3DES-CBC', 2: 'AES-CMAC'} +_KID_CC_ALGO = {0: 'implicit', 1: 'DES', 5: '3DES-CBC (2 keys)', 9: '3DES-CBC (3 keys)', 2: 'AES-CMAC'} _KID_RC_ALGO = {0: 'implicit', 1: 'CRC16', 5: 'CRC32', 3: 'proprietary'} # TS 102 225 §5.2 Table 5 + TS 31.115 §7 — Response status codes @@ -1798,12 +1798,21 @@ def _decode_secured_packet(body): 'pcntr': pcntr, 'data': data.hex().upper(), } + kic_algo = _KIC_ALGO.get(kic & 0x0F, 'reserved') + if not (spi1 & 0x08): # SPI says no ciphering → KIc unused + kic_algo += ' (unused)' + result['kic'] = {'key': kic >> 4, 'algo': kic_algo} if rc_cc_ds_kind == 2: # CC - result['kid'] = {'key': kid >> 4, 'algo': _KID_CC_ALGO.get(kid & 0x0F, 'reserved')} + kid_algo = _KID_CC_ALGO.get(kid & 0x0F, 'reserved') elif rc_cc_ds_kind == 1: # RC - result['kid'] = {'key': kid >> 4, 'algo': _KID_RC_ALGO.get(kid & 0x0F, 'reserved')} - else: - result['kid'] = {'key': kid >> 4, 'algo': 'implicit'} + kid_algo = _KID_RC_ALGO.get(kid & 0x0F, 'reserved') + elif rc_cc_ds_kind == 3: # DS — no simple nibble table + kid_algo = 'DS' + else: # none — decode the nibble anyway (CC interpretation) + kid_algo = _KID_CC_ALGO.get(kid & 0x0F, 'reserved') + if rc_cc_ds_kind == 0: + kid_algo += ' (unused)' + result['kid'] = {'key': kid >> 4, 'algo': kid_algo} if rc_cc_ds: result['rc_cc_ds'] = rc_cc_ds.hex().upper() return result