hw 14a raw: closer to pm3 syntax, removed bit_frame,...

Now data length is always in bits
Option -o => -a and only needed to turn field on without select or data
Reorganize pcd_14a_reader_raw_cmd
Some more checks
This commit is contained in:
Philippe Teuwen
2023-09-24 01:02:30 +02:00
parent 234b22c48a
commit f7db6d0fb3
6 changed files with 174 additions and 158 deletions
+25 -13
View File
@@ -1589,26 +1589,34 @@ class HF14ARaw(ReaderRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
parser.add_argument('-r', '--response', help="do not read response", action='store_true', default=False,)
parser.add_argument('-c', '--crc', help="calculate and append CRC", action='store_true', default=False,)
parser.add_argument('-cc', '--crc-clear', help="Verify and clear CRC of received data", action='store_true', default=False,)
parser.add_argument('-k', '--keep-rf', help="keep signal field ON after receive", action='store_true', default=False,)
parser.add_argument('-o', '--open-rf', help="active signal field ON", action='store_true', default=False,)
parser.add_argument('-s', '--select-tag', help="Select the tag before executing the command", action='store_true', default=False,)
parser.add_argument('-b', '--bits', type=int, help="number of bits to send. Useful for send partial byte")
parser.add_argument('-t', '--timeout', type=int, help="timeout in ms", default=100)
parser.add_argument('-a', '--activate-rf', help="Active signal field ON without select", action='store_true', default=False,)
parser.add_argument('-s', '--select-tag', help="Active signal field ON with select", action='store_true', default=False,)
# TODO: parser.add_argument('-3', '--type3-select-tag', help="Active signal field ON with ISO14443-3 select (no RATS)", action='store_true', default=False,)
parser.add_argument('-d', '--data', type=str, help="Data to be sent")
parser.add_argument('-b', '--bits', type=int, help="Number of bits to send. Useful for send partial byte")
parser.add_argument('-c', '--crc', help="Calculate and append CRC", action='store_true', default=False,)
parser.add_argument('-r', '--response', help="Do not read response", action='store_true', default=False,)
parser.add_argument('-cc', '--crc-clear', help="Verify and clear CRC of received data", action='store_true', default=False,)
parser.add_argument('-k', '--keep-rf', help="Keep signal field ON after receive", action='store_true', default=False,)
parser.add_argument('-t', '--timeout', type=int, help="Timeout in ms", default=100)
# TODO: need support for carriage returns in parser, why are they mangled?
# parser.description = 'Examples:\n' \
# ' hf 14a raw -b 7 -d 40 -k\n' \
# ' hf 14a raw -d 43 -k\n' \
# ' hf 14a raw -d 3000 -c\n' \
# ' hf 14a raw -sc -d 6000\n'
return parser
def on_exec(self, args: argparse.Namespace):
options = {
'open_rf_field': self.bool_to_bit(args.open_rf),
'wait_response': self.bool_to_bit(args.response == False),
'activate_rf_field': self.bool_to_bit(args.activate_rf),
'wait_response': self.bool_to_bit(not args.response),
'append_crc': self.bool_to_bit(args.crc),
'bit_frame': self.bool_to_bit(args.bits is not None),
'auto_select': self.bool_to_bit(args.select_tag),
'keep_rf_field': self.bool_to_bit(args.keep_rf),
'check_response_crc': self.bool_to_bit(args.crc_clear),
#'auto_type3_select': self.bool_to_bit(args.type3-select-tag),
}
data: str = args.data
if data is not None:
@@ -1624,6 +1632,10 @@ class HF14ARaw(ReaderRequiredUnit):
return
else:
data_bytes = []
if args.bits is not None and args.crc:
print(f" [!] {CR}--bits and --crc are mutually exclusive{C0}")
return
# Exec 14a raw cmd.
resp = self.cmd.hf14a_raw(options, args.timeout, data_bytes, args.bits)
if resp.status == chameleon_status.Device.HF_TAG_OK:
@@ -1632,9 +1644,9 @@ class HF14ARaw(ReaderRequiredUnit):
# print head
" - " +
# print data
' '.join([ hex(byte).replace('0x', '').rjust(2, '0') for byte in resp.data ])
' '.join([hex(byte).replace('0x', '').rjust(2, '0') for byte in resp.data])
)
else:
print(F" [*] {CY}No data response{C0}")
print(F" [*] {CY}No response{C0}")
else:
print(f" [!] {CR}{chameleon_status.message[resp.status]}{C0} ")
+15 -22
View File
@@ -617,7 +617,7 @@ class ChameleonCMD:
resp.data = resp.status == chameleon_status.Device.HF_TAG_OK
return resp
def hf14a_raw(self, options, resp_timeout_ms=100, data=[], bit_owned_by_the_last_byte=None):
def hf14a_raw(self, options, resp_timeout_ms=100, data=[], bitlen=None):
"""
Send raw cmd to 14a tag
:param options:
@@ -629,40 +629,35 @@ class ChameleonCMD:
class CStruct(ctypes.BigEndianStructure):
_fields_ = [
("open_rf_field", ctypes.c_uint8, 1),
("activate_rf_field", ctypes.c_uint8, 1),
("wait_response", ctypes.c_uint8, 1),
("append_crc", ctypes.c_uint8, 1),
("bit_frame", ctypes.c_uint8, 1),
("auto_select", ctypes.c_uint8, 1),
("keep_rf_field", ctypes.c_uint8, 1),
("check_response_crc", ctypes.c_uint8, 1),
("reserved", ctypes.c_uint8, 1),
("reserved", ctypes.c_uint8, 2),
]
cs = CStruct()
cs.open_rf_field = options['open_rf_field']
cs.activate_rf_field = options['activate_rf_field']
cs.wait_response = options['wait_response']
cs.append_crc = options['append_crc']
cs.bit_frame = options['bit_frame']
cs.auto_select = options['auto_select']
cs.keep_rf_field = options['keep_rf_field']
cs.check_response_crc = options['check_response_crc']
if options['bit_frame'] == 1:
bits_or_bytes = len(data) * 8 # bits = bytes * 8(bit)
if bit_owned_by_the_last_byte is not None and bit_owned_by_the_last_byte != 8:
bits_or_bytes = bits_or_bytes - (8 - bit_owned_by_the_last_byte)
if bitlen is None:
bitlen = len(data) * 8 # bits = bytes * 8(bit)
else:
bits_or_bytes = len(data) # bytes length
if len(data) > 0:
data = struct.pack(f'!BHH{len(data)}s', bytes(cs)[0], resp_timeout_ms, bits_or_bytes, bytearray(data))
else:
data = struct.pack(f'!BHH', bytes(cs)[0], resp_timeout_ms, 0)
if len(data) == 0:
raise ValueError(f'bitlen={bitlen} but missing data')
if not ((len(data) - 1) * 8 < bitlen <= len(data) * 8):
raise ValueError(f'bitlen={bitlen} incompatible with provided data ({len(data)} bytes), '
f'must be between {((len(data) - 1) * 8 )+1} and {len(data) * 8} included')
data = bytes(cs)+struct.pack(f'!HH{len(data)}s', resp_timeout_ms, bitlen, bytearray(data))
return self.device.send_cmd_sync(DATA_CMD_HF14A_RAW, data, timeout=(resp_timeout_ms / 1000) + 1)
@expect_response(chameleon_status.Device.HF_TAG_OK)
def mf1_static_nested_acquire(self, block_known, type_known, key_known, block_target, type_target):
"""
@@ -1228,26 +1223,24 @@ def test_fn():
cml.set_device_reader_mode()
options = {
'open_rf_field': 1,
'activate_rf_field': 1,
'wait_response': 1,
'append_crc': 0,
'bit_frame': 1,
'auto_select': 0,
'keep_rf_field': 1,
'check_response_crc': 0,
}
# unlock 1
resp = cml.hf14a_raw(options=options, resp_timeout_ms=1000, data=[0x40], bit_owned_by_the_last_byte=7)
resp = cml.hf14a_raw(options=options, resp_timeout_ms=1000, data=[0x40], bitlen=7)
if resp.status == 0x00 and resp.data[0] == 0x0a:
print("Gen1A unlock 1 success")
# unlock 2
options['bit_frame'] = 0
resp = cml.hf14a_raw(options=options, resp_timeout_ms=1000, data=[0x43])
if resp.status == 0x00 and resp.data[0] == 0x0a:
print("Gen1A unlock 2 success")
print("Start dump gen1a memeory...")
print("Start dump gen1a memory...")
block = 0
while block < 64:
# Tag read block cmd