"""NXP ICODE/NTAG5 platform — shared NXP custom commands.""" from __future__ import annotations import os import struct from .frame import RFFrame from .trace_fmt import decode_15693_nxp from .type5 import NfcType5Tag # NXP manufacturer code NXP_MFG = 0x04 # NXP custom commands per SL2S2602 datasheet CMD_INVENTORY_READ = 0xA0 CMD_FAST_INVENTORY_READ = 0xA1 CMD_SET_EAS = 0xA2 CMD_RESET_EAS = 0xA3 CMD_LOCK_EAS = 0xA4 CMD_EAS_ALARM = 0xA5 CMD_PASSWORD_PROTECT_EAS_AFI = 0xA6 CMD_WRITE_EAS_ID = 0xA7 CMD_GET_NXP_SYSTEM_INFO = 0xAB CMD_GET_RANDOM = 0xB2 CMD_SET_PASSWORD = 0xB3 CMD_WRITE_PASSWORD = 0xB4 CMD_LOCK_PASSWORD = 0xB5 CMD_PROTECT_PAGE = 0xB6 CMD_LOCK_PAGE_PROTECTION = 0xB7 CMD_DESTROY = 0xB9 CMD_ENABLE_PRIVACY = 0xBA CMD_64BIT_PASSWORD_PROTECTION = 0xBB CMD_STAY_QUIET_PERSISTENT = 0xBC CMD_READ_SIGNATURE = 0xBD CMD_READ_CONFIG = 0xC0 CMD_WRITE_CONFIG = 0xC1 CMD_READ_TT = 0xC4 class NxpIcodeTag(NfcType5Tag): """NXP ICODE/NTAG5 shared platform features. Provides: originality signature, NXP system info, GET_RANDOM, SET_PASSWORD. Base for ICODE SLIX, SLIX2, DNA, NTAG 5 Link, etc. """ _uid_prefix = b"\xE0\x04" # E0 + NXP manufacturer code def __init__(self, uid: bytes, signature: bytes | None = None, **kwargs): super().__init__(uid=uid, **kwargs) # 32-byte ECC originality signature (from factory, read-only) self._signature = signature or bytes(32) def decode_trace(self, direction: int, payload: bytes) -> str | None: return decode_15693_nxp(direction, payload) or super().decode_trace(direction, payload) def _handle_custom_command(self, cmd: int, frame: RFFrame) -> RFFrame | None: """Handle NXP custom commands (0xA0-0xDF).""" # Verify NXP manufacturer code if len(frame.data) < 3 or frame.data[2] != NXP_MFG: return None match cmd: case 0xB2: # GET RANDOM NUMBER return self._handle_get_random(frame) case 0xB3: # SET PASSWORD return self._nxp_handle_set_password(frame) return None def _handle_get_nxp_system_info(self, frame: RFFrame) -> RFFrame | None: """GET NXP SYSTEM INFO (0xAB): returns PP byte, PP conditions, lock bits, feature flags.""" # Base implementation — subclasses override with actual PP/feature data # Response: flags(1) + PP(1) + PP_cond(1) + lock_bits(1) + feature_flags(4) return RFFrame.from_bytes(bytes([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) def _handle_get_random(self, frame: RFFrame) -> RFFrame | None: random_bytes = os.urandom(2) return RFFrame.from_bytes(bytes([0x00]) + random_bytes) def _handle_read_signature(self, frame: RFFrame) -> RFFrame | None: """READ SIGNATURE (0xBD): returns 32-byte ECC originality signature.""" return RFFrame.from_bytes(bytes([0x00]) + self._signature) def _nxp_handle_set_password(self, frame: RFFrame) -> RFFrame | None: """Base SET_PASSWORD handler. Override in subclasses for specific password types.""" return None