refactor: remove all backward-compat shims from sim/

Deletes 24 shim files from sim/. All test imports now point directly
to canonical transponders/ and trace/ paths. sim/ contains only
infrastructure (15 files): frame, memory, transponder ABC, reader ABC,
medium, sim_session, table_compiler, replay, relay, fuzzer, pm3medium,
mcu_bridge, mcu_protocol, dual_session, __init__.

751 tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
michael
2026-03-18 20:56:40 -07:00
parent 8e8b945246
commit c1ab980036
48 changed files with 256 additions and 304 deletions

View File

@@ -5,7 +5,7 @@ from bitarray import bitarray
from pm3py.sim.frame import RFFrame
from pm3py.sim.medium import SoftwareMedium
from pm3py.sim.iso14443a import (
from pm3py.transponders.hf.iso14443a.base import (
Tag14443A, Tag14443A_3, Tag14443A_4, Reader14443A,
State14443A, REQA, WUPA, HLTA, CL1, CL2, CL3,
)

View File

@@ -4,7 +4,7 @@ import pytest
from pm3py.sim.frame import RFFrame
from pm3py.sim.medium import SoftwareMedium
from pm3py.sim.iso15693 import Tag15693, Reader15693, State15693
from pm3py.transponders.hf.iso15693.base import Tag15693, Reader15693, State15693
def run(coro):

View File

@@ -4,7 +4,7 @@ import pytest
from pm3py.sim.frame import RFFrame
from pm3py.sim.medium import SoftwareMedium
from pm3py.sim.iso14443a import Tag14443A_3, Reader14443A
from pm3py.transponders.hf.iso14443a.base import Tag14443A_3, Reader14443A
from pm3py.sim.fuzzer import MutationFuzzer, GrammarFuzzer
from pm3py.sim.relay import RelayTransponder, MitMProxy
from pm3py.sim.replay import TraceRecorder, TraceReplayer, TraceEntry

View File

@@ -15,8 +15,8 @@ def run(coro):
class TestTam1:
def test_challenge_readbuffer(self):
"""Full TAM1 flow: CHALLENGE computes TResponse, READBUFFER returns it."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
key = b"\xAA" * 16
tag = IcodeDnaTag(aes_keys=[key, None, None, None])
@@ -50,8 +50,8 @@ class TestTam1:
def test_challenge_key1(self):
"""TAM1 with key slot 1."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
key = b"\xCC" * 16
tag = IcodeDnaTag(aes_keys=[None, key, None, None])
@@ -75,7 +75,7 @@ class TestTam1:
def test_challenge_inactive_key_silent(self):
"""CHALLENGE with inactive key: tag stays silent, READBUFFER returns nothing."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag(aes_keys=[b"\xBB" * 16, None, None, None])
# Key header NOT active (default 0x81)
@@ -92,7 +92,7 @@ class TestTam1:
def test_readbuffer_without_challenge(self):
"""READBUFFER without prior CHALLENGE returns nothing."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
run(tag.power_on())
@@ -103,8 +103,8 @@ class TestTam1:
def test_readbuffer_one_shot(self):
"""TResponse is cleared after first READBUFFER (one-shot)."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
key = b"\xDD" * 16
tag = IcodeDnaTag(aes_keys=[key, None, None, None])
@@ -126,8 +126,8 @@ class TestTam1:
def test_challenge_no_key_in_slot(self):
"""CHALLENGE with None key slot stays silent."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
tag = IcodeDnaTag(aes_keys=[None, None, None, None])
tag._key_headers[0] = KEY_HEADER_ACTIVE_LOCKED
@@ -143,8 +143,8 @@ class TestTam1:
def test_challenge_invalid_key_id(self):
"""CHALLENGE with key_id > 3 stays silent."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
tag = IcodeDnaTag(aes_keys=[b"\xAA" * 16, None, None, None])
tag._key_headers[0] = KEY_HEADER_ACTIVE_LOCKED
@@ -156,8 +156,8 @@ class TestTam1:
def test_challenge_wrong_auth_method(self):
"""CHALLENGE with AuthMethod != 0x00 (not TAM1) stays silent."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
tag = IcodeDnaTag(aes_keys=[b"\xAA" * 16, None, None, None])
tag._key_headers[0] = KEY_HEADER_ACTIVE_LOCKED
@@ -177,8 +177,8 @@ class TestMam:
"""Tests for MAM1/MAM2 mutual authentication via AUTHENTICATE (0x35)."""
def _make_tag(self, key=b"\xAA" * 16, key_slot=0):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
keys = [None] * 4
keys[key_slot] = key
@@ -293,7 +293,7 @@ class TestMam:
def test_mam1_inactive_key_error(self):
"""MAM1 with inactive key returns error."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag(aes_keys=[b"\xAA" * 16, None, None, None])
run(tag.power_on())
@@ -366,7 +366,7 @@ class TestMam:
def test_mam2_purpose_enable_privacy(self):
"""MAM2 with purpose=0x09 sets privacy mode."""
from pm3py.sim.auth_aes import PRIV_PRIVACY
from pm3py.transponders.hf.iso15693.nxp.auth_aes import PRIV_PRIVACY
key = b"\xAA" * 16
tag = self._make_tag(key)
@@ -380,7 +380,7 @@ class TestMam:
def test_mam2_purpose_disable_privacy(self):
"""MAM2 with purpose=0x0A clears privacy mode."""
from pm3py.sim.auth_aes import PRIV_PRIVACY
from pm3py.transponders.hf.iso15693.nxp.auth_aes import PRIV_PRIVACY
key = b"\xAA" * 16
tag = self._make_tag(key)
@@ -395,7 +395,7 @@ class TestMam:
def test_mam2_purpose_destroy(self):
"""MAM2 with purpose=0x0B sets destroyed."""
from pm3py.sim.auth_aes import PRIV_DESTROY
from pm3py.transponders.hf.iso15693.nxp.auth_aes import PRIV_DESTROY
key = b"\xAA" * 16
tag = self._make_tag(key)

View File

@@ -4,8 +4,8 @@ import pytest
from pm3py.sim.frame import RFFrame
from pm3py.sim.medium import SoftwareMedium
from pm3py.sim.iso14443a import _compute_bcc
from pm3py.sim.desfire import DesfireTag, DesfireReader
from pm3py.transponders.hf.iso14443a.base import _compute_bcc
from pm3py.transponders.hf.iso14443a.nxp.desfire import DesfireTag, DesfireReader
def run(coro):

View File

@@ -4,7 +4,7 @@ import pytest
from pm3py.sim.dual_session import DualInterfaceSession
from pm3py.sim.mcu_bridge import McuBridge
from pm3py.sim.mcu_protocol import MsgType, build_frame, cobs_decode, parse_frame
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
class MockSimSession:

View File

@@ -4,7 +4,7 @@ import struct
import pytest
from pm3py.sim.frame import RFFrame
from pm3py.sim.nxp_icode import (
from pm3py.transponders.hf.iso15693.nxp.nxp_icode import (
CMD_SET_EAS, CMD_READ_CONFIG, CMD_WRITE_CONFIG, CMD_READ_TT,
)
@@ -41,20 +41,20 @@ PWD_CONFIG = 0x20
class TestIcode3Basics:
def test_import(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
def test_inherits_slix2(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
assert issubclass(Icode3Tag, IcodeSlix2Tag)
def test_default_76_blocks(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
assert tag._num_blocks == 76
def test_responds_to_inventory(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
inv = bytes([0x26, 0x01, 0x00])
@@ -68,14 +68,14 @@ class TestIcode3Basics:
class TestIcode3ConfigPassword:
def test_config_password_auth(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4),
config_password=0xDEADBEEF)
run(tag.power_on())
_authenticate(tag, PWD_CONFIG, 0xDEADBEEF)
def test_config_password_wrong(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4),
config_password=0xDEADBEEF)
run(tag.power_on())
@@ -91,7 +91,7 @@ class TestIcode3ConfigPassword:
class TestIcode3InheritsSlix2:
def test_eas(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
cmd = bytes([0x02, CMD_SET_EAS, 0x04])
@@ -100,7 +100,7 @@ class TestIcode3InheritsSlix2:
assert tag.eas_enabled
def test_privacy(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4),
privacy_password=0xAAAAAAAA)
run(tag.power_on())
@@ -108,7 +108,7 @@ class TestIcode3InheritsSlix2:
assert tag.privacy_mode
def test_destroy(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4),
destroy_password=0xBBBBBBBB)
run(tag.power_on())
@@ -125,7 +125,7 @@ class TestIcode3InheritsSlix2:
class TestIcode3Counter:
def test_counter_increments_24bit(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -141,7 +141,7 @@ class TestIcode3Counter:
assert counter == 1
def test_counter_accumulates(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -155,7 +155,7 @@ class TestIcode3Counter:
assert counter == 10
def test_counter_saturates_at_24bit(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -177,7 +177,7 @@ class TestIcode3Counter:
assert counter == 0xFFFFFF
def test_normal_blocks_still_overwrite(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -198,7 +198,7 @@ class TestIcode3Counter:
class TestIcode3Config:
def test_read_config(self):
"""READ CONFIG returns config memory blocks."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -211,7 +211,7 @@ class TestIcode3Config:
def test_write_config(self):
"""WRITE CONFIG writes to config memory."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -228,7 +228,7 @@ class TestIcode3Config:
def test_read_config_passwords_masked(self):
"""READ CONFIG masks password blocks with 0x00."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4),
read_password=0xDEADBEEF)
run(tag.power_on())
@@ -242,7 +242,7 @@ class TestIcode3Config:
def test_write_config_requires_auth_when_protected(self):
"""WRITE CONFIG fails without config password when protected."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4),
config_password=0xAABBCCDD)
run(tag.power_on())
@@ -254,7 +254,7 @@ class TestIcode3Config:
def test_read_config_multiple_blocks(self):
"""READ CONFIG can read multiple blocks."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -273,7 +273,7 @@ class TestIcode3Config:
class TestIcode3TagTamper:
def test_read_tt_closed(self):
"""READ TT returns closed status by default."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4), tag_tamper=True)
run(tag.power_on())
@@ -287,7 +287,7 @@ class TestIcode3TagTamper:
def test_read_tt_open(self):
"""READ TT returns open status when tampered."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4), tag_tamper=True)
run(tag.power_on())
tag._tt_status_actual = 0x4F # 'O' = Open
@@ -298,7 +298,7 @@ class TestIcode3TagTamper:
def test_read_tt_not_supported_without_flag(self):
"""READ TT returns error when tag_tamper=False."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4), tag_tamper=False)
run(tag.power_on())
@@ -314,7 +314,7 @@ class TestIcode3TagTamper:
class TestIcode3SystemInfo:
def test_feature_flags(self):
"""GET NXP SYSTEM INFO returns ICODE 3 feature flags."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -338,7 +338,7 @@ class TestIcode3SystemInfo:
class TestIcode3NfcMirror:
def test_uid_mirror(self):
"""UID mirror overlays 16 ASCII hex bytes into user memory on read."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06")
run(tag.power_on())
@@ -354,7 +354,7 @@ class TestIcode3NfcMirror:
def test_uid_counter_mirror(self):
"""UID + counter mirror: 16 bytes UID + 'x' + 6 bytes counter."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06")
run(tag.power_on())
@@ -380,7 +380,7 @@ class TestIcode3NfcMirror:
def test_mirror_disabled(self):
"""With mirror disabled (sel=0), reads return physical memory."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06")
run(tag.power_on())
@@ -397,7 +397,7 @@ class TestIcode3NfcMirror:
def test_mirror_with_byte_offset(self):
"""Mirror starting at byte 2 within a block."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06")
run(tag.power_on())
@@ -417,7 +417,7 @@ class TestIcode3NfcMirror:
def test_mirror_outside_block_returns_physical(self):
"""Blocks before mirror region return physical memory."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06")
run(tag.power_on())
@@ -438,7 +438,7 @@ class TestIcode3NfcMirror:
class TestIcode3PrivacyMode2:
def test_privacy_mode2_inventory_zeroed_uid(self):
"""In privacy mode 2, inventory returns zeroed UID."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06",
privacy_password=0xDEADBEEF)
run(tag.power_on())
@@ -455,7 +455,7 @@ class TestIcode3PrivacyMode2:
def test_privacy_mode2_allows_reads(self):
"""Privacy mode 2 allows READ SINGLE BLOCK."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06",
privacy_password=0xDEADBEEF)
run(tag.power_on())
@@ -475,7 +475,7 @@ class TestIcode3PrivacyMode2:
def test_privacy_mode1_blocks_reads(self):
"""Privacy mode 1 blocks everything except GET_RANDOM/SET_PASSWORD."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06",
privacy_password=0xDEADBEEF)
run(tag.power_on())
@@ -489,7 +489,7 @@ class TestIcode3PrivacyMode2:
def test_pick_random_id(self):
"""PICK RANDOM ID (0xC2) generates random UID for inventory."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06",
privacy_password=0xDEADBEEF)
run(tag.power_on())
@@ -514,7 +514,7 @@ class TestIcode3PrivacyMode2:
def test_pick_random_id_fails_outside_privacy(self):
"""PICK RANDOM ID fails when not in privacy mode."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20\x03\x04\x05\x06")
run(tag.power_on())
@@ -530,7 +530,7 @@ class TestIcode3PrivacyMode2:
class TestIcode3Signature48:
def test_default_32_byte_signature(self):
"""Default READ SIGNATURE returns 32 bytes (1 flag + 32 sig = 33)."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -542,7 +542,7 @@ class TestIcode3Signature48:
def test_48_byte_signature_mode(self):
"""With 48-byte mode enabled, READ SIGNATURE returns 49 bytes."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
sig48 = bytes(range(48))
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4), signature=sig48)
run(tag.power_on())
@@ -557,7 +557,7 @@ class TestIcode3Signature48:
def test_48_byte_mode_disabled_truncates(self):
"""With 48-byte mode disabled, READ SIGNATURE returns first 32 bytes."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
sig48 = bytes(range(48))
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4), signature=sig48)
run(tag.power_on())
@@ -574,7 +574,7 @@ class TestIcode3Signature48:
class TestIcode3CounterPreset:
def test_value_0x000001_increments(self):
"""Writing 0x000001 to block 75 increments counter by 1."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -590,7 +590,7 @@ class TestIcode3CounterPreset:
def test_value_not_0x000001_presets(self):
"""Writing != 0x000001 to block 75 presets (overwrites) counter."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -610,7 +610,7 @@ class TestIcode3CounterPreset:
def test_0x000001_twice_increments_twice(self):
"""Writing 0x000001 twice increments counter from 0 → 1 → 2."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())
@@ -625,7 +625,7 @@ class TestIcode3CounterPreset:
def test_prot_byte_written(self):
"""PROT byte (data[3]) is written to memory alongside counter."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(uid=b"\xE0\x04\x01\x20" + bytes(4))
run(tag.power_on())

View File

@@ -4,7 +4,7 @@ import struct
import pytest
from pm3py.sim.frame import RFFrame
from pm3py.sim.nxp_icode import (
from pm3py.transponders.hf.iso15693.nxp.nxp_icode import (
CMD_SET_EAS, CMD_RESET_EAS, CMD_LOCK_EAS, CMD_EAS_ALARM,
CMD_PASSWORD_PROTECT_EAS_AFI, CMD_WRITE_EAS_ID,
CMD_INVENTORY_READ, CMD_FAST_INVENTORY_READ,
@@ -45,23 +45,23 @@ PWD_EAS_AFI = 0x10
class TestIcodeSlixBasics:
def test_import(self):
"""IcodeSlixTag can be imported."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
def test_inherits_nxp_icode(self):
"""SLIX inherits from NxpIcodeTag."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.sim.nxp_icode import NxpIcodeTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.nxp_icode import NxpIcodeTag
assert issubclass(IcodeSlixTag, NxpIcodeTag)
def test_default_28_blocks(self):
"""SLIX defaults to 28 blocks × 4 bytes."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
assert tag._num_blocks == 28
assert tag._block_size == 4
def test_responds_to_inventory(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
inv = bytes([0x26, 0x01, 0x00])
@@ -69,7 +69,7 @@ class TestIcodeSlixBasics:
assert resp is not None
def test_read_write_block(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
# Write block 5
@@ -89,7 +89,7 @@ class TestIcodeSlixBasics:
class TestIcodeSlixPassword:
def test_set_password_eas_afi(self):
"""SET_PASSWORD with correct EAS/AFI password succeeds."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4),
eas_afi_password=0xAABBCCDD)
run(tag.power_on())
@@ -97,7 +97,7 @@ class TestIcodeSlixPassword:
def test_set_password_wrong(self):
"""SET_PASSWORD with wrong password fails."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4),
eas_afi_password=0xAABBCCDD)
run(tag.power_on())
@@ -108,7 +108,7 @@ class TestIcodeSlixPassword:
def test_write_password(self):
"""WRITE_PASSWORD changes the EAS/AFI password."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4),
eas_afi_password=0xAABBCCDD)
run(tag.power_on())
@@ -122,7 +122,7 @@ class TestIcodeSlixPassword:
def test_lock_password(self):
"""LOCK_PASSWORD prevents WRITE_PASSWORD."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4),
eas_afi_password=0xAABBCCDD)
run(tag.power_on())
@@ -139,7 +139,7 @@ class TestIcodeSlixPassword:
def test_no_privacy_password(self):
"""SLIX has no privacy — only EAS/AFI password accepted."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4),
eas_afi_password=0xAABBCCDD)
run(tag.power_on())
@@ -156,7 +156,7 @@ class TestIcodeSlixPassword:
class TestIcodeSlixEas:
def test_set_eas(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
cmd = bytes([0x02, CMD_SET_EAS, 0x04])
@@ -165,7 +165,7 @@ class TestIcodeSlixEas:
assert tag.eas_enabled
def test_reset_eas(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
tag.set_eas(True)
@@ -175,7 +175,7 @@ class TestIcodeSlixEas:
assert not tag.eas_enabled
def test_eas_alarm(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
tag.set_eas(True)
@@ -186,7 +186,7 @@ class TestIcodeSlixEas:
assert len(resp.data) >= 33
def test_eas_alarm_silent_when_disabled(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
cmd = bytes([0x02, CMD_EAS_ALARM, 0x04])
@@ -194,7 +194,7 @@ class TestIcodeSlixEas:
assert resp is None
def test_lock_eas(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
tag.set_eas(True)
@@ -207,7 +207,7 @@ class TestIcodeSlixEas:
assert resp.data[0] & 0x01
def test_password_protect_eas_afi(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4),
eas_afi_password=0xAABBCCDD)
run(tag.power_on())
@@ -219,7 +219,7 @@ class TestIcodeSlixEas:
def test_write_eas_id(self):
"""WRITE EAS ID is SLIX2-only (EAS Selective per AN11809)."""
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
tag = IcodeSlix2Tag(uid=b"\xE0\x04\x02" + bytes(5),
eas_afi_password=0xAABBCCDD)
run(tag.power_on())
@@ -231,7 +231,7 @@ class TestIcodeSlixEas:
def test_slix_rejects_write_eas_id(self):
"""SLIX (SL2S2002) does not support WRITE EAS ID (0xA7)."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
cmd = bytes([0x02, CMD_WRITE_EAS_ID, 0x04, 0x34, 0x12])
@@ -245,7 +245,7 @@ class TestIcodeSlixEas:
class TestIcodeSlixInventoryRead:
def test_inventory_read(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10\x03\x04\x05\x06")
run(tag.power_on())
cmd = bytes([0x06, CMD_INVENTORY_READ, 0x04, 0x00, 0x00, 0x00])
@@ -254,7 +254,7 @@ class TestIcodeSlixInventoryRead:
assert resp.data[0] == 0x00
def test_fast_inventory_read(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10\x03\x04\x05\x06")
run(tag.power_on())
cmd = bytes([0x06, CMD_FAST_INVENTORY_READ, 0x04, 0x00, 0x00, 0x00])
@@ -271,12 +271,12 @@ class TestSlix2StillWorks:
"""Verify SLIX2 inherits from SLIX and retains all features."""
def test_slix2_inherits_slix(self):
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
assert issubclass(IcodeSlix2Tag, IcodeSlixTag)
def test_slix2_privacy_still_works(self):
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
tag = IcodeSlix2Tag(uid=b"\xE0\x04\x02" + bytes(5),
privacy_password=0xDEADBEEF)
run(tag.power_on())
@@ -284,7 +284,7 @@ class TestSlix2StillWorks:
assert tag.privacy_mode
def test_slix2_destroy_still_works(self):
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
tag = IcodeSlix2Tag(uid=b"\xE0\x04\x02" + bytes(5),
destroy_password=0xDEAD1234)
run(tag.power_on())
@@ -298,7 +298,7 @@ class TestSlix2StillWorks:
def test_slix2_eas_inherited_from_slix(self):
"""SLIX2 EAS works via inheritance from SLIX."""
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
tag = IcodeSlix2Tag(uid=b"\xE0\x04\x02" + bytes(5))
run(tag.power_on())
cmd = bytes([0x02, CMD_SET_EAS, 0x04])
@@ -314,7 +314,7 @@ class TestSlix2StillWorks:
class TestSlixLacksPrivacy:
def test_no_enable_privacy(self):
"""SLIX does not respond to ENABLE PRIVACY (0xBA)."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
cmd = bytes([0x02, 0xBA, 0x04, 0x00, 0x00, 0x00, 0x00])
@@ -324,7 +324,7 @@ class TestSlixLacksPrivacy:
def test_no_destroy(self):
"""SLIX does not respond to DESTROY (0xB9)."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
cmd = bytes([0x02, 0xB9, 0x04, 0x00, 0x00, 0x00, 0x00])
@@ -333,7 +333,7 @@ class TestSlixLacksPrivacy:
def test_no_protect_page(self):
"""SLIX does not respond to PROTECT PAGE (0xB6)."""
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
tag = IcodeSlixTag(uid=b"\xE0\x04\x01\x10" + bytes(4))
run(tag.power_on())
cmd = bytes([0x02, 0xB6, 0x04, 0x08, 0x01])

View File

@@ -3,12 +3,12 @@ import asyncio
import pytest
from pm3py.sim.medium import SoftwareMedium
from pm3py.sim.implants import (
from pm3py.transponders.implants import (
xEM, xNT, xM1, FlexDF, NExT,
MagicMifareClassicTag,
)
from pm3py.sim.em4100 import EM4100Reader
from pm3py.sim.iso14443a import Reader14443A, _compute_bcc
from pm3py.transponders.lf.em.em4100 import EM4100Reader
from pm3py.transponders.hf.iso14443a.base import Reader14443A, _compute_bcc
def run(coro):
@@ -36,7 +36,7 @@ class TestXNT:
assert tag._total_pages >= 45 # NTAG213+ size
def test_is_type2_tag(self):
from pm3py.sim.ndef import NfcType2Tag
from pm3py.transponders.hf.iso14443a.ndef import NfcType2Tag
tag = xNT()
assert isinstance(tag, NfcType2Tag)
@@ -77,7 +77,7 @@ class TestMagicMifareClassic:
class TestFlexDF:
def test_creates_desfire(self):
from pm3py.sim.desfire import DesfireTag
from pm3py.transponders.hf.iso14443a.nxp.desfire import DesfireTag
tag = FlexDF()
assert isinstance(tag, DesfireTag)
@@ -92,7 +92,7 @@ class TestNExT:
# LF side is T5577 configured as EM4100
assert lf.blocks[0] != 0
# HF side is NfcType2Tag (xNT)
from pm3py.sim.ndef import NfcType2Tag
from pm3py.transponders.hf.iso14443a.ndef import NfcType2Tag
assert isinstance(hf, NfcType2Tag)
def test_both_sides_work(self):

View File

@@ -4,10 +4,10 @@ import pytest
from pm3py.sim.frame import RFFrame
from pm3py.sim.medium import SoftwareMedium
from pm3py.sim.lf_base import TagLF, ReaderLF, Modulation
from pm3py.sim.em4100 import EM4100Tag, EM4100Reader
from pm3py.sim.hid import HIDProxTag, HIDReader
from pm3py.sim.t5577 import T5577Tag, T5577Reader
from pm3py.transponders.lf.base import TagLF, ReaderLF, Modulation
from pm3py.transponders.lf.em.em4100 import EM4100Tag, EM4100Reader
from pm3py.transponders.lf.hid.hid import HIDProxTag, HIDReader
from pm3py.transponders.lf.atmel.t5577 import T5577Tag, T5577Reader
def run(coro):

View File

@@ -140,14 +140,14 @@ class TestTransponderRegions:
class TestTag15693Regions:
def test_has_user_region(self):
from pm3py.sim.iso15693 import Tag15693
from pm3py.transponders.hf.iso15693.base import Tag15693
tag = Tag15693(uid=bytes(8), block_size=4, num_blocks=28)
assert "user" in tag.regions
assert tag.regions["user"].block_size == 4
assert tag.regions["user"].eml_offset == 175
def test_memory_property_aliases_region(self):
from pm3py.sim.iso15693 import Tag15693
from pm3py.transponders.hf.iso15693.base import Tag15693
tag = Tag15693(uid=bytes(8), block_size=4, num_blocks=28)
tag._memory[0:4] = b"\xDE\xAD\xBE\xEF"
assert tag.regions["user"].data[0:4] == b"\xDE\xAD\xBE\xEF"
@@ -156,7 +156,7 @@ class TestTag15693Regions:
class TestIcodeSlix2AccessMap:
def test_protection_pointer_sets_access_map(self):
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
tag = IcodeSlix2Tag(uid=b"\xE0\x04\x02" + bytes(5), protection_pointer=4,
read_password=0xAABBCCDD)
user = tag.regions["user"]
@@ -166,7 +166,7 @@ class TestIcodeSlix2AccessMap:
assert user.access_for_block(4).read_key == 1
def test_no_protection_pointer_all_open(self):
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
tag = IcodeSlix2Tag(uid=b"\xE0\x04\x02" + bytes(5))
user = tag.regions["user"]
assert user.access_for_block(0).read == "open"
@@ -177,7 +177,7 @@ class TestIcodeSlix2AccessMap:
class TestCompileFromRegions:
def test_open_blocks_have_data_entries(self):
from pm3py.sim.iso15693 import Tag15693
from pm3py.transponders.hf.iso15693.base import Tag15693
from pm3py.sim.table_compiler import TableCompiler
tag = Tag15693(uid=bytes(8), block_size=4, num_blocks=4)
tag._memory[0:4] = b"\xDE\xAD\xBE\xEF"
@@ -187,7 +187,7 @@ class TestCompileFromRegions:
assert entry.response[1:5] == b"\xDE\xAD\xBE\xEF"
def test_protected_blocks_without_auth(self):
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
from pm3py.sim.table_compiler import TableCompiler
tag = IcodeSlix2Tag(uid=b"\xE0\x04\x02" + bytes(5), protection_pointer=2,
read_password=0xAABBCCDD, block_size=4, num_blocks=4)
@@ -198,7 +198,7 @@ class TestCompileFromRegions:
assert table.lookup(bytes([0x02, 0x20, 0x02])) is None
def test_protected_blocks_with_auth(self):
from pm3py.sim.icode_slix2 import IcodeSlix2Tag, PWD_READ
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag, PWD_READ
from pm3py.sim.table_compiler import TableCompiler
tag = IcodeSlix2Tag(uid=b"\xE0\x04\x02" + bytes(5), protection_pointer=2,
read_password=0xAABBCCDD, block_size=4, num_blocks=4)

View File

@@ -5,9 +5,9 @@ import pytest
from pm3py.sim.frame import RFFrame
from pm3py.sim.medium import SoftwareMedium
from pm3py.sim.crypto1 import Crypto1
from pm3py.sim.mifare import MifareClassicTag, MifareClassicReader
from pm3py.sim.iso14443a import Reader14443A, REQA, CL1, NVB_SELECT, _compute_bcc
from pm3py.transponders.hf.iso14443a.nxp.crypto1 import Crypto1
from pm3py.transponders.hf.iso14443a.nxp.mifare_classic import MifareClassicTag, MifareClassicReader
from pm3py.transponders.hf.iso14443a.base import Reader14443A, REQA, CL1, NVB_SELECT, _compute_bcc
def run(coro):

View File

@@ -4,8 +4,8 @@ import pytest
from pm3py.sim.frame import RFFrame
from pm3py.sim.medium import SoftwareMedium
from pm3py.sim.iso14443a import Reader14443A, _compute_bcc
from pm3py.sim.ndef import NfcType2Tag, NfcType4Tag
from pm3py.transponders.hf.iso14443a.base import Reader14443A, _compute_bcc
from pm3py.transponders.hf.iso14443a.ndef import NfcType2Tag, NfcType4Tag
def run(coro):

View File

@@ -15,45 +15,45 @@ def run(coro):
class TestIcodeDna:
def test_inherits_slix2(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
assert issubclass(IcodeDnaTag, IcodeSlix2Tag)
def test_default_64_blocks(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
assert tag._num_blocks == 64
def test_uid_prefix(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
assert tag._uid[:4] == b"\xE0\x04\x01\x18"
def test_counter_on_last_block(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
user = tag.regions["user"]
assert user.access_for_block(63).write_mode == "counter"
def test_4_aes_keys(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
assert len(tag._aes_keys) == 4
assert all(k is None for k in tag._aes_keys)
def test_aes_keys_from_constructor(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
key0 = b"\xAA" * 16
tag = IcodeDnaTag(aes_keys=[key0, None, None, None])
assert tag._aes_keys[0] == key0
def test_config_memory_48_blocks(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
assert len(tag._config_memory) == 48 * 4
def test_read_config(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
run(tag.power_on())
# Read config header block 0x08
@@ -64,7 +64,7 @@ class TestIcodeDna:
assert resp.data[1] == 0x81 # CONFIG_HEADER_WRITABLE default
def test_write_config(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
run(tag.power_on())
# Write CID to block 0x09
@@ -78,7 +78,7 @@ class TestIcodeDna:
def test_key_storage_masked_when_active(self):
"""Key blocks return zeros when key header is active."""
from pm3py.sim.icode_dna import IcodeDnaTag, KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag, KEY_HEADER_ACTIVE_LOCKED
tag = IcodeDnaTag(aes_keys=[b"\xAA" * 16, None, None, None])
run(tag.power_on())
@@ -95,7 +95,7 @@ class TestIcodeDna:
def test_key_write_rejected_when_active(self):
"""Cannot write key blocks when header is active."""
from pm3py.sim.icode_dna import IcodeDnaTag, KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag, KEY_HEADER_ACTIVE_LOCKED
tag = IcodeDnaTag()
run(tag.power_on())
tag._key_headers[0] = KEY_HEADER_ACTIVE_LOCKED
@@ -106,7 +106,7 @@ class TestIcodeDna:
def test_key_header_one_way(self):
"""Key header only goes up (lower → higher values)."""
from pm3py.sim.icode_dna import IcodeDnaTag, KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag, KEY_HEADER_ACTIVE_LOCKED
tag = IcodeDnaTag()
run(tag.power_on())
@@ -118,7 +118,7 @@ class TestIcodeDna:
def test_gch_one_way(self):
"""NFC_GCH only programs one-way."""
from pm3py.sim.icode_dna import IcodeDnaTag, GCH_ACTIVATED
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag, GCH_ACTIVATED
tag = IcodeDnaTag()
run(tag.power_on())
@@ -129,19 +129,19 @@ class TestIcodeDna:
assert tag._nfc_gch == GCH_ACTIVATED
def test_cid_default(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
assert tag._cid == 0xC000
def test_responds_to_inventory(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
run(tag.power_on())
resp = run(tag.handle_frame(RFFrame.from_bytes(bytes([0x26, 0x01, 0x00]))))
assert resp is not None
def test_inherits_eas(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
run(tag.power_on())
cmd = bytes([0x02, 0xA2, 0x04])
@@ -156,12 +156,12 @@ class TestIcodeDna:
class TestNtag5Platform:
def test_config_memory(self):
from pm3py.sim.ntag5_platform import Ntag5PlatformTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_platform import Ntag5PlatformTag
tag = Ntag5PlatformTag(num_blocks=128)
assert len(tag._config_memory) >= 160 * 4
def test_read_config(self):
from pm3py.sim.ntag5_platform import Ntag5PlatformTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_platform import Ntag5PlatformTag
tag = Ntag5PlatformTag(num_blocks=128)
run(tag.power_on())
cmd = bytes([0x02, 0xC0, 0x04, 0x3F, 0x00])
@@ -171,7 +171,7 @@ class TestNtag5Platform:
assert resp.data[1] == 0xA5 # DEV_SEC_CONFIG default
def test_write_config(self):
from pm3py.sim.ntag5_platform import Ntag5PlatformTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_platform import Ntag5PlatformTag
tag = Ntag5PlatformTag(num_blocks=128)
run(tag.power_on())
cmd = bytes([0x02, 0xC1, 0x04, 0x57, 0x34, 0x12, 0x00, 0x00])
@@ -189,36 +189,36 @@ class TestNtag5Platform:
class TestNtag5Switch:
def test_inherits_platform(self):
from pm3py.sim.ntag5_switch import Ntag5SwitchTag
from pm3py.sim.ntag5_platform import Ntag5PlatformTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_switch import Ntag5SwitchTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_platform import Ntag5PlatformTag
assert issubclass(Ntag5SwitchTag, Ntag5PlatformTag)
def test_default_128_blocks(self):
from pm3py.sim.ntag5_switch import Ntag5SwitchTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_switch import Ntag5SwitchTag
tag = Ntag5SwitchTag()
assert tag._num_blocks == 128
def test_no_aes(self):
from pm3py.sim.ntag5_switch import Ntag5SwitchTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_switch import Ntag5SwitchTag
tag = Ntag5SwitchTag()
assert not tag._aes_capable
def test_counter_on_block_127(self):
from pm3py.sim.ntag5_switch import Ntag5SwitchTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_switch import Ntag5SwitchTag
tag = Ntag5SwitchTag()
user = tag.regions["user"]
assert user.access_for_block(127).write_mode == "counter"
assert user.access_for_block(0).write_mode == "normal"
def test_responds_to_inventory(self):
from pm3py.sim.ntag5_switch import Ntag5SwitchTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_switch import Ntag5SwitchTag
tag = Ntag5SwitchTag()
run(tag.power_on())
resp = run(tag.handle_frame(RFFrame.from_bytes(bytes([0x26, 0x01, 0x00]))))
assert resp is not None
def test_switch_rejects_stay_quiet_persistent(self):
from pm3py.sim.ntag5_switch import Ntag5SwitchTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_switch import Ntag5SwitchTag
tag = Ntag5SwitchTag()
run(tag.power_on())
cmd = bytes([0x22, 0xBC]) + tag._uid[::-1] + bytes([0x04])
@@ -233,33 +233,33 @@ class TestNtag5Switch:
class TestNtag5Link:
def test_inherits_platform(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.sim.ntag5_platform import Ntag5PlatformTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_platform import Ntag5PlatformTag
assert issubclass(Ntag5LinkTag, Ntag5PlatformTag)
def test_default_512_blocks(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
assert tag._num_blocks == 512
def test_i2c_address(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
assert tag.i2c_address == 0x54
def test_sram(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
assert len(tag.sram) == 256
def test_i2c_sram_roundtrip(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
tag.i2c_write(0x2000, b"\xAA\xBB\xCC\xDD")
assert tag.i2c_read(0x2000, 4) == b"\xAA\xBB\xCC\xDD"
def test_sram_mirror_read(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag, ARBITER_MIRROR
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag, ARBITER_MIRROR
tag = Ntag5LinkTag()
run(tag.power_on())
tag._sram_enabled = True
@@ -270,12 +270,12 @@ class TestNtag5Link:
assert resp.data[1:5] == b"\xDE\xAD\xBE\xEF"
def test_password_only_variant(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag(aes_capable=False)
assert not tag._aes_capable
def test_aes_variant(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag(aes_capable=True)
assert tag._aes_capable
@@ -286,33 +286,33 @@ class TestNtag5Link:
class TestArbitration:
def test_acquire_nfc_succeeds_no_lock(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
assert tag.acquire_nfc() is True
assert tag.nfc_if_locked is True
def test_acquire_nfc_fails_when_i2c_locked(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
tag.set_i2c_locked(True)
assert tag.acquire_nfc() is False
assert tag.nfc_if_locked is False
def test_acquire_i2c_succeeds_no_lock(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
assert tag.acquire_i2c() is True
assert tag.i2c_if_locked is True
def test_acquire_i2c_fails_when_nfc_locked(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
tag.set_nfc_locked(True)
assert tag.acquire_i2c() is False
assert tag.i2c_if_locked is False
def test_release_clears_lock(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
tag.acquire_nfc()
assert tag.nfc_if_locked is True
@@ -325,7 +325,7 @@ class TestArbitration:
assert tag.i2c_if_locked is False
def test_nfc_sram_read_blocked_when_i2c_locked(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag, ARBITER_MIRROR
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag, ARBITER_MIRROR
tag = Ntag5LinkTag()
run(tag.power_on())
tag._sram_enabled = True
@@ -339,7 +339,7 @@ class TestArbitration:
assert resp.data[1] == 0x0F
def test_nfc_sram_read_works_with_nfc_lock(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag, ARBITER_MIRROR
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag, ARBITER_MIRROR
tag = Ntag5LinkTag()
run(tag.power_on())
tag._sram_enabled = True
@@ -352,21 +352,21 @@ class TestArbitration:
assert resp.data[1:5] == b"\xDE\xAD\xBE\xEF"
def test_i2c_sram_read_blocked_when_nfc_locked(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
tag.set_nfc_locked(True)
result = tag.i2c_read(0x2000, 4)
assert result is None
def test_i2c_sram_write_blocked_when_nfc_locked(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
tag.set_nfc_locked(True)
result = tag.i2c_write(0x2000, b"\x01\x02\x03\x04")
assert result is False
def test_lock_unlock_sequential_access(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
# NFC acquires, writes via SRAM directly, releases
@@ -391,27 +391,27 @@ class TestArbitration:
class TestNtag5Boost:
def test_inherits_link(self):
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
assert issubclass(Ntag5BoostTag, Ntag5LinkTag)
def test_aes_always(self):
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
assert tag._aes_capable
def test_default_512_blocks(self):
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
assert tag._num_blocks == 512
def test_has_sram(self):
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
assert len(tag.sram) == 256
def test_boost_rejects_stay_quiet_persistent(self):
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
cmd = bytes([0x22, 0xBC]) + tag._uid[::-1] + bytes([0x04])
@@ -428,7 +428,7 @@ class TestSessionRegisters:
"""Session register state machine for NTAG 5 platform."""
def _make_tag(self):
from pm3py.sim.ntag5_platform import Ntag5PlatformTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_platform import Ntag5PlatformTag
tag = Ntag5PlatformTag(num_blocks=128)
run(tag.power_on())
return tag
@@ -553,8 +553,8 @@ class TestNtag5Aes:
def test_link_5332_tam1(self):
"""TAM1 (CHALLENGE + READBUFFER) works on Link NTP5332 (aes_capable=True)."""
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from Crypto.Cipher import AES
key = b"\xCC" * 16
@@ -586,8 +586,8 @@ class TestNtag5Aes:
def test_link_5332_tam1_readbuffer_one_shot(self):
"""READBUFFER is one-shot — second read returns None."""
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
key = b"\xCC" * 16
tag = Ntag5LinkTag(aes_capable=True)
@@ -607,7 +607,7 @@ class TestNtag5Aes:
def test_switch_no_aes_challenge_rejected(self):
"""CHALLENGE on Switch (no AES) does not produce a valid response."""
from pm3py.sim.ntag5_switch import Ntag5SwitchTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_switch import Ntag5SwitchTag
tag = Ntag5SwitchTag()
run(tag.power_on())
@@ -620,7 +620,7 @@ class TestNtag5Aes:
def test_link_no_aes_challenge_rejected(self):
"""CHALLENGE on Link NTP5312 (aes_capable=False) does not work."""
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag(aes_capable=False)
run(tag.power_on())
@@ -631,8 +631,8 @@ class TestNtag5Aes:
def test_boost_mam1(self):
"""MAM1 (AUTHENTICATE with AuthMethod=0x02) works on Boost."""
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from Crypto.Cipher import AES
key = b"\xDD" * 16
@@ -663,8 +663,8 @@ class TestNtag5Aes:
def test_boost_mam2(self):
"""Full MAM1 + MAM2 mutual authentication on Boost."""
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from Crypto.Cipher import AES
key = b"\xEE" * 16
@@ -708,8 +708,8 @@ class TestNtag5Aes:
def test_boost_mam2_wrong_key_fails(self):
"""MAM2 with wrong key is rejected."""
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.sim.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.auth_aes import KEY_HEADER_ACTIVE_LOCKED
from Crypto.Cipher import AES
key = b"\xEE" * 16
@@ -735,7 +735,7 @@ class TestNtag5Aes:
def test_link_no_aes_authenticate_rejected(self):
"""AUTHENTICATE on Link NTP5312 (no AES) returns error."""
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag(aes_capable=False)
run(tag.power_on())
@@ -748,7 +748,7 @@ class TestNtag5Aes:
def test_boost_inherits_slix2_commands(self):
"""AES-capable Boost still handles SLIX2 commands (e.g. inventory, read)."""
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
@@ -772,13 +772,13 @@ class TestConfigReg:
"""CONFIG_REG (session register block 0xA1) bit-field accessors and enforcement."""
def _make_platform_tag(self):
from pm3py.sim.ntag5_platform import Ntag5PlatformTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_platform import Ntag5PlatformTag
tag = Ntag5PlatformTag(num_blocks=128)
run(tag.power_on())
return tag
def _make_link_tag(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
run(tag.power_on())
return tag
@@ -869,7 +869,7 @@ class TestPassThrough:
"""SRAM pass-through mode (arbiter_mode == 2)."""
def _make_tag(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag, ARBITER_PASSTHROUGH
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag, ARBITER_PASSTHROUGH
tag = Ntag5LinkTag()
run(tag.power_on())
tag.sram_enable = True
@@ -946,7 +946,7 @@ class TestPassThrough:
def test_passthrough_not_active_in_normal_mode(self):
"""Pass-through behavior inactive when arbiter_mode is NORMAL."""
from pm3py.sim.ntag5_link import Ntag5LinkTag, ARBITER_NORMAL
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag, ARBITER_NORMAL
tag = Ntag5LinkTag()
run(tag.power_on())
tag.sram_enable = True
@@ -958,7 +958,7 @@ class TestPassThrough:
def test_passthrough_not_active_in_mirror_mode(self):
"""Pass-through behavior inactive when arbiter_mode is MIRROR."""
from pm3py.sim.ntag5_link import Ntag5LinkTag, ARBITER_MIRROR
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag, ARBITER_MIRROR
tag = Ntag5LinkTag()
run(tag.power_on())
tag.sram_enable = True
@@ -998,7 +998,7 @@ class TestSynchDataBlock:
"""Synch data block triggers status register flags on access."""
def _make_tag(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
run(tag.power_on())
return tag
@@ -1075,7 +1075,7 @@ class TestEventDetection:
"""ED pin callbacks and trigger logic for NTAG 5 platform."""
def _make_tag(self):
from pm3py.sim.ntag5_platform import Ntag5PlatformTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_platform import Ntag5PlatformTag
tag = Ntag5PlatformTag(num_blocks=128)
run(tag.power_on())
return tag
@@ -1178,7 +1178,7 @@ class TestReadSram:
"""Direct SRAM read via NXP custom command 0xD2."""
def _make_tag(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
run(tag.power_on())
tag.sram_enable = True
@@ -1216,7 +1216,7 @@ class TestReadSram:
def test_error_when_sram_disabled(self):
"""Error (0x01, 0x0F) when SRAM is not enabled."""
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
run(tag.power_on())
# sram_enable defaults to False
@@ -1248,7 +1248,7 @@ class TestWriteSram:
"""Direct SRAM write via NXP custom command 0xD3."""
def _make_tag(self):
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
run(tag.power_on())
tag.sram_enable = True
@@ -1275,7 +1275,7 @@ class TestWriteSram:
def test_error_when_sram_disabled(self):
"""Error (0x01, 0x0F) when SRAM is not enabled."""
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
run(tag.power_on())
cmd = bytes([0x02, 0xD3, 0x04, 0x00, 0x01, 0xDE, 0xAD, 0xBE, 0xEF])
@@ -1302,7 +1302,7 @@ class TestDualInterfaceIntegration:
def _make_tag(self, pt_dir_nfc_to_i2c: bool = True):
"""Create an Ntag5LinkTag configured for pass-through mode."""
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
run(tag.power_on())
tag.sram_enable = True
@@ -1411,7 +1411,7 @@ class TestDualInterfaceIntegration:
def test_session_register_consistency(self):
"""STATUS_REG reflects complete state after a cycle."""
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
run(tag.power_on())
tag.sram_enable = True
@@ -1473,7 +1473,7 @@ class TestDualInterfaceIntegration:
def test_ed_pin_fires_on_synch_data_block_access(self):
"""ED pin fires when NFC writes to the configured synch data block."""
from pm3py.sim.ntag5_link import Ntag5LinkTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_link import Ntag5LinkTag
tag = Ntag5LinkTag()
run(tag.power_on())
@@ -1516,8 +1516,8 @@ class TestNtag5Area1Passwords:
"""AREA_1 password IDs (0x40/0x80) per NTP5210/NTA5332 datasheets."""
def test_area1_password_ids_exist_on_switch(self):
from pm3py.sim.ntag5_switch import Ntag5SwitchTag
from pm3py.sim.ntag5_platform import PWD_AREA1_READ, PWD_AREA1_WRITE
from pm3py.transponders.hf.iso15693.nxp.ntag5_switch import Ntag5SwitchTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_platform import PWD_AREA1_READ, PWD_AREA1_WRITE
tag = Ntag5SwitchTag()
assert PWD_AREA1_READ == 0x40
assert PWD_AREA1_WRITE == 0x80
@@ -1532,7 +1532,7 @@ class TestNtag5PickRandomUid:
"""PICK RANDOM UID (0xC2) per NTA5332 datasheet 8.2.4.9.15."""
def test_pick_random_uid_in_privacy_mode(self):
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
tag._privacy_mode = True
@@ -1546,7 +1546,7 @@ class TestNtag5PickRandomUid:
assert tag._random_uid[:2] == b"\xE0\x04"
def test_pick_random_uid_without_privacy_mode_returns_error(self):
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
assert tag._privacy_mode is False
@@ -1559,7 +1559,7 @@ class TestNtag5PickRandomUid:
def test_switch_rejects_pick_random_uid(self):
"""NTP5210 does not support PICK RANDOM UID per datasheet rev 3.2."""
from pm3py.sim.ntag5_switch import Ntag5SwitchTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_switch import Ntag5SwitchTag
tag = Ntag5SwitchTag()
run(tag.power_on())
# Test outside privacy mode — should get error via custom command dispatch
@@ -1580,7 +1580,7 @@ class TestExtendedCommands:
def test_extended_read_single_block(self):
"""Read block 256 (beyond 1-byte range) using extended read single."""
import struct
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
# Write known data to block 256
@@ -1597,7 +1597,7 @@ class TestExtendedCommands:
def test_extended_read_single_block_addressed(self):
"""Extended read single in addressed mode."""
import struct
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
offset = 300 * tag._block_size
@@ -1612,7 +1612,7 @@ class TestExtendedCommands:
def test_extended_write_single_block(self):
"""Write to block 300 using extended write, then read back."""
import struct
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
block_le = struct.pack("<H", 300)
@@ -1629,7 +1629,7 @@ class TestExtendedCommands:
def test_extended_read_multiple_blocks(self):
"""Read 3 blocks starting at block 256."""
import struct
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
bs = tag._block_size
@@ -1649,7 +1649,7 @@ class TestExtendedCommands:
def test_extended_read_last_block_boost(self):
"""Block 511 (last block of Boost) is readable via extended read."""
import struct
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
last = tag._num_blocks - 1 # 511
@@ -1664,7 +1664,7 @@ class TestExtendedCommands:
def test_extended_read_out_of_range(self):
"""Block 512 on Boost (512 blocks) returns error."""
import struct
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
block_le = struct.pack("<H", 512)
@@ -1677,7 +1677,7 @@ class TestExtendedCommands:
def test_extended_read_multiple_overflow(self):
"""Extended read multiple that would go past end returns error."""
import struct
from pm3py.sim.ntag5_boost import Ntag5BoostTag
from pm3py.transponders.hf.iso15693.nxp.ntag5_boost import Ntag5BoostTag
tag = Ntag5BoostTag()
run(tag.power_on())
block_le = struct.pack("<H", 510)

View File

@@ -5,18 +5,18 @@ import pytest
from pm3py.sim.frame import RFFrame
from pm3py.sim.medium import SoftwareMedium
from pm3py.sim.type5 import NfcType5Tag
from pm3py.sim.nxp_icode import NxpIcodeTag
from pm3py.sim.icode_slix import IcodeSlixTag
from pm3py.sim.icode_slix2 import (
from pm3py.transponders.hf.iso15693.type5 import NfcType5Tag
from pm3py.transponders.hf.iso15693.nxp.nxp_icode import NxpIcodeTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix import IcodeSlixTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import (
IcodeSlix2Tag, PWD_EAS_AFI, PWD_READ, PWD_WRITE, PWD_PRIVACY, PWD_DESTROY,
)
from pm3py.sim.nxp_icode import (
from pm3py.transponders.hf.iso15693.nxp.nxp_icode import (
CMD_SET_EAS, CMD_RESET_EAS, CMD_LOCK_EAS, CMD_EAS_ALARM,
CMD_PASSWORD_PROTECT_EAS_AFI, CMD_WRITE_EAS_ID, CMD_INVENTORY_READ,
CMD_FAST_INVENTORY_READ,
)
from pm3py.sim.iso15693 import Reader15693
from pm3py.transponders.hf.iso15693.base import Reader15693
def run(coro):

View File

@@ -5,16 +5,16 @@ import pytest
from unittest.mock import AsyncMock
from pm3py.sim.frame import RFFrame
from pm3py.sim.iso14443a import Tag14443A_3, Tag14443A_4, _compute_bcc
from pm3py.sim.mifare import MifareClassicTag
from pm3py.sim.iso15693 import Tag15693
from pm3py.sim.desfire import DesfireTag
from pm3py.transponders.hf.iso14443a.base import Tag14443A_3, Tag14443A_4, _compute_bcc
from pm3py.transponders.hf.iso14443a.nxp.mifare_classic import MifareClassicTag
from pm3py.transponders.hf.iso15693.base import Tag15693
from pm3py.transponders.hf.iso14443a.nxp.desfire import DesfireTag
from pm3py.sim.table_compiler import (
TableEntry, ResponseTable, TableCompiler,
EML_READ, EML_WRITE, MATCH_PREFIX,
)
from pm3py.sim.nxp_icode import NxpIcodeTag
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.nxp_icode import NxpIcodeTag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
def run(coro):
@@ -415,14 +415,14 @@ class TestTableCompilerEasAlarm:
class TestTableCompilerIcode3:
def test_compile_icode3_exists(self):
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag()
table = TableCompiler.compile_icode3(tag)
assert len(table.entries) > 0
def test_compile_icode3_includes_slix2_entries(self):
"""ICODE 3 table includes SLIX2 base entries."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag()
table = TableCompiler.compile_icode3(tag)
# Should have GET_RANDOM, GET_NXP_SYSTEM_INFO, READ_SIGNATURE
@@ -432,7 +432,7 @@ class TestTableCompilerIcode3:
def test_compile_icode3_system_info_has_feature_flags(self):
"""ICODE 3 GET NXP SYSTEM INFO has proper feature flags."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag()
table = TableCompiler.compile_icode3(tag)
entry = table.lookup(bytes([0x02, 0xAB]))
@@ -444,7 +444,7 @@ class TestTableCompilerIcode3:
def test_compile_icode3_config_password(self):
"""ICODE 3 table includes config password (pwd_id 0x20)."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
tag = Icode3Tag(config_password=0xAABBCCDD)
table = TableCompiler.compile_icode3(tag)
auth_entries = [e for e in table.entries if e.set_auth != 0]
@@ -457,7 +457,7 @@ class TestTableCompilerIcode3:
def test_session_dispatches_icode3(self):
"""SimSession uses compile_icode3 for Icode3Tag."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
from pm3py.sim.sim_session import SimSession
from unittest.mock import MagicMock
@@ -478,14 +478,14 @@ class TestTableCompilerIcode3:
class TestTableCompilerDna:
def test_compile_icode_dna_exists(self):
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
table = TableCompiler.compile_icode_dna(tag)
assert len(table.entries) > 0
def test_compile_includes_base_entries(self):
"""DNA table includes GET_RANDOM, READ_SIGNATURE from NXP base."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
table = TableCompiler.compile_icode_dna(tag)
assert table.lookup(bytes([0x02, 0xB2])) is not None # GET_RANDOM
@@ -493,7 +493,7 @@ class TestTableCompilerDna:
def test_compile_has_dna_feature_flags(self):
"""GET NXP SYSTEM INFO has DNA-specific feature flags."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
table = TableCompiler.compile_icode_dna(tag)
entry = table.lookup(bytes([0x02, 0xAB]))
@@ -507,7 +507,7 @@ class TestTableCompilerDna:
def test_compile_has_eas(self):
"""DNA table includes EAS entries."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
tag = IcodeDnaTag()
tag.set_eas(True)
table = TableCompiler.compile_icode_dna(tag)
@@ -516,7 +516,7 @@ class TestTableCompilerDna:
def test_session_dispatches_dna(self):
"""SimSession uses compile_icode_dna for IcodeDnaTag."""
from pm3py.sim.icode_dna import IcodeDnaTag
from pm3py.transponders.hf.iso15693.nxp.icode_dna import IcodeDnaTag
from pm3py.sim.sim_session import SimSession
from unittest.mock import MagicMock
@@ -538,7 +538,7 @@ class TestTableCompilerDna:
class TestSimSessionTableCompile:
def test_start_15693_compiles_nxp_table(self):
"""SimSession uses compile_icode3 for Icode3Tag."""
from pm3py.sim.icode3 import Icode3Tag
from pm3py.transponders.hf.iso15693.nxp.icode3 import Icode3Tag
from pm3py.sim.sim_session import SimSession
from unittest.mock import MagicMock

View File

@@ -2,7 +2,9 @@
import os
import pytest
from pm3py.sim.trace_fmt import decode_15693, decode_15693_nxp, decode_14443a, TraceFormatter
from pm3py.trace.decode_iso15 import decode_15693, decode_15693_nxp
from pm3py.trace.decode_iso14a import decode_14443a
from pm3py.trace.format import TraceFormatter
class TestDecode15693Request:
@@ -391,7 +393,7 @@ class TestTraceFormatterWrapping:
def test_long_annotation_wraps_to_next_line(self):
cc = bytes([0xE1, 0x40, 0x0D, 0x01])
from pm3py.sim.type5 import ndef_text
from pm3py.transponders.hf.iso15693.type5 import ndef_text
msg = ndef_text("A" * 30)
tlv = bytes([0x03, len(msg)]) + msg + bytes([0xFE])
payload = bytes([0x00]) + cc + tlv
@@ -490,44 +492,44 @@ class TestTransponderDecodeTrace:
assert hasattr(Transponder, 'decode_trace')
def test_tag15693_decodes_standard(self):
from pm3py.sim.iso15693 import Tag15693
from pm3py.transponders.hf.iso15693.base import Tag15693
tag = Tag15693(uid=bytes(8))
result = tag.decode_trace(0, bytes([0x26, 0x01, 0x00]))
assert result == "INVENTORY"
def test_tag15693_decodes_nxp_names(self):
"""Base Tag15693 decodes NXP command names (via standard decoder)."""
from pm3py.sim.iso15693 import Tag15693
from pm3py.transponders.hf.iso15693.base import Tag15693
tag = Tag15693(uid=bytes(8))
result = tag.decode_trace(0, bytes([0x22, 0xA1, 0x04, 0x02]))
assert result == "NXP FAST INVENTORY READ"
def test_nxp_icode_decodes_nxp(self):
from pm3py.sim.nxp_icode import NxpIcodeTag
from pm3py.transponders.hf.iso15693.nxp.nxp_icode import NxpIcodeTag
tag = NxpIcodeTag(uid=b"\xE0\x04" + bytes(6))
result = tag.decode_trace(0, bytes([0x22, 0xA1, 0x04, 0x02]))
assert result == "NXP FAST INVENTORY READ"
def test_nxp_icode_falls_back_to_standard(self):
from pm3py.sim.nxp_icode import NxpIcodeTag
from pm3py.transponders.hf.iso15693.nxp.nxp_icode import NxpIcodeTag
tag = NxpIcodeTag(uid=b"\xE0\x04" + bytes(6))
result = tag.decode_trace(0, bytes([0x26, 0x01, 0x00]))
assert result == "INVENTORY"
def test_icode_slix2_inherits_nxp(self):
from pm3py.sim.icode_slix2 import IcodeSlix2Tag
from pm3py.transponders.hf.iso15693.nxp.icode_slix2 import IcodeSlix2Tag
tag = IcodeSlix2Tag(uid=b"\xE0\x04\x02" + bytes(5))
result = tag.decode_trace(0, bytes([0x22, 0xB2, 0x04]))
assert result == "NXP GET RANDOM"
def test_tag14443a_decodes(self):
from pm3py.sim.iso14443a import Tag14443A
from pm3py.transponders.hf.iso14443a.base import Tag14443A
tag = Tag14443A(uid=bytes(4))
result = tag.decode_trace(0, bytes([0x26]))
assert result == "REQA"
def test_tag14443a_no_15693(self):
from pm3py.sim.iso14443a import Tag14443A
from pm3py.transponders.hf.iso14443a.base import Tag14443A
tag = Tag14443A(uid=bytes(4))
result = tag.decode_trace(0, bytes([0x26, 0x01, 0x00]))
# 14443a decoder sees 0x26 as REQA (single byte check happens first)