Files
pm3py/pm3py/core/protocol.py
michael b87f12253d feat(hw): repoint Cmd.LED_CONTROL to 0x011B (firmware LED port), hw.led now works
The firmware fork now provides CMD_LED_CONTROL at 0x011B (payload_led_control_t). hw.led already packs the matching <BBBHH> struct + action codes, so repointing the id makes it functional. Adds Cmd.SET_HF_FIELD_TIMEOUT (0x011A, upstream's use of that slot). README caveat updated: hw.led works with the fork, no-op on stock.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 02:04:37 -07:00

300 lines
7.5 KiB
Python

"""Proxmark3 NG wire protocol constants and CRC."""
import struct
from enum import IntEnum
# --- Magic values ---
CMD_PREAMBLE_MAGIC = 0x61334d50 # "PM3a"
RESP_PREAMBLE_MAGIC = 0x62334d50 # "PM3b"
CMD_POSTAMBLE_NOCRC = 0x3361 # "a3"
RESP_POSTAMBLE_NOCRC = 0x3362 # "b3"
PM3_CMD_DATA_SIZE = 512
# --- Frame formats (little-endian) ---
CMD_PREAMBLE_FMT = "<IHH" # magic(4) + length_ng(2) + cmd(2) = 8 bytes
CMD_PREAMBLE_SIZE = 8
CMD_POSTAMBLE_FMT = "<H" # crc(2) = 2 bytes
CMD_POSTAMBLE_SIZE = 2
RESP_PREAMBLE_FMT = "<IHbbH" # magic(4) + length_ng(2) + status(1) + reason(1) + cmd(2) = 10 bytes
RESP_PREAMBLE_SIZE = 10
RESP_POSTAMBLE_FMT = "<H"
RESP_POSTAMBLE_SIZE = 2
# --- MIX frame: 3x uint64 args at start of payload ---
MIX_ARGS_FMT = "<QQQ"
MIX_ARGS_SIZE = 24
# --- CRC-16/A (ISO 14443-3) ---
_CRC_TABLE: list[int] = []
def _reflect8(b: int) -> int:
r = 0
for i in range(8):
if b & (1 << i):
r |= 1 << (7 - i)
return r
def _reflect16(v: int) -> int:
r = 0
for i in range(16):
if v & (1 << i):
r |= 1 << (15 - i)
return r
def _init_crc_table() -> None:
global _CRC_TABLE
if _CRC_TABLE:
return
poly = 0x1021
_CRC_TABLE = [0] * 256
for i in range(256):
c = _reflect8(i) << 8
crc = 0
for _ in range(8):
if (crc ^ c) & 0x8000:
crc = ((crc << 1) ^ poly) & 0xFFFF
else:
crc = (crc << 1) & 0xFFFF
c = (c << 1) & 0xFFFF
_CRC_TABLE[i] = _reflect16(crc)
def crc16_a(data: bytes) -> int:
"""CRC-16/A: poly=0x1021, init=0xC6C6, refin=true, refout=true, xorout=0x0000."""
_init_crc_table()
crc = _reflect16(0xC6C6)
for b in data:
crc = ((crc >> 8) ^ _CRC_TABLE[(crc & 0xFF) ^ b]) & 0xFFFF
return crc
def crc15(data: bytes) -> int:
"""ISO 15693 / NFC Type 5 CRC (CRC-16/X-25): poly=0x8408 (reflected), init=0xFFFF,
refin/refout=true, xorout=0xFFFF. Check value crc15(b"123456789") == 0x906E."""
crc = 0xFFFF
for b in data:
crc ^= b
for _ in range(8):
crc = (crc >> 1) ^ 0x8408 if (crc & 1) else (crc >> 1)
return (~crc) & 0xFFFF
def crc15_bytes(data: bytes) -> bytes:
"""ISO 15693 CRC as appended on the wire (LSB byte first)."""
c = crc15(data)
return bytes([c & 0xFF, (c >> 8) & 0xFF])
# --- Error codes ---
class PM3Status(IntEnum):
SUCCESS = 0
EUNDEF = -1
EINVARG = -2
EDEVNOTSUPP = -3
ETIMEOUT = -4
EOPABORTED = -5
ENOTIMPL = -6
ERFTRANS = -7
EIO = -8
EOVFLOW = -9
ESOFT = -10
EFLASH = -11
EMALLOC = -12
EFILE = -13
ENOTTY = -14
EINIT = -15
EWRONGANSWER = -16
EOUTOFBOUND = -17
ECARDEXCHANGE = -18
EAPDU_ENCODEFAIL = -19
EAPDU_FAIL = -20
EFAILED = -21
EPARTIAL = -22
ETEAROFF = -23
ECRC = -24
ESTATIC_NONCE = -25
ENOPACS = -26
ELENGTH = -27
ENOKEY = -28
ECRYPTO = -29
ENOFILE = -30
ENODATA = -98
EFATAL = -99
# --- Command IDs ---
class Cmd(IntEnum):
# Bootloader
DEVICE_INFO = 0x0000
FINISH_WRITE = 0x0003
HARDWARE_RESET = 0x0004
START_FLASH = 0x0005
CHIP_INFO = 0x0006
BL_VERSION = 0x0007
# Debug
DEBUG_PRINT_STRING = 0x0100
DEBUG_PRINT_INTEGERS = 0x0101
DEBUG_PRINT_BYTES = 0x0102
# System
NACK = 0x00FE
ACK = 0x00FF
BUFF_CLEAR = 0x0105
READ_MEM = 0x0106
VERSION = 0x0107
STATUS = 0x0108
PING = 0x0109
READ_MEM_DOWNLOAD = 0x010A
READ_MEM_DOWNLOADED = 0x010B
DOWNLOAD_EML_BIGBUF = 0x0110
DOWNLOADED_EML_BIGBUF = 0x0111
CAPABILITIES = 0x0112
QUIT_SESSION = 0x0113
SET_DBGMODE = 0x0114
STANDALONE = 0x0115
WTX = 0x0116
TIA = 0x0117
BREAK_LOOP = 0x0118
SET_TEAROFF = 0x0119
SET_HF_FIELD_TIMEOUT = 0x011A
LED_CONTROL = 0x011B # our firmware fork (0x011A is upstream's SET_HF_FIELD_TIMEOUT)
GET_DBGMODE = 0x0120
# FPGA
FPGA_MAJOR_MODE_OFF = 0x0500
# LF
LF_TI_READ = 0x0202
LF_TI_WRITE = 0x0203
LF_ACQ_RAW_ADC = 0x0205
LF_MOD_THEN_ACQ_RAW_ADC = 0x0206
DOWNLOAD_BIGBUF = 0x0207
DOWNLOADED_BIGBUF = 0x0208
LF_UPLOAD_SIM_SAMPLES = 0x0209
LF_SIMULATE = 0x020A
LF_HID_WATCH = 0x020B
LF_HID_SIMULATE = 0x020C
LF_SET_DIVISOR = 0x020D
LF_SIMULATE_BIDIR = 0x020E
SET_ADC_MUX = 0x020F
LF_HID_CLONE = 0x0210
LF_EM410X_CLONE = 0x0211
LF_T55XX_READBL = 0x0214
LF_T55XX_WRITEBL = 0x0215
LF_T55XX_RESET_READ = 0x0216
LF_PCF7931_READ = 0x0217
LF_EM4X_READWORD = 0x0218
LF_EM4X_WRITEWORD = 0x0219
LF_IO_WATCH = 0x021A
LF_EM4X_PROTECTWORD = 0x021B
LF_EM410X_WATCH = 0x021C
LF_SAMPLING_SET_CONFIG = 0x021D
LF_FSK_SIMULATE = 0x021E
LF_ASK_SIMULATE = 0x021F
LF_PSK_SIMULATE = 0x0220
LF_AWID_WATCH = 0x0221
LF_VIKING_CLONE = 0x0222
LF_PCF7931_WRITE = 0x0223
LF_T55XX_WAKEUP = 0x0224
LF_COTAG_READ = 0x0225
LF_T55XX_SET_CONFIG = 0x0226
LF_SAMPLING_PRINT_CONFIG = 0x0227
LF_SAMPLING_GET_CONFIG = 0x0228
LF_EM4X_LOGIN = 0x0229
LF_EM4X_BF = 0x022A
LF_T55XX_CHK_PWDS = 0x0230
LF_T55XX_DANGERRAW = 0x0231
LF_NRZ_SIMULATE = 0x0232
LF_SNIFF_RAW_ADC = 0x0360
LF_HITAG_SNIFF = 0x0370
# HF General
HF_ACQ_RAW_ADC = 0x0301
HF_ISO15693_ACQ_RAW_ADC = 0x0300
HF_ISO15693_READER = 0x0310
HF_ISO15693_SIMULATE = 0x0311
HF_ISO15693_SNIFF = 0x0312
HF_ISO15693_COMMAND = 0x0313
HF_ISO15693_FINDAFI = 0x0315
HF_ISO15693_CSETUID = 0x0316
HF_ISO15693_EML_SETMEM = 0x0331
HF_SNIFF_STREAM = 0x0337
HF_SNIFF_STATUS = 0x0338
# Sim table commands (firmware response table)
SIM_TABLE_UPLOAD = 0x0900
SIM_TABLE_CLEAR = 0x0901
SIM_TABLE_UPDATE = 0x0902
HF_ISO14443A_SNIFF = 0x0383
HF_ISO14443A_SIMULATE = 0x0384
HF_ISO14443A_READER = 0x0385
HF_ISO14443A_GET_CONFIG = 0x03B1
HF_ISO14443A_SET_CONFIG = 0x03B2
HF_ISO14443B_COMMAND = 0x0305
HF_ISO14443B_SIMULATE = 0x0381
HF_ISO14443B_SNIFF = 0x0382
# Tuning
MEASURE_ANTENNA_TUNING = 0x0400
MEASURE_ANTENNA_TUNING_HF = 0x0401
MEASURE_ANTENNA_TUNING_LF = 0x0402
LISTEN_READER_FIELD = 0x0420
HF_DROPFIELD = 0x0430
HF_DECAY = 0x0440
# MIFARE Classic
HF_MIFARE_EML_MEMCLR = 0x0601
HF_MIFARE_EML_MEMSET = 0x0602
HF_MIFARE_EML_MEMGET = 0x0603
HF_MIFARE_SIMULATE = 0x0610
HF_MIFARE_READER = 0x0611
HF_MIFARE_NESTED = 0x0612
HF_MIFARE_ACQ_ENCRYPTED_NONCES = 0x0613
HF_MIFARE_ACQ_NONCES = 0x0614
HF_MIFARE_STATIC_NESTED = 0x0615
HF_MIFARE_READBL = 0x0620
HF_MIFARE_READSC = 0x0621
HF_MIFARE_WRITEBL = 0x0622
HF_MIFARE_CHKKEYS = 0x0623
HF_MIFARE_SETMOD = 0x0624
HF_MIFARE_CHKKEYS_FAST = 0x0625
HF_MIFARE_CHKKEYS_FILE = 0x0626
HF_MIFARE_VALUE = 0x0627
HF_MIFARE_READBL_EX = 0x0628
HF_MIFARE_WRITEBL_EX = 0x0629
HF_MIFARE_SNIFF = 0x0630
HF_MIFARE_MFKEY = 0x0631
HF_MIFARE_PERSONALIZE_UID = 0x0632
HF_MIFARE_CSETBL = 0x0605
HF_MIFARE_CGETBL = 0x0606
HF_MIFARE_CIDENT = 0x0607
# MIFARE Ultralight
HF_MIFAREU_READBL = 0x0720
HF_MIFAREU_READCARD = 0x0721
HF_MIFAREU_WRITEBL = 0x0722
HF_MIFARE_NACK_DETECT = 0x0730
# HF Sniff/Plot
HF_SNIFF = 0x0800
HF_PLOT = 0x0801
FPGAMEM_DOWNLOAD = 0x0802
FPGAMEM_DOWNLOADED = 0x0803
UNKNOWN = 0xFFFF
# Sniff streaming flags
SNIFF_FLAG_STREAMING = 0x01
SNIFF_FLAG_BUTTON_TOGGLE = 0x02
# Sniff states
SNIFF_STATE_STARTED = 0
SNIFF_STATE_PAUSED = 1
SNIFF_STATE_RESUMED = 2
SNIFF_STATE_STOPPED = 3