cli: metavar, simplify enums, replace tag types int by keywords

This commit is contained in:
Philippe Teuwen
2023-10-07 23:54:13 +02:00
parent 0c6abbea9d
commit 3aa73a2def
2 changed files with 94 additions and 104 deletions
+48 -51
View File
@@ -46,6 +46,7 @@ else:
# from source
default_cwd = str(Path(__file__).parent.parent / "bin")
class BaseCLIUnit:
def __init__(self):
@@ -384,12 +385,12 @@ class HFMFNested(ReaderRequiredUnit):
parser.description = 'Mifare Classic nested recover key'
parser.add_argument('-o', '--one', action='store_true', default=False,
help="one sector key recovery. Use block 0 Key A to find block 4 Key A")
parser.add_argument('--block-known', type=int, required=True, metavar="decimal",
parser.add_argument('--block-known', type=int, required=True, metavar="<dec>",
help="The block where the key of the card is known")
parser.add_argument('--type-known', type=str, required=True, choices=type_choices,
help="The key type of the tag")
parser.add_argument('--key-known', type=str, required=True, metavar="hex", help="tag sector key")
parser.add_argument('--block-target', type=int, metavar="decimal",
parser.add_argument('--key-known', type=str, required=True, metavar="<hex>", help="tag sector key")
parser.add_argument('--block-target', type=int, metavar="<dec>",
help="The key of the target block to recover")
parser.add_argument('--type-target', type=str, choices=type_choices,
help="The type of the target block to recover")
@@ -584,11 +585,11 @@ class BaseMF1AuthOpera(ReaderRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit:
type_choices = ['A', 'B', 'a', 'b']
parser = ArgumentParserNoExit()
parser.add_argument('-b', '--block', type=int, required=True, metavar="decimal",
parser.add_argument('-b', '--block', type=int, required=True, metavar="<dec>",
help="The block where the key of the card is known")
parser.add_argument('-t', '--type', type=str, required=True, choices=type_choices,
help="The key type of the tag")
parser.add_argument('-k', '--key', type=str, required=True, metavar="hex", help="tag sector key")
parser.add_argument('-k', '--key', type=str, required=True, metavar="<hex>", help="tag sector key")
return parser
def get_param(self, args):
@@ -644,8 +645,8 @@ class HFMFWRBL(BaseMF1AuthOpera):
def args_parser(self) -> ArgumentParserNoExit:
parser = super().args_parser()
parser.description = 'Mifare Classic write one block'
parser.add_argument('-d', '--data', type=str, required=True, metavar="Your block data",
help="Your block data, a hex string.")
parser.add_argument('-d', '--data', type=str, required=True, metavar="<hex>",
help="Your block data, as hex string.")
return parser
# hf mf wrbl -b 2 -t A -k FFFFFFFFFFFF -d 00000000000000000000000000000122
@@ -872,13 +873,13 @@ class HFMFERead(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.TAG_TYPE_MIFARE_Mini:
if tag_type == chameleon_cmd.TagSpecificType.MIFARE_Mini:
block_count = 20
elif tag_type == chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_1024:
elif tag_type == chameleon_cmd.TagSpecificType.MIFARE_1024:
block_count = 64
elif tag_type == chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_2048:
elif tag_type == chameleon_cmd.TagSpecificType.MIFARE_2048:
block_count = 128
elif tag_type == chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_4096:
elif tag_type == chameleon_cmd.TagSpecificType.MIFARE_4096:
block_count = 256
else:
raise Exception("Card in current slot is not Mifare Classic/Plus in SL1 mode")
@@ -946,10 +947,10 @@ class HFMFSim(DeviceRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit:
parser = ArgumentParserNoExit()
parser.description = 'Simulate a Mifare Classic card'
parser.add_argument('--uid', type=str, required=True, help="Unique ID(hex)", metavar="hex")
parser.add_argument('--atqa', type=str, required=True, help="Answer To Request(hex)", metavar="hex")
parser.add_argument('--sak', type=str, required=True, help="Select AcKnowledge(hex)", metavar="hex")
parser.add_argument('--ats', type=str, required=False, help="Answer To Select(hex)", metavar="hex")
parser.add_argument('--uid', type=str, required=True, help="Unique ID(hex)", metavar="<hex>")
parser.add_argument('--atqa', type=str, required=True, help="Answer To Request(hex)", metavar="<hex>")
parser.add_argument('--sak', type=str, required=True, help="Select AcKnowledge(hex)", metavar="<hex>")
parser.add_argument('--ats', type=str, required=False, help="Answer To Select(hex)", metavar="<hex>")
return parser
# hf mf sim --sak 08 --atqa 0400 --uid DEADBEEF
@@ -1013,7 +1014,7 @@ class HFMFURDPG(BaseMFUAuthOpera):
def args_parser(self) -> ArgumentParserNoExit:
parser = super().args_parser()
parser.description = 'MIFARE Ultralight read one page'
parser.add_argument('-p', '--page', type=int, required=True, metavar="decimal",
parser.add_argument('-p', '--page', type=int, required=True, metavar="<dec>",
help="The page where the key will be used against")
return parser
@@ -1045,9 +1046,9 @@ class HFMFUDUMP(BaseMFUAuthOpera):
def args_parser(self) -> ArgumentParserNoExit:
parser = super().args_parser()
parser.description = 'MIFARE Ultralight dump pages'
parser.add_argument('-p', '--page', type=int, required=False, metavar="decimal", default=0,
parser.add_argument('-p', '--page', type=int, required=False, metavar="<dec>", default=0,
help="Manually set number of pages to dump")
parser.add_argument('-q', '--qty', type=int, required=False, metavar="decimal", default=16,
parser.add_argument('-q', '--qty', type=int, required=False, metavar="<dec>", default=16,
help="Manually set number of pages to dump")
parser.add_argument('-f', '--file', type=str, required=False, default="",
help="Specify a filename for dump file")
@@ -1110,7 +1111,7 @@ class LFEMRead(ReaderRequiredUnit):
class LFEMCardRequiredUnit(DeviceRequiredUnit):
@staticmethod
def add_card_arg(parser: ArgumentParserNoExit):
parser.add_argument("--id", type=str, required=True, help="EM410x tag id", metavar="hex")
parser.add_argument("--id", type=str, required=True, help="EM410x tag id", metavar="<hex>")
return parser
def before_exec(self, args: argparse.Namespace):
@@ -1159,7 +1160,7 @@ class SlotIndexRequireUnit(DeviceRequiredUnit):
slot_choices = [x.value for x in chameleon_cmd.SlotNumber]
help_str = f"Slot Index: {slot_choices} Default: active slot"
parser.add_argument('-s', "--slot", type=int, required=mandatory, help=help_str, metavar="number",
parser.add_argument('-s', "--slot", type=int, required=mandatory, help=help_str, metavar="<1-8>",
choices=slot_choices)
return parser
@@ -1207,8 +1208,8 @@ class HWSlotList(DeviceRequiredUnit):
if not args.short:
slotnames = []
for slot in chameleon_cmd.SlotNumber:
hfn = self.get_slot_name(slot, chameleon_cmd.TagSenseType.TAG_SENSE_HF)
lfn = self.get_slot_name(slot, chameleon_cmd.TagSenseType.TAG_SENSE_LF)
hfn = self.get_slot_name(slot, chameleon_cmd.TagSenseType.HF)
lfn = self.get_slot_name(slot, chameleon_cmd.TagSenseType.LF)
m = max(hfn['baselen'], lfn['baselen'])
maxnamelength = m if m > maxnamelength else maxnamelength
slotnames.append({'hf': hfn, 'lf': lfn})
@@ -1221,7 +1222,7 @@ class HWSlotList(DeviceRequiredUnit):
print(f' HF: '
f'{("" if args.short else slotnames[fwslot]["hf"]["name"]):{maxnamelength+1 if args.short else maxnamelength+slotnames[fwslot]["hf"]["metalen"]+1}}', end='')
print(f'{f"({CR}disabled{C0}) " if not enabled[fwslot]["hf"] else ""}', end='')
if hf_tag_type != chameleon_cmd.TagSpecificType.TAG_TYPE_UNDEFINED:
if hf_tag_type != chameleon_cmd.TagSpecificType.UNDEFINED:
print(f"{CY if enabled[fwslot]['hf'] else C0}{hf_tag_type}{C0}")
else:
print("undef")
@@ -1229,10 +1230,10 @@ class HWSlotList(DeviceRequiredUnit):
enabled[fwslot]['hf'] and \
slot == selected and \
hf_tag_type in [
chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_Mini,
chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_1024,
chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_2048,
chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_4096,
chameleon_cmd.TagSpecificType.MIFARE_Mini,
chameleon_cmd.TagSpecificType.MIFARE_1024,
chameleon_cmd.TagSpecificType.MIFARE_2048,
chameleon_cmd.TagSpecificType.MIFARE_4096,
]:
config = self.cmd.mf1_get_emulator_config()
print(' - Mifare Classic emulator settings:')
@@ -1248,7 +1249,7 @@ class HWSlotList(DeviceRequiredUnit):
print(f' LF: '
f'{("" if args.short else slotnames[fwslot]["lf"]["name"]):{maxnamelength+1 if args.short else maxnamelength+slotnames[fwslot]["lf"]["metalen"]+1}}', end='')
print(f'{f"({CR}disabled{C0}) " if not enabled[fwslot]["lf"] else ""}', end='')
if lf_tag_type != chameleon_cmd.TagSpecificType.TAG_TYPE_UNDEFINED:
if lf_tag_type != chameleon_cmd.TagSpecificType.UNDEFINED:
print(f"{CY if enabled[fwslot]['lf'] else C0}{lf_tag_type}{C0}")
else:
print("undef")
@@ -1271,13 +1272,9 @@ class HWSlotSet(SlotIndexRequireUnit):
class TagTypeRequiredUnit(DeviceRequiredUnit):
@staticmethod
def add_type_args(parser: ArgumentParserNoExit):
type_choices = chameleon_cmd.TagSpecificType.list()
help_str = ""
for t in type_choices:
help_str += f"{t.value} = {t}, "
help_str = help_str[:-2]
parser.add_argument('-t', "--type", type=int, required=True, help=help_str, metavar="number",
choices=[t.value for t in type_choices])
type_names = [t.name for t in chameleon_cmd.TagSpecificType.list()]
help_str = "Tag Type: " + ", ".join(type_names)
parser.add_argument('-t', "--type", type=str, required=True, help=help_str, metavar="TAG_TYPE", choices=type_names)
return parser
def args_parser(self) -> ArgumentParserNoExit:
@@ -1298,7 +1295,7 @@ class HWSlotType(TagTypeRequiredUnit, SlotIndexRequireUnit):
# hw slot type -t 2
def on_exec(self, args: argparse.Namespace):
tag_type = args.type
tag_type = chameleon_cmd.TagSpecificType[args.type]
if args.slot is not None:
slot_num = args.slot
else:
@@ -1322,11 +1319,11 @@ class HWDeleteSlotSense(SlotIndexRequireUnit, SenseTypeRequireUnit):
else:
slot_num = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot())
if args.lf:
sense_type = chameleon_cmd.TagSenseType.TAG_SENSE_LF
sense_type = chameleon_cmd.TagSenseType.LF
else:
sense_type = chameleon_cmd.TagSenseType.TAG_SENSE_HF
sense_type = chameleon_cmd.TagSenseType.HF
self.cmd.delete_slot_sense_type(slot_num, sense_type)
print(f' - Delete slot {slot_num} {sense_type} tag type success.')
print(f' - Delete slot {slot_num} {sense_type.name} tag type success.')
@hw_slot.command('init')
@@ -1364,12 +1361,12 @@ class HWSlotEnableSet(SlotIndexRequireUnit, SenseTypeRequireUnit):
def on_exec(self, args: argparse.Namespace):
slot_num = args.slot
if args.lf:
sense_type = chameleon_cmd.TagSenseType.TAG_SENSE_LF
sense_type = chameleon_cmd.TagSenseType.LF
else:
sense_type = chameleon_cmd.TagSenseType.TAG_SENSE_HF
sense_type = chameleon_cmd.TagSenseType.HF
enable = args.enable
self.cmd.set_slot_enable(slot_num, sense_type, enable)
print(f' - Set slot {slot_num} {sense_type} {"enable" if enable else "disable"} success.')
print(f' - Set slot {slot_num} {sense_type.name} {"enable" if enable else "disable"} success.')
@lf_em_sim.command('set')
@@ -1418,22 +1415,22 @@ class HWSlotNick(SlotIndexRequireUnit, SenseTypeRequireUnit):
else:
slot_num = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot())
if args.lf:
sense_type = chameleon_cmd.TagSenseType.TAG_SENSE_LF
sense_type = chameleon_cmd.TagSenseType.LF
else:
sense_type = chameleon_cmd.TagSenseType.TAG_SENSE_HF
sense_type = chameleon_cmd.TagSenseType.HF
if args.name is not None:
name: str = args.name
encoded_name = name.encode(encoding="utf8")
if len(encoded_name) > 32:
raise ValueError("Your tag nick name too long.")
self.cmd.set_slot_tag_nick(slot_num, sense_type, encoded_name)
print(f' - Set tag nick name for slot {slot_num} {sense_type}: {name}')
print(f' - Set tag nick name for slot {slot_num} {sense_type.name}: {name}')
elif args.delete:
self.cmd.delete_slot_tag_nick(slot_num, sense_type)
print(f' - Delete tag nick name for slot {slot_num} {sense_type}')
print(f' - Delete tag nick name for slot {slot_num} {sense_type.name}')
else:
res = self.cmd.get_slot_tag_nick(slot_num, sense_type)
print(f' - Get tag nick name for slot {slot_num} {sense_type}'
print(f' - Get tag nick name for slot {slot_num} {sense_type.name}'
f': {res.decode(encoding="utf8")}')
@hw_slot.command('update')
@@ -1459,8 +1456,8 @@ class HWSlotOpenAll(DeviceRequiredUnit):
# hw slot openall
def on_exec(self, args: argparse.Namespace):
# what type you need set to default?
hf_type = chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_1024
lf_type = chameleon_cmd.TagSpecificType.TAG_TYPE_EM410X
hf_type = chameleon_cmd.TagSpecificType.MIFARE_1024
lf_type = chameleon_cmd.TagSpecificType.EM410X
# set all slot
for slot in chameleon_cmd.SlotNumber:
@@ -1472,8 +1469,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.TAG_SENSE_HF, True)
self.cmd.set_slot_enable(slot, chameleon_cmd.TagSenseType.TAG_SENSE_LF, True)
self.cmd.set_slot_enable(slot, chameleon_cmd.TagSenseType.HF, True)
self.cmd.set_slot_enable(slot, chameleon_cmd.TagSenseType.LF, True)
print(f' Slot {slot} setting done.')
# update config and save to flash
+46 -53
View File
@@ -128,47 +128,40 @@ class SlotNumber(enum.IntEnum):
@enum.unique
class TagSenseType(enum.IntEnum):
# Unknown
TAG_SENSE_NO = 0
UNDEFINED = 0
# 125 kHz
TAG_SENSE_LF = 1
LF = 1
# 13.56 MHz
TAG_SENSE_HF = 2
HF = 2
@staticmethod
def list(exclude_unknown=True):
enum_list = list(map(int, TagSenseType))
if exclude_unknown:
enum_list.remove(TagSenseType.TAG_SENSE_NO)
enum_list.remove(TagSenseType.NO)
return enum_list
def __str__(self):
if self == TagSenseType.TAG_SENSE_LF:
return "LF"
elif self == TagSenseType.TAG_SENSE_HF:
return "HF"
return "None"
@enum.unique
class TagSpecificType(enum.IntEnum):
TAG_TYPE_UNDEFINED = 0,
UNDEFINED = 0,
# old HL/LF common types, slots using these ones need to be migrated first
OLD_TAG_TYPE_EM410X = 1,
OLD_TAG_TYPE_MIFARE_Mini = 2,
OLD_TAG_TYPE_MIFARE_1024 = 3,
OLD_TAG_TYPE_MIFARE_2048 = 4,
OLD_TAG_TYPE_MIFARE_4096 = 5,
OLD_TAG_TYPE_NTAG_213 = 6,
OLD_TAG_TYPE_NTAG_215 = 7,
OLD_TAG_TYPE_NTAG_216 = 8,
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
TAG_TYPE_EM410X = 100,
EM410X = 100,
# FDX-B
# securakey
# gallagher
@@ -201,14 +194,14 @@ class TagSpecificType(enum.IntEnum):
###### HF ######
#### MIFARE Classic series 1000 ####
TAG_TYPE_MIFARE_Mini = 1000,
TAG_TYPE_MIFARE_1024 = 1001,
TAG_TYPE_MIFARE_2048 = 1002,
TAG_TYPE_MIFARE_4096 = 1003,
MIFARE_Mini = 1000,
MIFARE_1024 = 1001,
MIFARE_2048 = 1002,
MIFARE_4096 = 1003,
#### MFUL / NTAG series 1100 ####
TAG_TYPE_NTAG_213 = 1100,
TAG_TYPE_NTAG_215 = 1101,
TAG_TYPE_NTAG_216 = 1102,
NTAG_213 = 1100,
NTAG_215 = 1101,
NTAG_216 = 1102,
#### MIFARE Plus series 1200 ####
#### DESFire series 1300 ####
@@ -231,26 +224,26 @@ class TagSpecificType(enum.IntEnum):
@staticmethod
def list_lf():
return [t for t in TagSpecificType.list()
if (TagSpecificType.TAG_TYPE_UNDEFINED < t < TagSpecificType.TAG_TYPES_LF_END)]
if (TagSpecificType.UNDEFINED < t < TagSpecificType.TAG_TYPES_LF_END)]
def __str__(self):
if self == TagSpecificType.TAG_TYPE_UNDEFINED:
if self == TagSpecificType.UNDEFINED:
return "Undefined"
elif self == TagSpecificType.TAG_TYPE_EM410X:
elif self == TagSpecificType.EM410X:
return "EM410X"
elif self == TagSpecificType.TAG_TYPE_MIFARE_Mini:
elif self == TagSpecificType.MIFARE_Mini:
return "Mifare Mini"
elif self == TagSpecificType.TAG_TYPE_MIFARE_1024:
elif self == TagSpecificType.MIFARE_1024:
return "Mifare Classic 1k"
elif self == TagSpecificType.TAG_TYPE_MIFARE_2048:
elif self == TagSpecificType.MIFARE_2048:
return "Mifare Classic 2k"
elif self == TagSpecificType.TAG_TYPE_MIFARE_4096:
elif self == TagSpecificType.MIFARE_4096:
return "Mifare Classic 4k"
elif self == TagSpecificType.TAG_TYPE_NTAG_213:
elif self == TagSpecificType.NTAG_213:
return "NTAG 213"
elif self == TagSpecificType.TAG_TYPE_NTAG_215:
elif self == TagSpecificType.NTAG_215:
return "NTAG 215"
elif self == TagSpecificType.TAG_TYPE_NTAG_216:
elif self == TagSpecificType.NTAG_216:
return "NTAG 216"
elif self < TagSpecificType.OLD_TAG_TYPES_END:
return "Old tag type, must be migrated! Upgrade fw!"
@@ -373,26 +366,26 @@ class ButtonType(enum.IntEnum):
@enum.unique
class ButtonPressFunction(enum.IntEnum):
SettingsButtonDisable = 0
SettingsButtonCycleSlot = 1
SettingsButtonCycleSlotDec = 2
SettingsButtonCloneIcUid = 3
SettingsButtonShowBattery = 4
Disable = 0
CycleSlot = 1
CycleSlotDec = 2
CloneIcUid = 3
ShowBattery = 4
@staticmethod
def list():
return list(map(int, ButtonPressFunction))
def __str__(self):
if self == ButtonPressFunction.SettingsButtonDisable:
if self == ButtonPressFunction.Disable:
return "No Function"
elif self == ButtonPressFunction.SettingsButtonCycleSlot:
elif self == ButtonPressFunction.CycleSlot:
return "Cycle Slot"
elif self == ButtonPressFunction.SettingsButtonCycleSlotDec:
elif self == ButtonPressFunction.CycleSlotDec:
return "Cycle Slot Dec"
elif self == ButtonPressFunction.SettingsButtonCloneIcUid:
elif self == ButtonPressFunction.CloneIcUid:
return "Quickly Copy Ic Uid"
elif self == ButtonPressFunction.SettingsButtonShowBattery:
elif self == ButtonPressFunction.ShowBattery:
return "Show Battery Level"
return "None"
@@ -402,16 +395,16 @@ class ButtonPressFunction(enum.IntEnum):
# get usage for button function
def usage(self):
if self == ButtonPressFunction.SettingsButtonDisable:
if self == ButtonPressFunction.Disable:
return "This button have no function"
elif self == ButtonPressFunction.SettingsButtonCycleSlot:
elif self == ButtonPressFunction.CycleSlot:
return "Card slot number sequence will increase after pressing"
elif self == ButtonPressFunction.SettingsButtonCycleSlotDec:
elif self == ButtonPressFunction.CycleSlotDec:
return "Card slot number sequence decreases after pressing"
elif self == ButtonPressFunction.SettingsButtonCloneIcUid:
elif self == ButtonPressFunction.CloneIcUid:
return ("Read the UID card number immediately after pressing, continue searching," +
"and simulate immediately after reading the card")
elif self == ButtonPressFunction.SettingsButtonShowBattery:
elif self == ButtonPressFunction.ShowBattery:
return ("Lights up slot LEDs according to battery level")
return "Unknown"