mirror of
https://github.com/RfidResearchGroup/ChameleonUltra.git
synced 2026-05-12 11:22:59 -07:00
cli: move enums to new file
This commit is contained in:
@@ -19,7 +19,9 @@ import chameleon_status
|
||||
from chameleon_utils import ArgumentParserNoExit, ArgsParserError, UnexpectedResponseError
|
||||
from chameleon_utils import CLITree
|
||||
from chameleon_utils import CR, CG, CB, CC, CY, CM, C0
|
||||
|
||||
from chameleon_enum import Command, SlotNumber, TagSenseType, TagSpecificType
|
||||
from chameleon_enum import MifareClassicWriteMode, MifareClassicPrngType, MifareClassicDarksideStatus, MfcKeyType
|
||||
from chameleon_enum import AnimationMode, ButtonType, ButtonPressFunction
|
||||
|
||||
# NXP IDs based on https://www.nxp.com/docs/en/application-note/AN10833.pdf
|
||||
type_id_SAK_dict = {0x00: "MIFARE Ultralight Classic/C/EV1/Nano | NTAG 2xx",
|
||||
@@ -177,7 +179,7 @@ class ReaderRequiredUnit(DeviceRequiredUnit):
|
||||
class SlotIndexArgsUnit(DeviceRequiredUnit):
|
||||
@staticmethod
|
||||
def add_slot_args(parser: ArgumentParserNoExit, mandatory=False):
|
||||
slot_choices = [x.value for x in chameleon_cmd.SlotNumber]
|
||||
slot_choices = [x.value for x in SlotNumber]
|
||||
help_str = f"Slot Index: {slot_choices} Default: active slot"
|
||||
|
||||
parser.add_argument('-s', "--slot", type=int, required=mandatory, help=help_str, metavar="<1-8>",
|
||||
@@ -188,7 +190,7 @@ class SlotIndexArgsUnit(DeviceRequiredUnit):
|
||||
class SlotIndexArgsAndGoUnit(SlotIndexArgsUnit):
|
||||
def before_exec(self, args: argparse.Namespace):
|
||||
if super().before_exec(args):
|
||||
self.prev_slot_num = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
self.prev_slot_num = SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
if args.slot is not None:
|
||||
self.slot_num = args.slot
|
||||
if self.slot_num != self.prev_slot_num:
|
||||
@@ -227,7 +229,7 @@ class MF1AuthArgsUnit(ReaderRequiredUnit):
|
||||
class Param:
|
||||
def __init__(self):
|
||||
self.block = args.blk
|
||||
self.type = chameleon_cmd.MfcKeyType.B if args.b else chameleon_cmd.MfcKeyType.A
|
||||
self.type = MfcKeyType.B if args.b else MfcKeyType.A
|
||||
key: str = args.key
|
||||
if not re.match(r"^[a-fA-F0-9]{12}$", key):
|
||||
raise ArgsParserError("key must include 12 HEX symbols")
|
||||
@@ -350,7 +352,7 @@ class LFEMIdArgsUnit(DeviceRequiredUnit):
|
||||
class TagTypeArgsUnit(DeviceRequiredUnit):
|
||||
@staticmethod
|
||||
def add_type_args(parser: ArgumentParserNoExit):
|
||||
type_names = [t.name for t in chameleon_cmd.TagSpecificType.list()]
|
||||
type_names = [t.name for t in TagSpecificType.list()]
|
||||
help_str = "Tag Type: " + ", ".join(type_names)
|
||||
parser.add_argument('-t', "--type", type=str, required=True, metavar="TAG_TYPE",
|
||||
help=help_str, choices=type_names)
|
||||
@@ -581,7 +583,7 @@ class HF14AScan(ReaderRequiredUnit):
|
||||
# detect prng
|
||||
print("- Mifare Classic technology")
|
||||
prng_type = self.cmd.mf1_detect_prng()
|
||||
print(f" # Prng: {chameleon_cmd.MifareClassicPrngType(prng_type)}")
|
||||
print(f" # Prng: {MifareClassicPrngType(prng_type)}")
|
||||
|
||||
def sak_info(self, data_tag):
|
||||
# detect the technology in use based on SAK
|
||||
@@ -727,7 +729,7 @@ class HFMFNested(ReaderRequiredUnit):
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
block_known = args.blk
|
||||
# default to A
|
||||
type_known = chameleon_cmd.MfcKeyType.B if args.b else chameleon_cmd.MfcKeyType.A
|
||||
type_known = MfcKeyType.B if args.b else MfcKeyType.A
|
||||
|
||||
key_known: str = args.key
|
||||
if not re.match(r"^[a-fA-F0-9]{12}$", key_known):
|
||||
@@ -736,7 +738,7 @@ class HFMFNested(ReaderRequiredUnit):
|
||||
key_known: bytearray = bytearray.fromhex(key_known)
|
||||
block_target = args.tblk
|
||||
# default to A
|
||||
type_target = chameleon_cmd.MfcKeyType.B if args.b else chameleon_cmd.MfcKeyType.A
|
||||
type_target = MfcKeyType.B if args.b else MfcKeyType.A
|
||||
if block_known == block_target and type_known == type_target:
|
||||
print(f"{CR}Target key already known{C0}")
|
||||
return
|
||||
@@ -772,8 +774,8 @@ class HFMFDarkside(ReaderRequiredUnit):
|
||||
while retry_count < 0xFF:
|
||||
darkside_resp = self.cmd.mf1_darkside_acquire(block_target, type_target, first_recover, 30)
|
||||
first_recover = False # not first run.
|
||||
if darkside_resp[0] != chameleon_cmd.MifareClassicDarksideStatus.OK:
|
||||
print(f"Darkside error: {chameleon_cmd.MifareClassicDarksideStatus(darkside_resp[0])}")
|
||||
if darkside_resp[0] != MifareClassicDarksideStatus.OK:
|
||||
print(f"Darkside error: {MifareClassicDarksideStatus(darkside_resp[0])}")
|
||||
break
|
||||
darkside_obj = darkside_resp[1]
|
||||
|
||||
@@ -815,7 +817,7 @@ class HFMFDarkside(ReaderRequiredUnit):
|
||||
return None
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
key = self.recover_key(0x03, chameleon_cmd.MfcKeyType.A)
|
||||
key = self.recover_key(0x03, MfcKeyType.A)
|
||||
if key is not None:
|
||||
print(f" - Key Found: {key}")
|
||||
else:
|
||||
@@ -1043,14 +1045,14 @@ class HFMFESave(SlotIndexArgsAndGoUnit, DeviceRequiredUnit):
|
||||
|
||||
selected_slot = self.cmd.get_active_slot()
|
||||
slot_info = self.cmd.get_slot_info()
|
||||
tag_type = chameleon_cmd.TagSpecificType(slot_info[selected_slot]['hf'])
|
||||
if tag_type == chameleon_cmd.TagSpecificType.MIFARE_Mini:
|
||||
tag_type = TagSpecificType(slot_info[selected_slot]['hf'])
|
||||
if tag_type == TagSpecificType.MIFARE_Mini:
|
||||
block_count = 20
|
||||
elif tag_type == chameleon_cmd.TagSpecificType.MIFARE_1024:
|
||||
elif tag_type == TagSpecificType.MIFARE_1024:
|
||||
block_count = 64
|
||||
elif tag_type == chameleon_cmd.TagSpecificType.MIFARE_2048:
|
||||
elif tag_type == TagSpecificType.MIFARE_2048:
|
||||
block_count = 128
|
||||
elif tag_type == chameleon_cmd.TagSpecificType.MIFARE_4096:
|
||||
elif tag_type == TagSpecificType.MIFARE_4096:
|
||||
block_count = 256
|
||||
else:
|
||||
raise Exception("Card in current slot is not Mifare Classic/Plus in SL1 mode")
|
||||
@@ -1091,7 +1093,7 @@ class HFMFEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequiredU
|
||||
block0_group.add_argument('--enable-block0', action='store_true',
|
||||
help="Use anti-collision data from block 0 for 4 byte UID tags")
|
||||
block0_group.add_argument('--disable-block0', action='store_true', help="Use anti-collision data from settings")
|
||||
write_names = [w.name for w in chameleon_cmd.MifareClassicWriteMode.list()]
|
||||
write_names = [w.name for w in MifareClassicWriteMode.list()]
|
||||
help_str = "Write Mode: " + ", ".join(write_names)
|
||||
parser.add_argument('--write', type=str, help=help_str, metavar="MODE", choices=write_names)
|
||||
log_group = parser.add_mutually_exclusive_group()
|
||||
@@ -1110,13 +1112,13 @@ class HFMFEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequiredU
|
||||
sak = anti_coll_data['sak']
|
||||
ats = anti_coll_data['ats']
|
||||
slotinfo = self.cmd.get_slot_info()
|
||||
fwslot = chameleon_cmd.SlotNumber.to_fw(self.slot_num)
|
||||
hf_tag_type = chameleon_cmd.TagSpecificType(slotinfo[fwslot]['hf'])
|
||||
fwslot = SlotNumber.to_fw(self.slot_num)
|
||||
hf_tag_type = TagSpecificType(slotinfo[fwslot]['hf'])
|
||||
if hf_tag_type not in [
|
||||
chameleon_cmd.TagSpecificType.MIFARE_Mini,
|
||||
chameleon_cmd.TagSpecificType.MIFARE_1024,
|
||||
chameleon_cmd.TagSpecificType.MIFARE_2048,
|
||||
chameleon_cmd.TagSpecificType.MIFARE_4096,
|
||||
TagSpecificType.MIFARE_Mini,
|
||||
TagSpecificType.MIFARE_1024,
|
||||
TagSpecificType.MIFARE_2048,
|
||||
TagSpecificType.MIFARE_4096,
|
||||
]:
|
||||
print(f"{CR}Slot {self.slot_num} not configured as MIFARE Classic{C0}")
|
||||
return
|
||||
@@ -1124,7 +1126,7 @@ class HFMFEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequiredU
|
||||
gen1a_mode = mfc_config["gen1a_mode"]
|
||||
gen2_mode = mfc_config["gen2_mode"]
|
||||
block_anti_coll_mode = mfc_config["block_anti_coll_mode"]
|
||||
write_mode = chameleon_cmd.MifareClassicWriteMode(mfc_config["write_mode"])
|
||||
write_mode = MifareClassicWriteMode(mfc_config["write_mode"])
|
||||
detection = mfc_config["detection"]
|
||||
change_requested, change_done, uid, atqa, sak, ats = self.update_hf14a_anticoll(args, uid, atqa, sak, ats)
|
||||
if args.enable_gen1a:
|
||||
@@ -1177,7 +1179,7 @@ class HFMFEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequiredU
|
||||
print(f'{CY}Requested block0 anti-coll mode already disabled{C0}')
|
||||
if args.write is not None:
|
||||
change_requested = True
|
||||
new_write_mode = chameleon_cmd.MifareClassicWriteMode[args.write]
|
||||
new_write_mode = MifareClassicWriteMode[args.write]
|
||||
if new_write_mode != write_mode:
|
||||
write_mode = new_write_mode
|
||||
self.cmd.mf1_set_write_mode(write_mode)
|
||||
@@ -1219,7 +1221,7 @@ class HFMFEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequiredU
|
||||
f'- {"Use anti-collision data from block 0:":40}'
|
||||
f'{f"{CG}enabled{C0}" if block_anti_coll_mode else f"{CR}disabled{C0}"}')
|
||||
try:
|
||||
print(f'- {"Write mode:":40}{CY}{chameleon_cmd.MifareClassicWriteMode(write_mode)}{C0}')
|
||||
print(f'- {"Write mode:":40}{CY}{MifareClassicWriteMode(write_mode)}{C0}')
|
||||
except ValueError:
|
||||
print(f'- {"Write mode:":40}{CR}invalid value!{C0}')
|
||||
print(
|
||||
@@ -1333,12 +1335,12 @@ class HFMFUEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequired
|
||||
sak = anti_coll_data['sak']
|
||||
ats = anti_coll_data['ats']
|
||||
slotinfo = self.cmd.get_slot_info()
|
||||
fwslot = chameleon_cmd.SlotNumber.to_fw(self.slot_num)
|
||||
hf_tag_type = chameleon_cmd.TagSpecificType(slotinfo[fwslot]['hf'])
|
||||
fwslot = SlotNumber.to_fw(self.slot_num)
|
||||
hf_tag_type = TagSpecificType(slotinfo[fwslot]['hf'])
|
||||
if hf_tag_type not in [
|
||||
chameleon_cmd.TagSpecificType.NTAG_213,
|
||||
chameleon_cmd.TagSpecificType.NTAG_215,
|
||||
chameleon_cmd.TagSpecificType.NTAG_216,
|
||||
TagSpecificType.NTAG_213,
|
||||
TagSpecificType.NTAG_215,
|
||||
TagSpecificType.NTAG_216,
|
||||
]:
|
||||
print(f"{CR}Slot {self.slot_num} not configured as MIFARE Ultralight / NTAG{C0}")
|
||||
return
|
||||
@@ -1407,21 +1409,21 @@ class HWSlotList(DeviceRequiredUnit):
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
slotinfo = self.cmd.get_slot_info()
|
||||
selected = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
selected = SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
current = selected
|
||||
enabled = self.cmd.get_enabled_slots()
|
||||
maxnamelength = 0
|
||||
slotnames = []
|
||||
for slot in chameleon_cmd.SlotNumber:
|
||||
hfn = self.get_slot_name(slot, chameleon_cmd.TagSenseType.HF)
|
||||
lfn = self.get_slot_name(slot, chameleon_cmd.TagSenseType.LF)
|
||||
for slot in SlotNumber:
|
||||
hfn = self.get_slot_name(slot, TagSenseType.HF)
|
||||
lfn = self.get_slot_name(slot, TagSenseType.LF)
|
||||
m = max(hfn['baselen'], lfn['baselen'])
|
||||
maxnamelength = m if m > maxnamelength else maxnamelength
|
||||
slotnames.append({'hf': hfn, 'lf': lfn})
|
||||
for slot in chameleon_cmd.SlotNumber:
|
||||
fwslot = chameleon_cmd.SlotNumber.to_fw(slot)
|
||||
hf_tag_type = chameleon_cmd.TagSpecificType(slotinfo[fwslot]['hf'])
|
||||
lf_tag_type = chameleon_cmd.TagSpecificType(slotinfo[fwslot]['lf'])
|
||||
for slot in SlotNumber:
|
||||
fwslot = SlotNumber.to_fw(slot)
|
||||
hf_tag_type = TagSpecificType(slotinfo[fwslot]['hf'])
|
||||
lf_tag_type = TagSpecificType(slotinfo[fwslot]['lf'])
|
||||
print(f' - {f"Slot {slot}:":{4+maxnamelength+1}}'
|
||||
f'{f"({CG}active{C0})" if slot == selected else ""}')
|
||||
|
||||
@@ -1430,7 +1432,7 @@ class HWSlotList(DeviceRequiredUnit):
|
||||
print(f' HF: '
|
||||
f'{slotnames[fwslot]["hf"]["name"]:{field_length}}', end='')
|
||||
print(f'{f"({CR}disabled{C0}) " if not enabled[fwslot]["hf"] else ""}', end='')
|
||||
if hf_tag_type != chameleon_cmd.TagSpecificType.UNDEFINED:
|
||||
if hf_tag_type != TagSpecificType.UNDEFINED:
|
||||
print(f"{CY if enabled[fwslot]['hf'] else C0}{hf_tag_type}{C0}")
|
||||
else:
|
||||
print("undef")
|
||||
@@ -1451,10 +1453,10 @@ class HWSlotList(DeviceRequiredUnit):
|
||||
if len(ats) > 0:
|
||||
print(f' {"ATS:":40}{CY}{ats.hex().upper()}{C0}')
|
||||
if hf_tag_type in [
|
||||
chameleon_cmd.TagSpecificType.MIFARE_Mini,
|
||||
chameleon_cmd.TagSpecificType.MIFARE_1024,
|
||||
chameleon_cmd.TagSpecificType.MIFARE_2048,
|
||||
chameleon_cmd.TagSpecificType.MIFARE_4096,
|
||||
TagSpecificType.MIFARE_Mini,
|
||||
TagSpecificType.MIFARE_1024,
|
||||
TagSpecificType.MIFARE_2048,
|
||||
TagSpecificType.MIFARE_4096,
|
||||
]:
|
||||
config = self.cmd.mf1_get_emulator_config()
|
||||
# print(' - Mifare Classic emulator settings:')
|
||||
@@ -1469,7 +1471,7 @@ class HWSlotList(DeviceRequiredUnit):
|
||||
f'{f"{CG}enabled{C0}" if config["block_anti_coll_mode"] else f"{CR}disabled{C0}"}')
|
||||
try:
|
||||
print(f' {"Write mode:":40}{CY}'
|
||||
f'{chameleon_cmd.MifareClassicWriteMode(config["write_mode"])}{C0}')
|
||||
f'{MifareClassicWriteMode(config["write_mode"])}{C0}')
|
||||
except ValueError:
|
||||
print(f' {"Write mode:":40}{CR}invalid value!{C0}')
|
||||
print(
|
||||
@@ -1481,7 +1483,7 @@ class HWSlotList(DeviceRequiredUnit):
|
||||
print(f' LF: '
|
||||
f'{slotnames[fwslot]["lf"]["name"]:{field_length}}', end='')
|
||||
print(f'{f"({CR}disabled{C0}) " if not enabled[fwslot]["lf"] else ""}', end='')
|
||||
if lf_tag_type != chameleon_cmd.TagSpecificType.UNDEFINED:
|
||||
if lf_tag_type != TagSpecificType.UNDEFINED:
|
||||
print(f"{CY if enabled[fwslot]['lf'] else C0}{lf_tag_type}{C0}")
|
||||
else:
|
||||
print("undef")
|
||||
@@ -1519,11 +1521,11 @@ class HWSlotType(TagTypeArgsUnit, SlotIndexArgsUnit):
|
||||
return parser
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
tag_type = chameleon_cmd.TagSpecificType[args.type]
|
||||
tag_type = TagSpecificType[args.type]
|
||||
if args.slot is not None:
|
||||
slot_num = args.slot
|
||||
else:
|
||||
slot_num = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
slot_num = SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
self.cmd.set_slot_tag_type(slot_num, tag_type)
|
||||
print(f' - Set slot {slot_num} tag type success.')
|
||||
|
||||
@@ -1541,11 +1543,11 @@ class HWDeleteSlotSense(SlotIndexArgsUnit, SenseTypeArgsUnit):
|
||||
if args.slot is not None:
|
||||
slot_num = args.slot
|
||||
else:
|
||||
slot_num = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
slot_num = SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
if args.lf:
|
||||
sense_type = chameleon_cmd.TagSenseType.LF
|
||||
sense_type = TagSenseType.LF
|
||||
else:
|
||||
sense_type = chameleon_cmd.TagSenseType.HF
|
||||
sense_type = TagSenseType.HF
|
||||
self.cmd.delete_slot_sense_type(slot_num, sense_type)
|
||||
print(f' - Delete slot {slot_num} {sense_type.name} tag type success.')
|
||||
|
||||
@@ -1560,11 +1562,11 @@ class HWSlotInit(TagTypeArgsUnit, SlotIndexArgsUnit):
|
||||
return parser
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
tag_type = chameleon_cmd.TagSpecificType[args.type]
|
||||
tag_type = TagSpecificType[args.type]
|
||||
if args.slot is not None:
|
||||
slot_num = args.slot
|
||||
else:
|
||||
slot_num = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
slot_num = SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
self.cmd.set_slot_data_default(slot_num, tag_type)
|
||||
print(' - Set slot tag data init success.')
|
||||
|
||||
@@ -1582,11 +1584,11 @@ class HWSlotEnable(SlotIndexArgsUnit, SenseTypeArgsUnit):
|
||||
if args.slot is not None:
|
||||
slot_num = args.slot
|
||||
else:
|
||||
slot_num = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
slot_num = SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
if args.lf:
|
||||
sense_type = chameleon_cmd.TagSenseType.LF
|
||||
sense_type = TagSenseType.LF
|
||||
else:
|
||||
sense_type = chameleon_cmd.TagSenseType.HF
|
||||
sense_type = TagSenseType.HF
|
||||
self.cmd.set_slot_enable(slot_num, sense_type, True)
|
||||
print(f' - Enable slot {slot_num} {sense_type.name} success.')
|
||||
|
||||
@@ -1603,9 +1605,9 @@ class HWSlotDisable(SlotIndexArgsUnit, SenseTypeArgsUnit):
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
slot_num = args.slot
|
||||
if args.lf:
|
||||
sense_type = chameleon_cmd.TagSenseType.LF
|
||||
sense_type = TagSenseType.LF
|
||||
else:
|
||||
sense_type = chameleon_cmd.TagSenseType.HF
|
||||
sense_type = TagSenseType.HF
|
||||
self.cmd.set_slot_enable(slot_num, sense_type, False)
|
||||
print(f' - Disable slot {slot_num} {sense_type.name} success.')
|
||||
|
||||
@@ -1645,11 +1647,11 @@ class HWSlotNick(SlotIndexArgsUnit, SenseTypeArgsUnit):
|
||||
if args.slot is not None:
|
||||
slot_num = args.slot
|
||||
else:
|
||||
slot_num = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
slot_num = SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
if args.lf:
|
||||
sense_type = chameleon_cmd.TagSenseType.LF
|
||||
sense_type = TagSenseType.LF
|
||||
else:
|
||||
sense_type = chameleon_cmd.TagSenseType.HF
|
||||
sense_type = TagSenseType.HF
|
||||
if args.name is not None:
|
||||
name: str = args.name
|
||||
encoded_name = name.encode(encoding="utf8")
|
||||
@@ -1687,11 +1689,11 @@ class HWSlotOpenAll(DeviceRequiredUnit):
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
# what type you need set to default?
|
||||
hf_type = chameleon_cmd.TagSpecificType.MIFARE_1024
|
||||
lf_type = chameleon_cmd.TagSpecificType.EM410X
|
||||
hf_type = TagSpecificType.MIFARE_1024
|
||||
lf_type = TagSpecificType.EM410X
|
||||
|
||||
# set all slot
|
||||
for slot in chameleon_cmd.SlotNumber:
|
||||
for slot in SlotNumber:
|
||||
print(f' Slot {slot} setting...')
|
||||
# first to set tag type
|
||||
self.cmd.set_slot_tag_type(slot, hf_type)
|
||||
@@ -1700,8 +1702,8 @@ class HWSlotOpenAll(DeviceRequiredUnit):
|
||||
self.cmd.set_slot_data_default(slot, hf_type)
|
||||
self.cmd.set_slot_data_default(slot, lf_type)
|
||||
# finally, we can enable this slot.
|
||||
self.cmd.set_slot_enable(slot, chameleon_cmd.TagSenseType.HF, True)
|
||||
self.cmd.set_slot_enable(slot, chameleon_cmd.TagSenseType.LF, True)
|
||||
self.cmd.set_slot_enable(slot, TagSenseType.HF, True)
|
||||
self.cmd.set_slot_enable(slot, TagSenseType.LF, True)
|
||||
print(f' Slot {slot} setting done.')
|
||||
|
||||
# update config and save to flash
|
||||
@@ -1734,7 +1736,7 @@ class HWSettingsAnimation(DeviceRequiredUnit):
|
||||
def args_parser(self) -> ArgumentParserNoExit:
|
||||
parser = ArgumentParserNoExit()
|
||||
parser.description = 'Get or change current animation mode value'
|
||||
mode_names = [m.name for m in list(chameleon_cmd.AnimationMode)]
|
||||
mode_names = [m.name for m in list(AnimationMode)]
|
||||
help_str = "Mode: " + ", ".join(mode_names)
|
||||
parser.add_argument('-m', '--mode', type=str, required=False,
|
||||
help=help_str, metavar="MODE", choices=mode_names)
|
||||
@@ -1742,12 +1744,12 @@ class HWSettingsAnimation(DeviceRequiredUnit):
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
if args.mode is not None:
|
||||
mode = chameleon_cmd.AnimationMode[args.mode]
|
||||
mode = AnimationMode[args.mode]
|
||||
self.cmd.set_animation_mode(mode)
|
||||
print("Animation mode change success.")
|
||||
print(f"{CY}Do not forget to store your settings in flash!{C0}")
|
||||
else:
|
||||
print(chameleon_cmd.AnimationMode(self.cmd.get_animation_mode()))
|
||||
print(AnimationMode(self.cmd.get_animation_mode()))
|
||||
|
||||
|
||||
@hw_settings.command('bleclearbonds')
|
||||
@@ -1852,8 +1854,8 @@ class HWButtonSettingsGet(DeviceRequiredUnit):
|
||||
duration_group = parser.add_mutually_exclusive_group()
|
||||
duration_group.add_argument('-s', '--short', action='store_true', help="Short-press (default)")
|
||||
duration_group.add_argument('-l', '--long', action='store_true', help="Long-press")
|
||||
function_names = [f.name for f in list(chameleon_cmd.ButtonPressFunction)]
|
||||
function_descs = [f"{f.name} ({f})" for f in list(chameleon_cmd.ButtonPressFunction)]
|
||||
function_names = [f.name for f in list(ButtonPressFunction)]
|
||||
function_descs = [f"{f.name} ({f})" for f in list(ButtonPressFunction)]
|
||||
help_str = "Function: " + ", ".join(function_descs)
|
||||
parser.add_argument('-f', '--function', type=str, required=False,
|
||||
help=help_str, metavar="FUNCTION", choices=function_names)
|
||||
@@ -1861,14 +1863,14 @@ class HWButtonSettingsGet(DeviceRequiredUnit):
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
if args.function is not None:
|
||||
function = chameleon_cmd.ButtonPressFunction[args.function]
|
||||
function = ButtonPressFunction[args.function]
|
||||
if not args.a and not args.b:
|
||||
print(f"{CR}You must specify which button you want to change{C0}")
|
||||
return
|
||||
if args.a:
|
||||
button = chameleon_cmd.ButtonType.A
|
||||
button = ButtonType.A
|
||||
else:
|
||||
button = chameleon_cmd.ButtonType.B
|
||||
button = ButtonType.B
|
||||
if args.long:
|
||||
self.cmd.set_long_button_press_config(button, function)
|
||||
else:
|
||||
@@ -1878,19 +1880,19 @@ class HWButtonSettingsGet(DeviceRequiredUnit):
|
||||
print(f"{CY}Do not forget to store your settings in flash!{C0}")
|
||||
else:
|
||||
if args.a:
|
||||
button_list = [chameleon_cmd.ButtonType.A]
|
||||
button_list = [ButtonType.A]
|
||||
elif args.b:
|
||||
button_list = [chameleon_cmd.ButtonType.B]
|
||||
button_list = [ButtonType.B]
|
||||
else:
|
||||
button_list = list(chameleon_cmd.ButtonType)
|
||||
button_list = list(ButtonType)
|
||||
for button in button_list:
|
||||
if not args.long:
|
||||
resp = self.cmd.get_button_press_config(button)
|
||||
button_fn = chameleon_cmd.ButtonPressFunction(resp)
|
||||
button_fn = ButtonPressFunction(resp)
|
||||
print(f" - {CG}{button.name} short{C0}: {button_fn}")
|
||||
if not args.short:
|
||||
resp_long = self.cmd.get_long_button_press_config(button)
|
||||
button_long_fn = chameleon_cmd.ButtonPressFunction(resp_long)
|
||||
button_long_fn = ButtonPressFunction(resp_long)
|
||||
print(f" - {CG}{button.name} long {C0}: {button_long_fn}")
|
||||
print("")
|
||||
|
||||
@@ -1965,7 +1967,7 @@ class HWRaw(DeviceRequiredUnit):
|
||||
def args_parser(self) -> ArgumentParserNoExit:
|
||||
parser = ArgumentParserNoExit()
|
||||
parser.description = 'Send raw command'
|
||||
cmd_names = sorted([c.name for c in list(chameleon_cmd.Command)])
|
||||
cmd_names = sorted([c.name for c in list(Command)])
|
||||
help_str = "Command: " + ", ".join(cmd_names)
|
||||
command_group = parser.add_mutually_exclusive_group(required=True)
|
||||
command_group.add_argument('-c', '--command', type=str, metavar="COMMAND", help=help_str, choices=cmd_names)
|
||||
@@ -1976,7 +1978,7 @@ class HWRaw(DeviceRequiredUnit):
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
if args.command is not None:
|
||||
command = chameleon_cmd.Command[args.command]
|
||||
command = Command[args.command]
|
||||
else:
|
||||
# We accept not-yet-known command ids as "hw raw" is meant for debugging
|
||||
command = args.num_command
|
||||
@@ -1984,7 +1986,7 @@ class HWRaw(DeviceRequiredUnit):
|
||||
command, data=bytes.fromhex(args.data), status=0x0, timeout=args.timeout)
|
||||
print(" - Received:")
|
||||
try:
|
||||
command = chameleon_cmd.Command(response.cmd)
|
||||
command = Command(response.cmd)
|
||||
print(f" Command: {response.cmd} {command.name}")
|
||||
except ValueError:
|
||||
print(f" Command: {response.cmd} (unknown)")
|
||||
|
||||
@@ -1,377 +1,15 @@
|
||||
import enum
|
||||
import struct
|
||||
import ctypes
|
||||
|
||||
import chameleon_com
|
||||
import chameleon_status
|
||||
from chameleon_utils import expect_response
|
||||
from chameleon_enum import Command, SlotNumber, TagSenseType, TagSpecificType
|
||||
from chameleon_enum import MifareClassicDarksideStatus
|
||||
from chameleon_enum import ButtonType, ButtonPressFunction
|
||||
|
||||
CURRENT_VERSION_SETTINGS = 5
|
||||
|
||||
@enum.unique
|
||||
class Command(enum.IntEnum):
|
||||
GET_APP_VERSION = 1000
|
||||
CHANGE_DEVICE_MODE = 1001
|
||||
GET_DEVICE_MODE = 1002
|
||||
SET_ACTIVE_SLOT = 1003
|
||||
SET_SLOT_TAG_TYPE = 1004
|
||||
SET_SLOT_DATA_DEFAULT = 1005
|
||||
SET_SLOT_ENABLE = 1006
|
||||
|
||||
SET_SLOT_TAG_NICK = 1007
|
||||
GET_SLOT_TAG_NICK = 1008
|
||||
|
||||
SLOT_DATA_CONFIG_SAVE = 1009
|
||||
|
||||
ENTER_BOOTLOADER = 1010
|
||||
GET_DEVICE_CHIP_ID = 1011
|
||||
GET_DEVICE_ADDRESS = 1012
|
||||
|
||||
SAVE_SETTINGS = 1013
|
||||
RESET_SETTINGS = 1014
|
||||
SET_ANIMATION_MODE = 1015
|
||||
GET_ANIMATION_MODE = 1016
|
||||
|
||||
GET_GIT_VERSION = 1017
|
||||
|
||||
GET_ACTIVE_SLOT = 1018
|
||||
GET_SLOT_INFO = 1019
|
||||
|
||||
WIPE_FDS = 1020
|
||||
|
||||
DELETE_SLOT_TAG_NICK = 1021
|
||||
|
||||
GET_ENABLED_SLOTS = 1023
|
||||
DELETE_SLOT_SENSE_TYPE = 1024
|
||||
|
||||
GET_BATTERY_INFO = 1025
|
||||
|
||||
GET_BUTTON_PRESS_CONFIG = 1026
|
||||
SET_BUTTON_PRESS_CONFIG = 1027
|
||||
|
||||
GET_LONG_BUTTON_PRESS_CONFIG = 1028
|
||||
SET_LONG_BUTTON_PRESS_CONFIG = 1029
|
||||
|
||||
SET_BLE_PAIRING_KEY = 1030
|
||||
GET_BLE_PAIRING_KEY = 1031
|
||||
DELETE_ALL_BLE_BONDS = 1032
|
||||
|
||||
GET_DEVICE_MODEL = 1033
|
||||
# FIXME: implemented but unused in CLI commands
|
||||
GET_DEVICE_SETTINGS = 1034
|
||||
GET_DEVICE_CAPABILITIES = 1035
|
||||
GET_BLE_PAIRING_ENABLE = 1036
|
||||
SET_BLE_PAIRING_ENABLE = 1037
|
||||
|
||||
HF14A_SCAN = 2000
|
||||
MF1_DETECT_SUPPORT = 2001
|
||||
MF1_DETECT_PRNG = 2002
|
||||
MF1_STATIC_NESTED_ACQUIRE = 2003
|
||||
MF1_DARKSIDE_ACQUIRE = 2004
|
||||
MF1_DETECT_NT_DIST = 2005
|
||||
MF1_NESTED_ACQUIRE = 2006
|
||||
MF1_AUTH_ONE_KEY_BLOCK = 2007
|
||||
MF1_READ_ONE_BLOCK = 2008
|
||||
MF1_WRITE_ONE_BLOCK = 2009
|
||||
HF14A_RAW = 2010
|
||||
|
||||
EM410X_SCAN = 3000
|
||||
EM410X_WRITE_TO_T55XX = 3001
|
||||
|
||||
MF1_WRITE_EMU_BLOCK_DATA = 4000
|
||||
HF14A_SET_ANTI_COLL_DATA = 4001
|
||||
MF1_SET_DETECTION_ENABLE = 4004
|
||||
MF1_GET_DETECTION_COUNT = 4005
|
||||
MF1_GET_DETECTION_LOG = 4006
|
||||
# FIXME: not implemented
|
||||
MF1_GET_DETECTION_ENABLE = 4007
|
||||
MF1_READ_EMU_BLOCK_DATA = 4008
|
||||
MF1_GET_EMULATOR_CONFIG = 4009
|
||||
# FIXME: not implemented
|
||||
MF1_GET_GEN1A_MODE = 4010
|
||||
MF1_SET_GEN1A_MODE = 4011
|
||||
# FIXME: not implemented
|
||||
MF1_GET_GEN2_MODE = 4012
|
||||
MF1_SET_GEN2_MODE = 4013
|
||||
# FIXME: not implemented
|
||||
MF1_GET_BLOCK_ANTI_COLL_MODE = 4014
|
||||
MF1_SET_BLOCK_ANTI_COLL_MODE = 4015
|
||||
# FIXME: not implemented
|
||||
MF1_GET_WRITE_MODE = 4016
|
||||
MF1_SET_WRITE_MODE = 4017
|
||||
HF14A_GET_ANTI_COLL_DATA = 4018
|
||||
|
||||
EM410X_SET_EMU_ID = 5000
|
||||
EM410X_GET_EMU_ID = 5001
|
||||
|
||||
|
||||
@enum.unique
|
||||
class SlotNumber(enum.IntEnum):
|
||||
SLOT_1 = 1
|
||||
SLOT_2 = 2
|
||||
SLOT_3 = 3
|
||||
SLOT_4 = 4
|
||||
SLOT_5 = 5
|
||||
SLOT_6 = 6
|
||||
SLOT_7 = 7
|
||||
SLOT_8 = 8
|
||||
|
||||
@staticmethod
|
||||
def to_fw(index: int): # can be int or SlotNumber
|
||||
# SlotNumber() will raise error for us if index not in slot range
|
||||
return SlotNumber(index).value - 1
|
||||
|
||||
@staticmethod
|
||||
def from_fw(index: int):
|
||||
# SlotNumber() will raise error for us if index not in fw range
|
||||
return SlotNumber(index + 1)
|
||||
|
||||
|
||||
@enum.unique
|
||||
class TagSenseType(enum.IntEnum):
|
||||
# Unknown
|
||||
UNDEFINED = 0
|
||||
# 125 kHz
|
||||
LF = 1
|
||||
# 13.56 MHz
|
||||
HF = 2
|
||||
|
||||
|
||||
@enum.unique
|
||||
class TagSpecificType(enum.IntEnum):
|
||||
UNDEFINED = 0
|
||||
|
||||
# old HL/LF common types, slots using these ones need to be migrated first
|
||||
OLD_EM410X = 1
|
||||
OLD_MIFARE_Mini = 2
|
||||
OLD_MIFARE_1024 = 3
|
||||
OLD_MIFARE_2048 = 4
|
||||
OLD_MIFARE_4096 = 5
|
||||
OLD_NTAG_213 = 6
|
||||
OLD_NTAG_215 = 7
|
||||
OLD_NTAG_216 = 8
|
||||
OLD_TAG_TYPES_END = 9
|
||||
|
||||
###### LF ######
|
||||
|
||||
#### ASK Tag-Talk-First 100 ####
|
||||
# EM410x
|
||||
EM410X = 100
|
||||
# FDX-B
|
||||
# securakey
|
||||
# gallagher
|
||||
# PAC/Stanley
|
||||
# Presco
|
||||
# Visa2000
|
||||
# Viking
|
||||
# Noralsy
|
||||
# Jablotron
|
||||
|
||||
#### FSK Tag-Talk-First 200 ####
|
||||
# HID Prox
|
||||
# ioProx
|
||||
# AWID
|
||||
# Paradox
|
||||
|
||||
#### PSK Tag-Talk-First 300 ####
|
||||
# Indala
|
||||
# Keri
|
||||
# NexWatch
|
||||
|
||||
#### Reader-Talk-First 400 ####
|
||||
# T5577
|
||||
# EM4x05/4x69
|
||||
# EM4x50/4x70
|
||||
# Hitag series
|
||||
|
||||
TAG_TYPES_LF_END = 999
|
||||
|
||||
###### HF ######
|
||||
|
||||
#### MIFARE Classic series 1000 ####
|
||||
MIFARE_Mini = 1000
|
||||
MIFARE_1024 = 1001
|
||||
MIFARE_2048 = 1002
|
||||
MIFARE_4096 = 1003
|
||||
#### MFUL / NTAG series 1100 ####
|
||||
NTAG_213 = 1100
|
||||
NTAG_215 = 1101
|
||||
NTAG_216 = 1102
|
||||
#### MIFARE Plus series 1200 ####
|
||||
#### DESFire series 1300 ####
|
||||
|
||||
#### ST25TA series 2000 ####
|
||||
|
||||
#### HF14A-4 series 3000 ####
|
||||
|
||||
@staticmethod
|
||||
def list(exclude_meta=True):
|
||||
return [t for t in TagSpecificType
|
||||
if (t > TagSpecificType.OLD_TAG_TYPES_END and
|
||||
t != TagSpecificType.TAG_TYPES_LF_END)
|
||||
or not exclude_meta]
|
||||
|
||||
@staticmethod
|
||||
def list_hf():
|
||||
return [t for t in TagSpecificType.list()
|
||||
if (t > TagSpecificType.TAG_TYPES_LF_END)]
|
||||
|
||||
@staticmethod
|
||||
def list_lf():
|
||||
return [t for t in TagSpecificType.list()
|
||||
if (TagSpecificType.UNDEFINED < t < TagSpecificType.TAG_TYPES_LF_END)]
|
||||
|
||||
def __str__(self):
|
||||
if self == TagSpecificType.UNDEFINED:
|
||||
return "Undefined"
|
||||
elif self == TagSpecificType.EM410X:
|
||||
return "EM410X"
|
||||
elif self == TagSpecificType.MIFARE_Mini:
|
||||
return "Mifare Mini"
|
||||
elif self == TagSpecificType.MIFARE_1024:
|
||||
return "Mifare Classic 1k"
|
||||
elif self == TagSpecificType.MIFARE_2048:
|
||||
return "Mifare Classic 2k"
|
||||
elif self == TagSpecificType.MIFARE_4096:
|
||||
return "Mifare Classic 4k"
|
||||
elif self == TagSpecificType.NTAG_213:
|
||||
return "NTAG 213"
|
||||
elif self == TagSpecificType.NTAG_215:
|
||||
return "NTAG 215"
|
||||
elif self == TagSpecificType.NTAG_216:
|
||||
return "NTAG 216"
|
||||
elif self < TagSpecificType.OLD_TAG_TYPES_END:
|
||||
return "Old tag type, must be migrated! Upgrade fw!"
|
||||
return "Invalid"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class MifareClassicWriteMode(enum.IntEnum):
|
||||
# Normal write
|
||||
NORMAL = 0
|
||||
# Send NACK to write attempts
|
||||
DENIED = 1
|
||||
# Acknowledge writes, but don't remember contents
|
||||
DECEIVE = 2
|
||||
# Store data to RAM, but not to ROM
|
||||
SHADOW = 3
|
||||
# Shadow requested, will be changed to SHADOW and stored to ROM
|
||||
SHADOW_REQ = 4
|
||||
|
||||
@staticmethod
|
||||
def list(exclude_meta=True):
|
||||
return [m for m in MifareClassicWriteMode
|
||||
if m != MifareClassicWriteMode.SHADOW_REQ
|
||||
or not exclude_meta]
|
||||
|
||||
def __str__(self):
|
||||
if self == MifareClassicWriteMode.NORMAL:
|
||||
return "Normal"
|
||||
elif self == MifareClassicWriteMode.DENIED:
|
||||
return "Denied"
|
||||
elif self == MifareClassicWriteMode.DECEIVE:
|
||||
return "Deceive"
|
||||
elif self == MifareClassicWriteMode.SHADOW:
|
||||
return "Shadow"
|
||||
elif self == MifareClassicWriteMode.SHADOW_REQ:
|
||||
return "Shadow requested"
|
||||
return "None"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class MifareClassicPrngType(enum.IntEnum):
|
||||
# the random number of the card response is fixed
|
||||
STATIC = 0
|
||||
# the random number of the card response is weak
|
||||
WEAK = 1
|
||||
# the random number of the card response is unpredictable
|
||||
HARD = 2
|
||||
|
||||
def __str__(self):
|
||||
if self == MifareClassicPrngType.STATIC:
|
||||
return "Static"
|
||||
elif self == MifareClassicPrngType.WEAK:
|
||||
return "Weak"
|
||||
elif self == MifareClassicPrngType.HARD:
|
||||
return "Hard"
|
||||
return "None"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class MifareClassicDarksideStatus(enum.IntEnum):
|
||||
OK = 0
|
||||
# Darkside can't fix NT (PRNG is unpredictable)
|
||||
CANT_FIX_NT = 1
|
||||
# Darkside try to recover a default key
|
||||
LUCKY_AUTH_OK = 2
|
||||
# Darkside can't get tag response enc(nak)
|
||||
NO_NAK_SENT = 3
|
||||
# Darkside running, can't change tag
|
||||
TAG_CHANGED = 4
|
||||
|
||||
def __str__(self):
|
||||
if self == MifareClassicDarksideStatus.OK:
|
||||
return "Success"
|
||||
elif self == MifareClassicDarksideStatus.CANT_FIX_NT:
|
||||
return "Cannot fix NT (unpredictable PRNG)"
|
||||
elif self == MifareClassicDarksideStatus.LUCKY_AUTH_OK:
|
||||
return "Try to recover a default key"
|
||||
elif self == MifareClassicDarksideStatus.NO_NAK_SENT:
|
||||
return "Cannot get tag response enc(nak)"
|
||||
elif self == MifareClassicDarksideStatus.TAG_CHANGED:
|
||||
return "Tag changed during attack"
|
||||
return "None"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class AnimationMode(enum.IntEnum):
|
||||
FULL = 0
|
||||
MINIMAL = 1
|
||||
NONE = 2
|
||||
|
||||
def __str__(self):
|
||||
if self == AnimationMode.FULL:
|
||||
return "Full animation"
|
||||
elif self == AnimationMode.MINIMAL:
|
||||
return "Minimal animation"
|
||||
elif self == AnimationMode.NONE:
|
||||
return "No animation"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class ButtonType(enum.IntEnum):
|
||||
A = ord('A')
|
||||
B = ord('B')
|
||||
|
||||
|
||||
@enum.unique
|
||||
class MfcKeyType(enum.IntEnum):
|
||||
A = 0x60
|
||||
B = 0x61
|
||||
|
||||
|
||||
@enum.unique
|
||||
class ButtonPressFunction(enum.IntEnum):
|
||||
NONE = 0
|
||||
NEXTSLOT = 1
|
||||
PREVSLOT = 2
|
||||
CLONE = 3
|
||||
BATTERY = 4
|
||||
|
||||
def __str__(self):
|
||||
if self == ButtonPressFunction.NONE:
|
||||
return "No Function"
|
||||
elif self == ButtonPressFunction.NEXTSLOT:
|
||||
return "Select next slot"
|
||||
elif self == ButtonPressFunction.PREVSLOT:
|
||||
return "Select previous slot"
|
||||
elif self == ButtonPressFunction.CLONE:
|
||||
return "Read then simulate the ID/UID card number"
|
||||
elif self == ButtonPressFunction.BATTERY:
|
||||
return "Show Battery Level"
|
||||
return "None"
|
||||
|
||||
|
||||
class ChameleonCMD:
|
||||
"""
|
||||
Chameleon cmd function
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
import enum
|
||||
|
||||
@enum.unique
|
||||
class Command(enum.IntEnum):
|
||||
GET_APP_VERSION = 1000
|
||||
CHANGE_DEVICE_MODE = 1001
|
||||
GET_DEVICE_MODE = 1002
|
||||
SET_ACTIVE_SLOT = 1003
|
||||
SET_SLOT_TAG_TYPE = 1004
|
||||
SET_SLOT_DATA_DEFAULT = 1005
|
||||
SET_SLOT_ENABLE = 1006
|
||||
|
||||
SET_SLOT_TAG_NICK = 1007
|
||||
GET_SLOT_TAG_NICK = 1008
|
||||
|
||||
SLOT_DATA_CONFIG_SAVE = 1009
|
||||
|
||||
ENTER_BOOTLOADER = 1010
|
||||
GET_DEVICE_CHIP_ID = 1011
|
||||
GET_DEVICE_ADDRESS = 1012
|
||||
|
||||
SAVE_SETTINGS = 1013
|
||||
RESET_SETTINGS = 1014
|
||||
SET_ANIMATION_MODE = 1015
|
||||
GET_ANIMATION_MODE = 1016
|
||||
|
||||
GET_GIT_VERSION = 1017
|
||||
|
||||
GET_ACTIVE_SLOT = 1018
|
||||
GET_SLOT_INFO = 1019
|
||||
|
||||
WIPE_FDS = 1020
|
||||
|
||||
DELETE_SLOT_TAG_NICK = 1021
|
||||
|
||||
GET_ENABLED_SLOTS = 1023
|
||||
DELETE_SLOT_SENSE_TYPE = 1024
|
||||
|
||||
GET_BATTERY_INFO = 1025
|
||||
|
||||
GET_BUTTON_PRESS_CONFIG = 1026
|
||||
SET_BUTTON_PRESS_CONFIG = 1027
|
||||
|
||||
GET_LONG_BUTTON_PRESS_CONFIG = 1028
|
||||
SET_LONG_BUTTON_PRESS_CONFIG = 1029
|
||||
|
||||
SET_BLE_PAIRING_KEY = 1030
|
||||
GET_BLE_PAIRING_KEY = 1031
|
||||
DELETE_ALL_BLE_BONDS = 1032
|
||||
|
||||
GET_DEVICE_MODEL = 1033
|
||||
# FIXME: implemented but unused in CLI commands
|
||||
GET_DEVICE_SETTINGS = 1034
|
||||
GET_DEVICE_CAPABILITIES = 1035
|
||||
GET_BLE_PAIRING_ENABLE = 1036
|
||||
SET_BLE_PAIRING_ENABLE = 1037
|
||||
|
||||
HF14A_SCAN = 2000
|
||||
MF1_DETECT_SUPPORT = 2001
|
||||
MF1_DETECT_PRNG = 2002
|
||||
MF1_STATIC_NESTED_ACQUIRE = 2003
|
||||
MF1_DARKSIDE_ACQUIRE = 2004
|
||||
MF1_DETECT_NT_DIST = 2005
|
||||
MF1_NESTED_ACQUIRE = 2006
|
||||
MF1_AUTH_ONE_KEY_BLOCK = 2007
|
||||
MF1_READ_ONE_BLOCK = 2008
|
||||
MF1_WRITE_ONE_BLOCK = 2009
|
||||
HF14A_RAW = 2010
|
||||
|
||||
EM410X_SCAN = 3000
|
||||
EM410X_WRITE_TO_T55XX = 3001
|
||||
|
||||
MF1_WRITE_EMU_BLOCK_DATA = 4000
|
||||
HF14A_SET_ANTI_COLL_DATA = 4001
|
||||
MF1_SET_DETECTION_ENABLE = 4004
|
||||
MF1_GET_DETECTION_COUNT = 4005
|
||||
MF1_GET_DETECTION_LOG = 4006
|
||||
# FIXME: not implemented
|
||||
MF1_GET_DETECTION_ENABLE = 4007
|
||||
MF1_READ_EMU_BLOCK_DATA = 4008
|
||||
MF1_GET_EMULATOR_CONFIG = 4009
|
||||
# FIXME: not implemented
|
||||
MF1_GET_GEN1A_MODE = 4010
|
||||
MF1_SET_GEN1A_MODE = 4011
|
||||
# FIXME: not implemented
|
||||
MF1_GET_GEN2_MODE = 4012
|
||||
MF1_SET_GEN2_MODE = 4013
|
||||
# FIXME: not implemented
|
||||
MF1_GET_BLOCK_ANTI_COLL_MODE = 4014
|
||||
MF1_SET_BLOCK_ANTI_COLL_MODE = 4015
|
||||
# FIXME: not implemented
|
||||
MF1_GET_WRITE_MODE = 4016
|
||||
MF1_SET_WRITE_MODE = 4017
|
||||
HF14A_GET_ANTI_COLL_DATA = 4018
|
||||
|
||||
EM410X_SET_EMU_ID = 5000
|
||||
EM410X_GET_EMU_ID = 5001
|
||||
|
||||
|
||||
@enum.unique
|
||||
class SlotNumber(enum.IntEnum):
|
||||
SLOT_1 = 1
|
||||
SLOT_2 = 2
|
||||
SLOT_3 = 3
|
||||
SLOT_4 = 4
|
||||
SLOT_5 = 5
|
||||
SLOT_6 = 6
|
||||
SLOT_7 = 7
|
||||
SLOT_8 = 8
|
||||
|
||||
@staticmethod
|
||||
def to_fw(index: int): # can be int or SlotNumber
|
||||
# SlotNumber() will raise error for us if index not in slot range
|
||||
return SlotNumber(index).value - 1
|
||||
|
||||
@staticmethod
|
||||
def from_fw(index: int):
|
||||
# SlotNumber() will raise error for us if index not in fw range
|
||||
return SlotNumber(index + 1)
|
||||
|
||||
|
||||
@enum.unique
|
||||
class TagSenseType(enum.IntEnum):
|
||||
# Unknown
|
||||
UNDEFINED = 0
|
||||
# 125 kHz
|
||||
LF = 1
|
||||
# 13.56 MHz
|
||||
HF = 2
|
||||
|
||||
|
||||
@enum.unique
|
||||
class TagSpecificType(enum.IntEnum):
|
||||
UNDEFINED = 0
|
||||
|
||||
# old HL/LF common types, slots using these ones need to be migrated first
|
||||
OLD_EM410X = 1
|
||||
OLD_MIFARE_Mini = 2
|
||||
OLD_MIFARE_1024 = 3
|
||||
OLD_MIFARE_2048 = 4
|
||||
OLD_MIFARE_4096 = 5
|
||||
OLD_NTAG_213 = 6
|
||||
OLD_NTAG_215 = 7
|
||||
OLD_NTAG_216 = 8
|
||||
OLD_TAG_TYPES_END = 9
|
||||
|
||||
###### LF ######
|
||||
|
||||
#### ASK Tag-Talk-First 100 ####
|
||||
# EM410x
|
||||
EM410X = 100
|
||||
# FDX-B
|
||||
# securakey
|
||||
# gallagher
|
||||
# PAC/Stanley
|
||||
# Presco
|
||||
# Visa2000
|
||||
# Viking
|
||||
# Noralsy
|
||||
# Jablotron
|
||||
|
||||
#### FSK Tag-Talk-First 200 ####
|
||||
# HID Prox
|
||||
# ioProx
|
||||
# AWID
|
||||
# Paradox
|
||||
|
||||
#### PSK Tag-Talk-First 300 ####
|
||||
# Indala
|
||||
# Keri
|
||||
# NexWatch
|
||||
|
||||
#### Reader-Talk-First 400 ####
|
||||
# T5577
|
||||
# EM4x05/4x69
|
||||
# EM4x50/4x70
|
||||
# Hitag series
|
||||
|
||||
TAG_TYPES_LF_END = 999
|
||||
|
||||
###### HF ######
|
||||
|
||||
#### MIFARE Classic series 1000 ####
|
||||
MIFARE_Mini = 1000
|
||||
MIFARE_1024 = 1001
|
||||
MIFARE_2048 = 1002
|
||||
MIFARE_4096 = 1003
|
||||
#### MFUL / NTAG series 1100 ####
|
||||
NTAG_213 = 1100
|
||||
NTAG_215 = 1101
|
||||
NTAG_216 = 1102
|
||||
#### MIFARE Plus series 1200 ####
|
||||
#### DESFire series 1300 ####
|
||||
|
||||
#### ST25TA series 2000 ####
|
||||
|
||||
#### HF14A-4 series 3000 ####
|
||||
|
||||
@staticmethod
|
||||
def list(exclude_meta=True):
|
||||
return [t for t in TagSpecificType
|
||||
if (t > TagSpecificType.OLD_TAG_TYPES_END and
|
||||
t != TagSpecificType.TAG_TYPES_LF_END)
|
||||
or not exclude_meta]
|
||||
|
||||
@staticmethod
|
||||
def list_hf():
|
||||
return [t for t in TagSpecificType.list()
|
||||
if (t > TagSpecificType.TAG_TYPES_LF_END)]
|
||||
|
||||
@staticmethod
|
||||
def list_lf():
|
||||
return [t for t in TagSpecificType.list()
|
||||
if (TagSpecificType.UNDEFINED < t < TagSpecificType.TAG_TYPES_LF_END)]
|
||||
|
||||
def __str__(self):
|
||||
if self == TagSpecificType.UNDEFINED:
|
||||
return "Undefined"
|
||||
elif self == TagSpecificType.EM410X:
|
||||
return "EM410X"
|
||||
elif self == TagSpecificType.MIFARE_Mini:
|
||||
return "Mifare Mini"
|
||||
elif self == TagSpecificType.MIFARE_1024:
|
||||
return "Mifare Classic 1k"
|
||||
elif self == TagSpecificType.MIFARE_2048:
|
||||
return "Mifare Classic 2k"
|
||||
elif self == TagSpecificType.MIFARE_4096:
|
||||
return "Mifare Classic 4k"
|
||||
elif self == TagSpecificType.NTAG_213:
|
||||
return "NTAG 213"
|
||||
elif self == TagSpecificType.NTAG_215:
|
||||
return "NTAG 215"
|
||||
elif self == TagSpecificType.NTAG_216:
|
||||
return "NTAG 216"
|
||||
elif self < TagSpecificType.OLD_TAG_TYPES_END:
|
||||
return "Old tag type, must be migrated! Upgrade fw!"
|
||||
return "Invalid"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class MifareClassicWriteMode(enum.IntEnum):
|
||||
# Normal write
|
||||
NORMAL = 0
|
||||
# Send NACK to write attempts
|
||||
DENIED = 1
|
||||
# Acknowledge writes, but don't remember contents
|
||||
DECEIVE = 2
|
||||
# Store data to RAM, but not to ROM
|
||||
SHADOW = 3
|
||||
# Shadow requested, will be changed to SHADOW and stored to ROM
|
||||
SHADOW_REQ = 4
|
||||
|
||||
@staticmethod
|
||||
def list(exclude_meta=True):
|
||||
return [m for m in MifareClassicWriteMode
|
||||
if m != MifareClassicWriteMode.SHADOW_REQ
|
||||
or not exclude_meta]
|
||||
|
||||
def __str__(self):
|
||||
if self == MifareClassicWriteMode.NORMAL:
|
||||
return "Normal"
|
||||
elif self == MifareClassicWriteMode.DENIED:
|
||||
return "Denied"
|
||||
elif self == MifareClassicWriteMode.DECEIVE:
|
||||
return "Deceive"
|
||||
elif self == MifareClassicWriteMode.SHADOW:
|
||||
return "Shadow"
|
||||
elif self == MifareClassicWriteMode.SHADOW_REQ:
|
||||
return "Shadow requested"
|
||||
return "None"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class MifareClassicPrngType(enum.IntEnum):
|
||||
# the random number of the card response is fixed
|
||||
STATIC = 0
|
||||
# the random number of the card response is weak
|
||||
WEAK = 1
|
||||
# the random number of the card response is unpredictable
|
||||
HARD = 2
|
||||
|
||||
def __str__(self):
|
||||
if self == MifareClassicPrngType.STATIC:
|
||||
return "Static"
|
||||
elif self == MifareClassicPrngType.WEAK:
|
||||
return "Weak"
|
||||
elif self == MifareClassicPrngType.HARD:
|
||||
return "Hard"
|
||||
return "None"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class MifareClassicDarksideStatus(enum.IntEnum):
|
||||
OK = 0
|
||||
# Darkside can't fix NT (PRNG is unpredictable)
|
||||
CANT_FIX_NT = 1
|
||||
# Darkside try to recover a default key
|
||||
LUCKY_AUTH_OK = 2
|
||||
# Darkside can't get tag response enc(nak)
|
||||
NO_NAK_SENT = 3
|
||||
# Darkside running, can't change tag
|
||||
TAG_CHANGED = 4
|
||||
|
||||
def __str__(self):
|
||||
if self == MifareClassicDarksideStatus.OK:
|
||||
return "Success"
|
||||
elif self == MifareClassicDarksideStatus.CANT_FIX_NT:
|
||||
return "Cannot fix NT (unpredictable PRNG)"
|
||||
elif self == MifareClassicDarksideStatus.LUCKY_AUTH_OK:
|
||||
return "Try to recover a default key"
|
||||
elif self == MifareClassicDarksideStatus.NO_NAK_SENT:
|
||||
return "Cannot get tag response enc(nak)"
|
||||
elif self == MifareClassicDarksideStatus.TAG_CHANGED:
|
||||
return "Tag changed during attack"
|
||||
return "None"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class AnimationMode(enum.IntEnum):
|
||||
FULL = 0
|
||||
MINIMAL = 1
|
||||
NONE = 2
|
||||
|
||||
def __str__(self):
|
||||
if self == AnimationMode.FULL:
|
||||
return "Full animation"
|
||||
elif self == AnimationMode.MINIMAL:
|
||||
return "Minimal animation"
|
||||
elif self == AnimationMode.NONE:
|
||||
return "No animation"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class ButtonType(enum.IntEnum):
|
||||
A = ord('A')
|
||||
B = ord('B')
|
||||
|
||||
|
||||
@enum.unique
|
||||
class MfcKeyType(enum.IntEnum):
|
||||
A = 0x60
|
||||
B = 0x61
|
||||
|
||||
|
||||
@enum.unique
|
||||
class ButtonPressFunction(enum.IntEnum):
|
||||
NONE = 0
|
||||
NEXTSLOT = 1
|
||||
PREVSLOT = 2
|
||||
CLONE = 3
|
||||
BATTERY = 4
|
||||
|
||||
def __str__(self):
|
||||
if self == ButtonPressFunction.NONE:
|
||||
return "No Function"
|
||||
elif self == ButtonPressFunction.NEXTSLOT:
|
||||
return "Select next slot"
|
||||
elif self == ButtonPressFunction.PREVSLOT:
|
||||
return "Select previous slot"
|
||||
elif self == ButtonPressFunction.CLONE:
|
||||
return "Read then simulate the ID/UID card number"
|
||||
elif self == ButtonPressFunction.BATTERY:
|
||||
return "Show Battery Level"
|
||||
return "None"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user