Implement new Mifare Classic emulator configuration commands, improve CLI

Slot

Won't work like this

More randomness on nested auth (for hardnested recovery) and change default GCC location

Nobody will have GCC in this default location, /usr/bin/ will target way more users

Get enabled slots command

hw slot list show disabled slots

Improve python code quality

Show Mifare Classic emulator settings in hw slot list

Implement hf mf settings to change Mifare Classic emulator settings

Update
This commit is contained in:
Foxushka
2023-08-19 20:59:39 +03:00
parent de5aa050fd
commit 151f412490
11 changed files with 564 additions and 287 deletions
+130 -1
View File
@@ -463,7 +463,7 @@ data_frame_tx_t* cmd_processor_set_mf1_anti_collision_res(uint16_t cmd, uint16_t
} else {
uint8_t uid_length = length - 3;
if (is_valid_uid_size(uid_length)) {
nfc_tag_14a_coll_res_referen_t* info = get_miafre_coll_res();
nfc_tag_14a_coll_res_referen_t* info = get_mifare_coll_res();
// copy sak
info->sak[0] = data[0];
// copy atqa
@@ -528,6 +528,124 @@ data_frame_tx_t* cmd_processor_get_slot_tag_nick_name(uint16_t cmd, uint16_t sta
return data_frame_make(cmd, status, length, data);
}
data_frame_tx_t* cmd_processor_get_mf1_info(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
uint8_t mf1_info[5] = {};
mf1_info[0] = nfc_tag_mf1_is_detection_enable();
mf1_info[1] = nfc_tag_mf1_is_gen1a_magic_mode();
mf1_info[2] = nfc_tag_mf1_is_gen2_magic_mode();
mf1_info[3] = nfc_tag_mf1_is_use_mf1_coll_res();
nfc_tag_mf1_write_mode_t write_mode = nfc_tag_mf1_get_write_mode();
if (write_mode == NFC_TAG_MF1_WRITE_NORMAL) {
mf1_info[4] = 0;
} else if (write_mode == NFC_TAG_MF1_WRITE_DENIED) {
mf1_info[4] = 1;
} else if (write_mode == NFC_TAG_MF1_WRITE_DECEIVE) {
mf1_info[4] = 2;
} else if (write_mode == NFC_TAG_MF1_WRITE_SHADOW) {
mf1_info[4] = 3;
}
return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, 5, mf1_info);
}
data_frame_tx_t* cmd_processor_get_mf1_gen1a_magic_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (nfc_tag_mf1_is_gen1a_magic_mode()) {
status = 1;
} else {
status = 0;
}
return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, 1, (uint8_t*)&status);
}
data_frame_tx_t* cmd_processor_set_mf1_gen1a_magic_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (length == 1 && (data[0] == 0 || data[0] == 1)) {
nfc_tag_mf1_set_gen1a_magic_mode(data[0]);
status = STATUS_DEVICE_SUCCESS;
} else {
status = STATUS_PAR_ERR;
}
return data_frame_make(cmd, status, 0, NULL);
}
data_frame_tx_t* cmd_processor_get_mf1_gen2_magic_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (nfc_tag_mf1_is_gen2_magic_mode()) {
status = 1;
} else {
status = 0;
}
return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, 1, (uint8_t*)&status);
}
data_frame_tx_t* cmd_processor_set_mf1_gen2_magic_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (length == 1 && (data[0] == 0 || data[0] == 1)) {
nfc_tag_mf1_set_gen2_magic_mode(data[0]);
status = STATUS_DEVICE_SUCCESS;
} else {
status = STATUS_PAR_ERR;
}
return data_frame_make(cmd, status, 0, NULL);
}
data_frame_tx_t* cmd_processor_get_mf1_use_coll_res(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (nfc_tag_mf1_is_use_mf1_coll_res()) {
status = 1;
} else {
status = 0;
}
return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, 1, (uint8_t*)&status);
}
data_frame_tx_t* cmd_processor_set_mf1_use_coll_res(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (length == 1 && (data[0] == 0 || data[0] == 1)) {
nfc_tag_mf1_set_use_mf1_coll_res(data[0]);
status = STATUS_DEVICE_SUCCESS;
} else {
status = STATUS_PAR_ERR;
}
return data_frame_make(cmd, status, 0, NULL);
}
data_frame_tx_t* cmd_processor_get_mf1_write_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
nfc_tag_mf1_write_mode_t write_mode = nfc_tag_mf1_get_write_mode();
if (write_mode == NFC_TAG_MF1_WRITE_NORMAL) {
status = 0;
} else if (write_mode == NFC_TAG_MF1_WRITE_DENIED) {
status = 1;
} else if (write_mode == NFC_TAG_MF1_WRITE_DECEIVE) {
status = 2;
} else if (write_mode == NFC_TAG_MF1_WRITE_SHADOW) {
status = 3;
}
return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, 1, (uint8_t*)&status);
}
data_frame_tx_t* cmd_processor_set_mf1_write_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
if (length == 1 && (data[0] >= 0 || data[0] <= 3)) {
uint8_t mode = data[0];
if (mode == 0) {
nfc_tag_mf1_set_write_mode(NFC_TAG_MF1_WRITE_NORMAL);
} else if (mode == 1) {
nfc_tag_mf1_set_write_mode(NFC_TAG_MF1_WRITE_DENIED);
} else if (mode == 2) {
nfc_tag_mf1_set_write_mode(NFC_TAG_MF1_WRITE_DECEIVE);
} else if (mode == 3) {
nfc_tag_mf1_set_write_mode(NFC_TAG_MF1_WRITE_SHADOW);
}
status = STATUS_DEVICE_SUCCESS;
} else {
status = STATUS_PAR_ERR;
}
return data_frame_make(cmd, status, 0, NULL);
}
data_frame_tx_t* cmd_processor_get_enabled_slots(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
uint8_t slot_info[8] = {};
for (uint8_t slot = 0; slot < 8; slot++) {
slot_info[slot] = tag_emulation_slot_is_enable(slot);
}
return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, 8, slot_info);
}
#if defined(PROJECT_CHAMELEON_ULTRA)
@@ -614,6 +732,8 @@ static cmd_data_map_t m_data_cmd_map[] = {
{ DATA_CMD_GET_ACTIVE_SLOT, NULL, cmd_processor_get_activated_slot, NULL },
{ DATA_CMD_GET_SLOT_INFO, NULL, cmd_processor_get_slot_info, NULL },
{ DATA_CMD_WIPE_FDS, NULL, cmd_processor_wipe_fds, NULL },
{ DATA_CMD_GET_ENABLED_SLOTS, NULL, cmd_processor_get_enabled_slots, NULL },
{ DATA_CMD_SET_EM410X_EMU_ID, NULL, cmd_processor_set_em410x_emu_id, NULL },
@@ -624,6 +744,15 @@ static cmd_data_map_t m_data_cmd_map[] = {
{ DATA_CMD_GET_MF1_DETECTION_RESULT, NULL, cmd_processor_get_mf1_detection_log, NULL },
{ DATA_CMD_LOAD_MF1_BLOCK_DATA, NULL, cmd_processor_set_mf1_emulator_block, NULL },
{ DATA_CMD_SET_MF1_ANTI_COLLISION_RES, NULL, cmd_processor_set_mf1_anti_collision_res, NULL },
{ DATA_CMD_GET_MF1_EMULATOR_CONFIG, NULL, cmd_processor_get_mf1_info, NULL },
{ DATA_CMD_GET_MF1_GEN1A_MODE, NULL, cmd_processor_get_mf1_gen1a_magic_mode, NULL },
{ DATA_CMD_SET_MF1_GEN1A_MODE, NULL, cmd_processor_set_mf1_gen1a_magic_mode, NULL },
{ DATA_CMD_GET_MF1_GEN2_MODE, NULL, cmd_processor_get_mf1_gen2_magic_mode, NULL },
{ DATA_CMD_SET_MF1_GEN2_MODE, NULL, cmd_processor_set_mf1_gen2_magic_mode, NULL },
{ DATA_CMD_GET_MF1_USE_FIRST_BLOCK_COLL, NULL, cmd_processor_get_mf1_use_coll_res, NULL },
{ DATA_CMD_SET_MF1_USE_FIRST_BLOCK_COLL, NULL, cmd_processor_set_mf1_use_coll_res, NULL },
{ DATA_CMD_GET_MF1_WRITE_MODE, NULL, cmd_processor_get_mf1_write_mode, NULL },
{ DATA_CMD_SET_MF1_WRITE_MODE, NULL, cmd_processor_set_mf1_write_mode, NULL },
{ DATA_CMD_SET_SLOT_TAG_NICK, NULL, cmd_processor_set_slot_tag_nick_name, NULL },
{ DATA_CMD_GET_SLOT_TAG_NICK, NULL, cmd_processor_get_slot_tag_nick_name, NULL },
+12
View File
@@ -28,6 +28,7 @@
#define DATA_CMD_GET_ACTIVE_SLOT (1018)
#define DATA_CMD_GET_SLOT_INFO (1019)
#define DATA_CMD_WIPE_FDS (1020)
#define DATA_CMD_GET_ENABLED_SLOTS (1023)
//
// ******************************************************************
@@ -69,6 +70,17 @@
//
#define DATA_CMD_LOAD_MF1_BLOCK_DATA (4000)
#define DATA_CMD_SET_MF1_ANTI_COLLISION_RES (4001)
#define DATA_CMD_GET_MF1_EMULATOR_CONFIG (4009)
#define DATA_CMD_GET_MF1_GEN1A_MODE (4010)
#define DATA_CMD_SET_MF1_GEN1A_MODE (4011)
#define DATA_CMD_GET_MF1_GEN2_MODE (4012)
#define DATA_CMD_SET_MF1_GEN2_MODE (4013)
#define DATA_CMD_GET_MF1_USE_FIRST_BLOCK_COLL (4014)
#define DATA_CMD_SET_MF1_USE_FIRST_BLOCK_COLL (4015)
#define DATA_CMD_GET_MF1_WRITE_MODE (4016)
#define DATA_CMD_SET_MF1_WRITE_MODE (4017)
//
// ******************************************************************
@@ -38,14 +38,14 @@ NRF_LOG_MODULE_REGISTER();
#define CMD_AUTH_A 0x60
#define CMD_AUTH_B 0x61
#define CMD_AUTH_FRAME_SIZE 2 /* Bytes without CRCA */
#define CMD_AUTH_RB_FRAME_SIZE 4 /* Bytes */
#define CMD_AUTH_AB_FRAME_SIZE 8 /* Bytes */
#define CMD_AUTH_BA_FRAME_SIZE 4 /* Bytes */
#define CMD_AUTH_RB_FRAME_SIZE 4 /* Bytes */
#define CMD_AUTH_AB_FRAME_SIZE 8 /* Bytes */
#define CMD_AUTH_BA_FRAME_SIZE 4 /* Bytes */
#define CMD_HALT 0x50
#define CMD_HALT_FRAME_SIZE 2 /* Bytes without CRCA */
#define CMD_HALT_FRAME_SIZE 2 /* Bytes without CRCA */
#define CMD_READ 0x30
#define CMD_READ_FRAME_SIZE 2 /* Bytes without CRCA */
#define CMD_READ_RESPONSE_FRAME_SIZE 16 /* Bytes without CRCA */
#define CMD_READ_RESPONSE_FRAME_SIZE 16 /* Bytes without CRCA */
#define CMD_WRITE 0xA0
#define CMD_WRITE_FRAME_SIZE 2 /* Bytes without CRCA */
#define CMD_DECREMENT 0xC0
@@ -54,8 +54,6 @@ NRF_LOG_MODULE_REGISTER();
#define CMD_INCREMENT_FRAME_SIZE 2 /* Bytes without CRCA */
#define CMD_RESTORE 0xC2
#define CMD_RESTORE_FRAME_SIZE 2 /* Bytes without CRCA */
#define CMD_SIG_READ 0xC2
#define CMD_SIG_READ_FRAME_SIZE 1 /* Bytes without CRCA */
#define CMD_TRANSFER 0xB0
#define CMD_TRANSFER_FRAME_SIZE 2 /* Bytes without CRCA */
@@ -311,9 +309,18 @@ void ValueToBlock(uint8_t *Block, uint32_t Value) {
/** @brief mf1获取一个随机数
* @param nonce 随机数的Buffer
*/
void nfc_tag_mf1_random_nonce(uint8_t nonce[4]) {
void nfc_tag_mf1_random_nonce(uint8_t nonce[4], bool isNested) {
// 使用rand进行快速产生随机数,性能损耗较小
num_to_bytes(rand(), 4, nonce);
// isNested provides more randomness for hardnested attack
if (isNested) {
nonce[0] = rand() & 0xff;
nonce[1] = rand() & 0xff;
nonce[2] = rand() & 0xff;
nonce[3] = rand() & 0xff;
} else {
// fast for most readers
num_to_bytes(rand(), 4, nonce);
}
}
/**
@@ -494,7 +501,7 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) {
m_tag_trailer_info = (nfc_tag_mf1_trailer_info_t*)m_tag_information->memory[BlockEnd];
// 生成随机数
nfc_tag_mf1_random_nonce(CardNonce);
nfc_tag_mf1_random_nonce(CardNonce, false);
// 根据卡随机数预先计算读卡器应答
for (uint8_t i = 0; i < sizeof(ReaderResponse); i++) {
@@ -674,10 +681,10 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) {
case CMD_READ: {
// 保存当前操作的块地址
CurrentAddress = p_data[1];
// 生成访问控制,用于下面的数据访问控制
uint8_t Acc = abTrailorAccessConditions[ GetAccessCondition(CurrentAddress) ][ KeyInUse ];
// 读取命令。从内存中读取数据并附加CRCA。注意:读取操作受到控制位的限制,但是目前我们只限制控制位的读取
if ((p_data[1] < 128 && (p_data[1] & 3) == 3) || ((p_data[1] & 15) == 15)) {
// 生成访问控制,用于下面的数据访问控制
uint8_t Acc = abTrailorAccessConditions[ GetAccessCondition(CurrentAddress) ][ KeyInUse ];
if ((CurrentAddress < 128 && (CurrentAddress & 3) == 3) || ((CurrentAddress & 15) == 15)) {
// 清空一下buffer,避免缓存的数据影响到后续操作
memset(m_tag_tx_buffer.tx_raw_buffer, 0x00, sizeof(m_tag_tx_buffer.tx_raw_buffer));
// 让这块数据区域变成我们需要的尾部块类型
@@ -717,7 +724,7 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) {
}
case CMD_WRITE: {
// 正常的卡不允许写block0,不然会被CUID防火墙识别到
if (p_data[1] == 0x00) {
if (p_data[1] == 0x00 && !m_tag_information->config.mode_gen2_magic) {
// 直接重置14a的状态机,让标签休眠
nfc_tag_14a_set_state(NFC_TAG_STATE_14A_HALTED);
// 告知一下读头此操作不被允许
@@ -823,7 +830,7 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) {
m_tag_trailer_info = (nfc_tag_mf1_trailer_info_t*)m_tag_information->memory[BlockEnd];
// 生成随机数
nfc_tag_mf1_random_nonce(CardNonce);
nfc_tag_mf1_random_nonce(CardNonce, true);
// 根据卡随机数预先计算读卡器响应
for (uint8_t i = 0; i < sizeof(ReaderResponse); i++) {
@@ -1041,7 +1048,7 @@ void nfc_tag_mf1_state_handler(uint8_t* p_data, uint16_t szDataBits) {
/**
* @brief 提供mifare标签必要的防冲突资源(仅提供指针)
*/
nfc_tag_14a_coll_res_referen_t* get_miafre_coll_res() {
nfc_tag_14a_coll_res_referen_t* get_mifare_coll_res() {
// 根据当前的互通配置,选择性的返回其中配置的数据,假设开启了数据互通,那么我们还需要确保当前模拟的卡是4BYTE的
if (m_tag_information->config.use_mf1_coll_res && m_tag_information->res_coll.size == NFC_TAG_14A_UID_SINGLE_SIZE) {
// 获得数据区域的厂商信息
@@ -1119,7 +1126,7 @@ int nfc_tag_mf1_data_loadcb(tag_specific_type_t type, tag_data_buffer_t* buffer)
m_tag_type = type;
// 注册14a通信管理接口
nfc_tag_14a_handler_t handler_for_14a = {
.get_coll_res = get_miafre_coll_res,
.get_coll_res = get_mifare_coll_res,
.cb_state = nfc_tag_mf1_state_handler,
.cb_reset = nfc_tag_mf1_reset_handler,
};
@@ -1166,6 +1173,7 @@ bool nfc_tag_mf1_data_factory(uint8_t slot, tag_specific_type_t tag_type) {
// default mf1 config
p_mf1_information->config.mode_gen1a_magic = false;
p_mf1_information->config.mode_gen2_magic = false;
p_mf1_information->config.use_mf1_coll_res = false;
p_mf1_information->config.mode_block_write = NFC_TAG_MF1_WRITE_NORMAL;
p_mf1_information->config.detection_enable = false;
@@ -1204,3 +1212,44 @@ void nfc_tag_mf1_detection_log_clear(void) {
uint32_t nfc_tag_mf1_detection_log_count(void) {
return m_auth_log.count;
}
// Set gen1a magic mode
void nfc_tag_mf1_set_gen1a_magic_mode(bool enable) {
m_tag_information->config.mode_gen1a_magic = enable;
}
// Is in gen1a magic mode?
bool nfc_tag_mf1_is_gen1a_magic_mode(void) {
return m_tag_information->config.mode_gen1a_magic;
}
// Set gen2 magic mode
void nfc_tag_mf1_set_gen2_magic_mode(bool enable) {
m_tag_information->config.mode_gen2_magic = enable;
}
// Is in gen2 magic mode?
bool nfc_tag_mf1_is_gen2_magic_mode(void) {
return m_tag_information->config.mode_gen2_magic;
}
// Set anti collision data from block 0
void nfc_tag_mf1_set_use_mf1_coll_res(bool enable) {
m_tag_information->config.use_mf1_coll_res = enable;
}
// Get is anti collision data from block 0
bool nfc_tag_mf1_is_use_mf1_coll_res(void) {
return m_tag_information->config.use_mf1_coll_res;
}
// Set write mode
void nfc_tag_mf1_set_write_mode(nfc_tag_mf1_write_mode_t write_mode) {
m_tag_information->config.mode_block_write = write_mode;
}
// Get write mode
nfc_tag_mf1_write_mode_t nfc_tag_mf1_get_write_mode(void) {
return m_tag_information->config.mode_block_write;
}
@@ -44,10 +44,10 @@ typedef enum {
// mf1配置
typedef struct {
/**
* 正常写入模式(根据当前的状态去正常写入,受控制位和后门卡影响)
* 拒绝写入模式(类似控制位锁死,直接拒绝任何写入,返回nack
* 欺诈写入模式(表面上返回ack表示写入成功,其实连RAM都不写入)
* 影子写入模式(写入到RAM里面,并且返回ack表示成功,但是不保存到flash里面)
* Normal write mode (write normally according to the current state, affected by the control bit and the back door card)
* Deny write mode (similar to control bit lock, directly reject any write, return nack)
* Fraudulent writing mode (on the surface, returning ack indicates that the writing is successful, but in fact, even RAM is not written)
* Shadow write mode (write to RAM, and return ack to indicate success, but not save to flash)
* @see nfc_tag_mf1_write_mode_t
*/
nfc_tag_mf1_write_mode_t mode_block_write;
@@ -66,8 +66,10 @@ typedef struct {
* 使能侦测,将自动记录mf1的验证日志
*/
uint8_t detection_enable: 1;
// Allow to write block 0 (CUID/gen2 mode)
uint8_t mode_gen2_magic: 1;
// 保留
uint8_t reserved1: 5;
uint8_t reserved1: 4;
uint8_t reserved2;
uint8_t reserved3;
} nfc_tag_mf1_configure_t;
@@ -140,6 +142,15 @@ void nfc_tag_mf1_set_detection_enable(bool enable);
bool nfc_tag_mf1_is_detection_enable(void);
void nfc_tag_mf1_detection_log_clear(void);
uint32_t nfc_tag_mf1_detection_log_count(void);
nfc_tag_14a_coll_res_referen_t* get_miafre_coll_res(void);
nfc_tag_14a_coll_res_referen_t* get_mifare_coll_res(void);
void nfc_tag_mf1_set_gen1a_magic_mode(bool enable);
bool nfc_tag_mf1_is_gen1a_magic_mode(void);
void nfc_tag_mf1_set_gen2_magic_mode(bool enable);
bool nfc_tag_mf1_is_gen2_magic_mode(void);
void nfc_tag_mf1_set_use_mf1_coll_res(bool enable);
bool nfc_tag_mf1_is_use_mf1_coll_res(void);
void nfc_tag_mf1_set_write_mode(nfc_tag_mf1_write_mode_t write_mode);
nfc_tag_mf1_write_mode_t nfc_tag_mf1_get_write_mode(void);
#endif
@@ -1,3 +1,3 @@
GNU_INSTALL_ROOT ?= /usr/local/gcc-arm-none-eabi-10.3-2021.10/bin/
GNU_INSTALL_ROOT ?= /usr/bin/
GNU_VERSION ?= 9.3.1
GNU_PREFIX ?= arm-none-eabi
+14 -18
View File
@@ -1,5 +1,4 @@
import argparse
import os
import platform
import sys
import traceback
@@ -10,9 +9,6 @@ import colorama
import chameleon_cli_unit
import os
if os.name == 'posix':
import readline
ULTRA = r"""
╦ ╦╦ ╔╦╗╦═╗╔═╗
███████ ║ ║║ ║ ╠╦╝╠═╣
@@ -43,10 +39,7 @@ def new_uint(unit_clz, help_msg):
:param help_msg: unit usage
:return: a dict...
"""
return {
'unit': unit_clz,
'help': help_msg,
}
return {'unit': unit_clz, 'help': help_msg}
class ChameleonCLI:
@@ -60,7 +53,7 @@ class ChameleonCLI:
'connect': new_uint(chameleon_cli_unit.HWConnect, "Connect to chameleon by serial port"),
'chipid': {
'get': new_uint(chameleon_cli_unit.HWChipIdGet, "Get device chipset ID"),
'help': "Device chipsed ID get"
'help': "Device chipset ID get"
},
'address': {
'get': new_uint(chameleon_cli_unit.HWAddressGet, "Get device address (used with Bluetooth)"),
@@ -72,7 +65,7 @@ class ChameleonCLI:
'help': "Device mode get/set"
},
'slot': {
'info': new_uint(chameleon_cli_unit.HWSlotInfo, "Get information about slots"),
'list': new_uint(chameleon_cli_unit.HWSlotList, "Get information about slots"),
'change': new_uint(chameleon_cli_unit.HWSlotSet, "Set emulation tag slot activated."),
'type': new_uint(chameleon_cli_unit.HWSlotTagType, "Set emulation tag type"),
'init': new_uint(chameleon_cli_unit.HWSlotDataDefault, "Set emulation tag data to default"),
@@ -87,7 +80,8 @@ class ChameleonCLI:
'help': "Emulation tag slot.",
},
'version': new_uint(chameleon_cli_unit.HWVersion, "Get current device firmware version"),
'dfu': new_uint(chameleon_cli_unit.HWDFU, "Restart application to bootloader mode(Not yet implement dfu)."),
'dfu': new_uint(chameleon_cli_unit.HWDFU, "Restart application to bootloader mode(Not yet implement "
"dfu)."),
'settings': {
'animation': {
'get': new_uint(chameleon_cli_unit.HWSettingsAnimationGet, "Get current animation mode value"),
@@ -98,7 +92,8 @@ class ChameleonCLI:
'reset': new_uint(chameleon_cli_unit.HWSettingsReset, "Reset settings to default values"),
'help': "Chameleon settings management"
},
'factory_reset': new_uint(chameleon_cli_unit.HWFactoryReset, "Wipe all data and return to factory settings"),
'factory_reset': new_uint(chameleon_cli_unit.HWFactoryReset, "Wipe all data and return to factory "
"settings"),
'help': "hardware controller",
},
'hf': {
@@ -110,15 +105,16 @@ class ChameleonCLI:
'mf': {
'nested': new_uint(chameleon_cli_unit.HFMFNested, "Mifare Classic nested recover key"),
'darkside': new_uint(chameleon_cli_unit.HFMFDarkside, "Mifare Classic darkside recover key"),
'rdbl': new_uint(chameleon_cli_unit.HFMFRDBL, "MiFARE Classic read one block"),
'wrbl': new_uint(chameleon_cli_unit.HFMFWRBL, "MiFARE Classic write one block"),
'rdbl': new_uint(chameleon_cli_unit.HFMFRDBL, "Mifare Classic read one block"),
'wrbl': new_uint(chameleon_cli_unit.HFMFWRBL, "Mifare Classic write one block"),
'detection': {
'enable': new_uint(chameleon_cli_unit.HFMFDetectionEnable, "Detection enable"),
'count': new_uint(chameleon_cli_unit.HFMFDetectionLogCount, "Detection log count"),
'decrypt': new_uint(chameleon_cli_unit.HFMFDetectionDecrypt, "Download log and decrypt keys"),
'help': "Mifare Classic detection log"
},
'sim': new_uint(chameleon_cli_unit.HFMFSim, "Simulation a mifare classic card"),
'settings': new_uint(chameleon_cli_unit.HFMFSettings, "Settings of Mifare Classic emulator"),
'sim': new_uint(chameleon_cli_unit.HFMFSim, "Simulate a Mifare Classic card"),
'eload': new_uint(chameleon_cli_unit.HFMFELoad, "Load data to emulator memory"),
'help': "Mifare Classic mini/1/2/4, attack/read/write"
},
@@ -154,12 +150,10 @@ class ChameleonCLI:
"""
cmds = cmd_str.split(" ")
cmd_maps: dict or types.FunctionType = self.cmd_maps
cmd_end = ""
cmd_end_position = 0
for cmd in cmds:
if cmd in cmd_maps: # CMD found in map, we can continue find next
cmd_maps = cmd_maps[cmd]
cmd_end = cmd
cmd_end_position += len(cmd) + 1
else: # CMD not found
break
@@ -175,13 +169,15 @@ class ChameleonCLI:
while True:
# wait user input
status = f"{colorama.Fore.GREEN}USB" if self.device_com.isOpen() else f"{colorama.Fore.RED}Offline"
cmd_str = ""
try:
cmd_str = input(f"[{status}{colorama.Style.RESET_ALL}] chameleon --> ").strip()
except EOFError:
print("")
closing = True
if closing or cmd_str == "exit" or cmd_str == "quit" or cmd_str.startswith('q', 0) or cmd_str.startswith('e', 0):
if closing or cmd_str == "exit" or cmd_str == "quit" or cmd_str.startswith('q', 0) or cmd_str.startswith(
'e', 0):
print("Bye, thank you. ^.^ ")
self.device_com.close()
sys.exit(996)
File diff suppressed because it is too large Load Diff
+136 -62
View File
@@ -32,6 +32,8 @@ DATA_CMD_GET_SLOT_INFO = 1019
DATA_CMD_WIPE_FDS = 1020
DATA_CMD_GET_ENABLED_SLOTS = 1023
DATA_CMD_SCAN_14A_TAG = 2000
DATA_CMD_MF1_SUPPORT_DETECT = 2001
DATA_CMD_MF1_NT_LEVEL_DETECT = 2002
@@ -49,11 +51,22 @@ DATA_CMD_WRITE_EM410X_TO_T5577 = 3001
DATA_CMD_LOAD_MF1_BLOCK_DATA = 4000
DATA_CMD_SET_MF1_ANTI_COLLISION_RES = 4001
DATA_CMD_GET_MF1_EMULATOR_CONFIG = 4009
DATA_CMD_GET_MF1_GEN1A_MODE = 4010
DATA_CMD_SET_MF1_GEN1A_MODE = 4011
DATA_CMD_GET_MF1_GEN2_MODE = 4012
DATA_CMD_SET_MF1_GEN2_MODE = 4013
DATA_CMD_GET_MF1_USE_FIRST_BLOCK_COLL = 4014
DATA_CMD_SET_MF1_USE_FIRST_BLOCK_COLL = 4015
DATA_CMD_GET_MF1_WRITE_MODE = 4016
DATA_CMD_SET_MF1_WRITE_MODE = 4017
DATA_CMD_SET_EM410X_EMU_ID = 5000
DATA_CMD_SET_MF1_DETECTION_ENABLE = 5003
DATA_CMD_GET_MF1_DETECTION_COUNT = 5004
DATA_CMD_GET_MF1_DETECTION_RESULT = 5005
@enum.unique
class SlotNumber(enum.IntEnum):
SLOT_1 = 1,
@@ -66,7 +79,7 @@ class SlotNumber(enum.IntEnum):
SLOT_8 = 8,
@staticmethod
def to_fw(index: int): # can be int or SlotNumber
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
@@ -78,13 +91,12 @@ class SlotNumber(enum.IntEnum):
@enum.unique
class TagSenseType(enum.IntEnum):
# 无场感应
TAG_SENSE_NO = 0,
# 低频125khz场感应
TAG_SENSE_LF = 1,
# 高频13.56mhz场感应
TAG_SENSE_HF = 2,
# Unknown
TAG_SENSE_NO = 0
# 125 kHz
TAG_SENSE_LF = 1
# 13.56 MHz
TAG_SENSE_HF = 2
@staticmethod
def list(exclude_unknown=True):
@@ -100,18 +112,19 @@ class TagSenseType(enum.IntEnum):
return "HF"
return "None"
@enum.unique
class TagSpecificType(enum.IntEnum):
# 特定的且必须存在的标志不存在的类型
# Empty slot
TAG_TYPE_UNKNOWN = 0
# 125khzID卡)系列
# 125 kHzIDcards
TAG_TYPE_EM410X = 1
# Mifare系列
# Mifare Classic
TAG_TYPE_MIFARE_Mini = 2
TAG_TYPE_MIFARE_1024 = 3
TAG_TYPE_MIFARE_2048 = 4
TAG_TYPE_MIFARE_4096 = 5
# NTAG系列
# NTAG
TAG_TYPE_NTAG_213 = 6
TAG_TYPE_NTAG_215 = 7
TAG_TYPE_NTAG_216 = 8
@@ -143,6 +156,32 @@ class TagSpecificType(enum.IntEnum):
return "Unknown"
@enum.unique
class MifareClassicWriteMode(enum.IntEnum):
# Normal write
NORMAL = 0
# Send NACK to write attempts
DEINED = 1
# Acknowledge writes, but don't remember contents
DECEIVE = 2
# Store data to RAM, but not to ROM
SHADOW = 3
@staticmethod
def list():
return list(map(int, MifareClassicWriteMode))
def __str__(self):
if self == MifareClassicWriteMode.NORMAL:
return "Normal"
elif self == MifareClassicWriteMode.DEINED:
return "Deined"
elif self == MifareClassicWriteMode.DECEIVE:
return "Deceive"
elif self == MifareClassicWriteMode.SHADOW:
return "Shadow"
return "None"
class BaseChameleonCMD:
"""
@@ -159,25 +198,25 @@ class BaseChameleonCMD:
"""
Get firmware version number(application)
"""
resp = self.device.send_cmd_sync(DATA_CMD_GET_APP_VERSION, 0x00, None)
resp = self.device.send_cmd_sync(DATA_CMD_GET_APP_VERSION, 0x00)
return int.from_bytes(resp.data, 'little')
def get_device_chip_id(self) -> str:
"""
Get device chip id
"""
resp = self.device.send_cmd_sync(DATA_CMD_GET_DEVICE_CHIP_ID, 0x00, None)
resp = self.device.send_cmd_sync(DATA_CMD_GET_DEVICE_CHIP_ID, 0x00)
return resp.data.hex()
def get_device_address(self) -> str:
"""
Get device address
"""
resp = self.device.send_cmd_sync(DATA_CMD_GET_DEVICE_ADDRESS, 0x00, None)
resp = self.device.send_cmd_sync(DATA_CMD_GET_DEVICE_ADDRESS, 0x00)
return resp.data[::-1].hex()
def get_git_version(self) -> str:
resp = self.device.send_cmd_sync(DATA_CMD_GET_GIT_VERSION, 0x00, None)
resp = self.device.send_cmd_sync(DATA_CMD_GET_GIT_VERSION, 0x00)
return resp.data.decode('utf-8')
def is_reader_device_mode(self) -> bool:
@@ -185,7 +224,7 @@ class BaseChameleonCMD:
Get device mode, reader or tag
:return: True is reader mode, else tag mode
"""
resp = self.device.send_cmd_sync(DATA_CMD_GET_DEVICE_MODE, 0x00, None)
resp = self.device.send_cmd_sync(DATA_CMD_GET_DEVICE_MODE, 0x00)
return True if resp.data[0] == 1 else False
def set_reader_device_mode(self, reader_mode: bool = True):
@@ -201,21 +240,21 @@ class BaseChameleonCMD:
扫描场内的14a标签
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_SCAN_14A_TAG, 0x00, None)
return self.device.send_cmd_sync(DATA_CMD_SCAN_14A_TAG, 0x00)
def detect_mf1_support(self):
"""
检测是否是mifare classic标签
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_MF1_SUPPORT_DETECT, 0x00, None)
return self.device.send_cmd_sync(DATA_CMD_MF1_SUPPORT_DETECT, 0x00)
def detect_mf1_nt_level(self):
"""
检测mifare classic的nt漏洞的等级
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_MF1_NT_LEVEL_DETECT, 0x00, None)
return self.device.send_cmd_sync(DATA_CMD_MF1_NT_LEVEL_DETECT, 0x00)
def detect_darkside_support(self):
"""
@@ -315,7 +354,7 @@ class BaseChameleonCMD:
读取EM410X的卡号
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_SCAN_EM410X_TAG, 0x00, None)
return self.device.send_cmd_sync(DATA_CMD_SCAN_EM410X_TAG, 0x00)
def write_em_410x_to_t55xx(self, id_bytes: bytearray):
"""
@@ -324,10 +363,7 @@ class BaseChameleonCMD:
:return:
"""
new_key = [0x20, 0x20, 0x66, 0x66]
old_keys = [
[0x51, 0x24, 0x36, 0x48],
[0x19, 0x92, 0x04, 0x27],
]
old_keys = [[0x51, 0x24, 0x36, 0x48], [0x19, 0x92, 0x04, 0x27]]
if len(id_bytes) != 5:
raise ValueError("The id bytes length must equal 5")
data = bytearray()
@@ -342,19 +378,19 @@ class BaseChameleonCMD:
Get slots info
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_GET_SLOT_INFO, 0x00, None)
return self.device.send_cmd_sync(DATA_CMD_GET_SLOT_INFO, 0x00)
def get_active_slot(self):
"""
Get selected slot
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_GET_ACTIVE_SLOT, 0x00, None)
return self.device.send_cmd_sync(DATA_CMD_GET_ACTIVE_SLOT, 0x00)
def set_slot_activated(self, slot_index: SlotNumber):
"""
设置当前激活使用的卡槽
:param slot_index: 卡槽索引,从 1 - 8(不是从0下标开始)
Set the card slot currently active for use
:param slot_index: Card slot index
:return:
"""
# SlotNumber() will raise error for us if slot_index not in slot range
@@ -428,7 +464,7 @@ class BaseChameleonCMD:
获取当前侦测记录的统计个数
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_GET_MF1_DETECTION_COUNT, 0x00, None)
return self.device.send_cmd_sync(DATA_CMD_GET_MF1_DETECTION_COUNT, 0x00)
def get_mf1_detection_log(self, index: int):
"""
@@ -465,7 +501,7 @@ class BaseChameleonCMD:
data.extend(atqa)
data.extend(uid)
return self.device.send_cmd_sync(DATA_CMD_SET_MF1_ANTI_COLLISION_RES, 0X00, data)
def set_slot_tag_nick_name(self, slot: SlotNumber, sense_type: TagSenseType, name: bytes):
"""
设置MF1的模拟卡的防冲撞资源信息
@@ -479,26 +515,61 @@ class BaseChameleonCMD:
data.extend([SlotNumber.to_fw(slot), sense_type])
data.extend(name)
return self.device.send_cmd_sync(DATA_CMD_SET_SLOT_TAG_NICK, 0x00, data)
def get_slot_tag_nick_name(self, slot: SlotNumber, sense_type: TagSenseType):
"""
设置MF1的模拟卡的防冲撞资源信息
:param slot: 卡槽号码
:param sense_type: 场类型
:param name: 卡槽昵称
:return:
"""
# SlotNumber() will raise error for us if slot not in slot range
data = bytearray()
data.extend([SlotNumber.to_fw(slot), sense_type])
return self.device.send_cmd_sync(DATA_CMD_GET_SLOT_TAG_NICK, 0x00, data)
def get_mf1_emulator_settings(self):
"""
Get array of Mifare Classic emulators settings:
[0] - mf1_is_detection_enable (mfkey32)
[1] - mf1_is_gen1a_magic_mode
[2] - mf1_is_gen2_magic_mode
[3] - mf1_is_use_mf1_coll_res (use UID/BCC/SAK/ATQA from 0 block)
[4] - mf1_get_write_mode
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_GET_MF1_EMULATOR_CONFIG, 0x00)
def set_mf1_gen1a_mode(self, enabled: bool):
"""
Set gen1a magic mode
"""
return self.device.send_cmd_sync(DATA_CMD_SET_MF1_GEN1A_MODE, 0x00, bytearray([1 if enabled else 0]))
def set_mf1_gen2_mode(self, enabled: bool):
"""
Set gen2 magic mode
"""
return self.device.send_cmd_sync(DATA_CMD_SET_MF1_GEN2_MODE, 0x00, bytearray([1 if enabled else 0]))
def set_mf1_block_anti_coll_mode(self, enabled: bool):
"""
Set 0 block anti-collision data
"""
return self.device.send_cmd_sync(DATA_CMD_SET_MF1_ANTI_COLLISION_RES, 0x00, bytearray([1 if enabled else 0]))
def set_mf1_write_mode(self, mode: int):
"""
Set write mode
"""
return self.device.send_cmd_sync(DATA_CMD_SET_MF1_WRITE_MODE, 0x00, bytearray([mode]))
def update_slot_data_config(self):
"""
更新卡槽的配置和数据到flash中。
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_SLOT_DATA_CONFIG_SAVE, 0x00, None)
return self.device.send_cmd_sync(DATA_CMD_SLOT_DATA_CONFIG_SAVE, 0x00)
def enter_dfu_mode(self):
"""
@@ -506,19 +577,25 @@ class BaseChameleonCMD:
:return:
"""
return self.device.send_cmd_auto(DATA_CMD_ENTER_BOOTLOADER, 0x00, close=True)
def get_settings_animation(self):
"""
Get animation mode value
"""
return self.device.send_cmd_sync(DATA_CMD_GET_ANIMATION_MODE, 0x00, None)
return self.device.send_cmd_sync(DATA_CMD_GET_ANIMATION_MODE, 0x00)
def get_enabled_slots(self):
"""
Get animation mode value
"""
return self.device.send_cmd_sync(DATA_CMD_GET_ENABLED_SLOTS, 0x00)
def set_settings_animation(self, value: int):
"""
Set animation mode value
"""
return self.device.send_cmd_sync(DATA_CMD_SET_ANIMATION_MODE, 0x00, bytearray([value]))
def reset_settings(self):
"""
Reset settings stored in flash memory
@@ -530,7 +607,7 @@ class BaseChameleonCMD:
Store settings to flash memory
"""
return self.device.send_cmd_sync(DATA_CMD_SAVE_SETTINGS, 0x00)
def factory_reset(self):
"""
Reset to factory settings
@@ -578,8 +655,8 @@ class PositiveChameleonCMD(BaseChameleonCMD):
return ret
def acquire_nested(self, block_known, type_known, key_known, block_target, type_target):
ret = super(PositiveChameleonCMD, self).acquire_nested(
block_known, type_known, key_known, block_target, type_target)
ret = super(PositiveChameleonCMD, self).acquire_nested(block_known, type_known, key_known, block_target,
type_target)
self.check_status(ret.status, chameleon_status.Device.HF_TAG_OK)
return ret
@@ -590,10 +667,7 @@ class PositiveChameleonCMD(BaseChameleonCMD):
def auth_mf1_key(self, block, type_value, key):
ret = super(PositiveChameleonCMD, self).auth_mf1_key(block, type_value, key)
self.check_status(ret.status, [
chameleon_status.Device.HF_TAG_OK,
chameleon_status.Device.MF_ERRAUTH,
])
self.check_status(ret.status, [chameleon_status.Device.HF_TAG_OK, chameleon_status.Device.MF_ERRAUTH])
return ret
def read_mf1_block(self, block, type_value, key):
@@ -621,17 +695,17 @@ class PositiveChameleonCMD(BaseChameleonCMD):
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def set_slot_tag_type(self, slot_index: int, tag_type: TagSpecificType):
def set_slot_tag_type(self, slot_index: SlotNumber, tag_type: TagSpecificType):
ret = super(PositiveChameleonCMD, self).set_slot_tag_type(slot_index, tag_type)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def set_slot_data_default(self, slot_index: int, tag_type: TagSpecificType):
def set_slot_data_default(self, slot_index: SlotNumber, tag_type: TagSpecificType):
ret = super(PositiveChameleonCMD, self).set_slot_data_default(slot_index, tag_type)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def set_slot_enable(self, slot_index: int, enable: bool):
def set_slot_enable(self, slot_index: SlotNumber, enable: bool):
ret = super(PositiveChameleonCMD, self).set_slot_enable(slot_index, enable)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
@@ -656,17 +730,17 @@ class PositiveChameleonCMD(BaseChameleonCMD):
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def set_mf1_anti_collision_res(self, sak: int, atqa: bytearray, uid: bytearray):
def set_mf1_anti_collision_res(self, sak: bytearray, atqa: bytearray, uid: bytearray):
ret = super(PositiveChameleonCMD, self).set_mf1_anti_collision_res(sak, atqa, uid)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def set_slot_tag_nick_name(self, slot: int, sense_type: int, name: bytes):
def set_slot_tag_nick_name(self, slot: SlotNumber, sense_type: TagSenseType, name: bytes):
ret = super(PositiveChameleonCMD, self).set_slot_tag_nick_name(slot, sense_type, name)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def get_slot_tag_nick_name(self, slot: int, sense_type: int):
def get_slot_tag_nick_name(self, slot: SlotNumber, sense_type: TagSenseType):
ret = super(PositiveChameleonCMD, self).get_slot_tag_nick_name(slot, sense_type)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
@@ -679,12 +753,12 @@ if __name__ == '__main__':
cml = BaseChameleonCMD(dev)
ver = cml.get_firmware_version()
print(f"Firmware number of application: {ver}")
id = cml.get_device_chip_id()
print(f"Device chip id: {id}")
chip = cml.get_device_chip_id()
print(f"Device chip id: {chip}")
# disconnect
dev.close()
# nerver exit
while True: pass
# never exit
while True:
pass
+14 -27
View File
@@ -40,8 +40,6 @@ class ChameleonCom:
Chameleon device base class
Communication and Data frame implemented
"""
baudrate = 115200
data_frame_sof = 0x11
data_max_length = 512
@@ -49,7 +47,7 @@ class ChameleonCom:
"""
Create a chameleon device instance
"""
self.serial_instance: serial.Serial = None
self.serial_instance: serial.Serial | None = None
self.send_data_queue = queue.Queue()
self.wait_response_map = {}
self.event_closing = threading.Event()
@@ -72,7 +70,7 @@ class ChameleonCom:
error = None
try:
# open serial port
self.serial_instance = serial.Serial(port=port, baudrate=self.baudrate)
self.serial_instance = serial.Serial(port=port, baudrate=115200)
except Exception as e:
error = e
finally:
@@ -80,7 +78,7 @@ class ChameleonCom:
raise OpenFailException(error)
try:
self.serial_instance.dtr = 1 # must make dtr enable
except Exception as e:
except:
# not all serial support dtr, e.g. virtual serial over BLE
pass
self.serial_instance.timeout = 0 # noblock
@@ -89,9 +87,9 @@ class ChameleonCom:
self.wait_response_map.clear()
# Start a sub thread to process data
self.event_closing.clear()
threading.Thread(target=self.thread_data_receive, ).start()
threading.Thread(target=self.thread_data_transfer, ).start()
threading.Thread(target=self.thread_check_timeout, ).start()
threading.Thread(target=self.thread_data_receive).start()
threading.Thread(target=self.thread_data_transfer).start()
threading.Thread(target=self.thread_check_timeout).start()
return self
def check_open(self):
@@ -200,11 +198,8 @@ class ChameleonCom:
del self.wait_response_map[data_cmd]
fn_call(data_cmd, data_status, data_response)
else:
self.wait_response_map[data_cmd]['response'] = Response(
data_cmd,
data_status,
data_response
)
self.wait_response_map[data_cmd]['response'] = Response(data_cmd, data_status,
data_response)
else:
print(f"No task wait process: ${data_cmd}")
else:
@@ -232,13 +227,9 @@ class ChameleonCom:
task_close = task['close']
# register to wait map
if 'callback' in task and callable(task['callback']):
self.wait_response_map[task_cmd] = {
'callback': task['callback'] # The callback for this task
}
self.wait_response_map[task_cmd] = {'callback': task['callback']} # The callback for this task
else:
self.wait_response_map[task_cmd] = {
'response': None,
}
self.wait_response_map[task_cmd] = {'response': None}
# set start time
start_time = time.time()
self.wait_response_map[task_cmd]['start_time'] = start_time
@@ -279,7 +270,6 @@ class ChameleonCom:
:return: frame
"""
frame = bytearray()
lrc = 0x00
# sof and sof lrc byte
frame.append(self.data_frame_sof)
frame.append(self.lrc_calc(frame[0:1]))
@@ -295,7 +285,8 @@ class ChameleonCom:
frame.append(self.lrc_calc(frame))
return frame
def send_cmd_auto(self, cmd: int, status: int, data: bytearray = None, callback=None, timeout: int = 3, close: bool = False):
def send_cmd_auto(self, cmd: int, status: int, data: bytearray = None, callback=None, timeout: int = 3,
close: bool = False):
"""
Send cmd to device
:param timeout: wait response timeout
@@ -303,6 +294,7 @@ class ChameleonCom:
:param status: status(optional)
:param callback: call on response
:param data: bytes data
:param close: close connection after executing
:return:
"""
self.check_open()
@@ -311,12 +303,7 @@ class ChameleonCom:
del self.wait_response_map[cmd]
# make data frame
data_frame = self.make_data_frame_bytes(cmd, status, data)
task = {
'cmd': cmd,
'frame': data_frame,
'timeout': timeout,
'close': close,
}
task = {'cmd': cmd, 'frame': data_frame, 'timeout': timeout, 'close': close}
if callable(callback):
task['callback'] = callback
self.send_data_queue.put(task)
+7 -26
View File
@@ -22,7 +22,7 @@ def parse_14a_scan_tag_result(data: bytearray):
'uid_size': data[10],
'uid_hex': data[0:data[10]].hex(),
'sak_hex': hex(data[12]).lstrip('0x').rjust(2, '0'),
'atqa_hex': data[13:15].hex().upper(),
'atqa_hex': data[13:15].hex().upper()
}
@@ -49,7 +49,7 @@ def parse_nested_nt_acquire_group(data: bytearray):
group.append({
'nt': bytes_to_u32(data[i: i + 4]),
'nt_enc': bytes_to_u32(data[i + 4: i + 8]),
'par': data[i + 8],
'par': data[i + 8]
})
i += 9
return group
@@ -62,32 +62,15 @@ def parse_darkside_acquire_result(data: bytearray):
:return:
"""
return {
'uid': bytes_to_u32(data[0 : 4]),
'nt1': bytes_to_u32(data[4 : 8]),
'par': bytes_to_u32(data[8 : 16]),
'uid': bytes_to_u32(data[0: 4]),
'nt1': bytes_to_u32(data[4: 8]),
'par': bytes_to_u32(data[8: 16]),
'ks1': bytes_to_u32(data[16: 24]),
'nr': bytes_to_u32(data[24: 28]),
'ar': bytes_to_u32(data[28: 32]),
'ar': bytes_to_u32(data[28: 32])
}
"""
// 验证的基础信息
struct {
uint8_t block;
uint8_t is_keyb: 1;
uint8_t is_nested: 1;
// 空域占位置用的
uint8_t : 6;
} cmd;
// mfkey32必要参数
uint8_t uid[4];
uint8_t nt[4];
uint8_t nr[4];
uint8_t ar[4];
"""
def parse_mf1_detection_result(data: bytearray):
"""
From bytes parse detection param
@@ -105,7 +88,7 @@ def parse_mf1_detection_result(data: bytearray):
'uid': data[2 + pos: 6 + pos].hex(),
'nt': data[6 + pos: 10 + pos].hex(),
'nr': data[10 + pos: 14 + pos].hex(),
'ar': data[14 + pos: 18 + pos].hex(),
'ar': data[14 + pos: 18 + pos].hex()
})
pos += 18
@@ -127,5 +110,3 @@ def parse_mf1_detection_result(data: bytearray):
result_map[uid][block][type_chr].append(item)
return result_map
+48 -51
View File
@@ -1,6 +1,4 @@
class MetaDevice(type):
def __iter__(self):
for attr in dir(self):
if not attr.startswith("__"):
@@ -16,60 +14,59 @@ class MetaDevice(type):
class Device(metaclass=MetaDevice):
HF_TAG_OK = 0x00 # IC卡操作成功
HF_TAG_NO = 0x01 # 没有发现IC卡
HF_ERRSTAT = 0x02 # IC卡通信异常
HF_ERRCRC = 0x03 # IC卡通信校验异常
HF_COLLISION = 0x04 # IC卡冲突
HF_ERRBCC = 0x05 # IC卡BCC错误
MF_ERRAUTH = 0x06 # MF卡验证失败
HF_ERRPARITY = 0x07 # IC卡奇偶校验错误
HF_TAG_OK = 0x00 # IC卡操作成功
HF_TAG_NO = 0x01 # 没有发现IC卡
HF_ERRSTAT = 0x02 # IC卡通信异常
HF_ERRCRC = 0x03 # IC卡通信校验异常
HF_COLLISION = 0x04 # IC卡冲突
HF_ERRBCC = 0x05 # IC卡BCC错误
MF_ERRAUTH = 0x06 # MF卡验证失败
HF_ERRPARITY = 0x07 # IC卡奇偶校验错误
#
DARKSIDE_CANT_FIXED_NT = 0x20 # Darkside,无法固定随机数,这个情况可能出现在UID卡上
DARKSIDE_LUCK_AUTH_OK = 0x21 # Darkside,直接验证成功了,可能刚好密钥是空的
DARKSIDE_NACK_NO_SNED = 0x22 # Darkside,卡片不响应nack,可能是一张修复了nack逻辑漏洞的卡片
DARKSIDE_TAG_CHANGED = 0x23 # Darkside,在运行darkside的过程中出现了卡片切换,可能信号问题,或者真的是两张卡迅速切换了
NESTED_TAG_IS_STATIC = 0x24 # Nested,检测到卡片应答的随机数是固定的
NESTED_TAG_IS_HARD = 0x25 # Nested,检测到卡片应答的随机数是不可预测的
#
LF_TAG_OK = 0x40 # 低频卡的一些操作成功!
EM410X_TAG_NO_FOUND = 0x41 # 无法搜索到有效的EM410X标签
#
STATUS_PAR_ERR = 0x60 # BLE指令传递的参数错误,或者是调用某些函数传递的参数错误
STATUS_DEVIEC_MODE_ERROR = 0x66 # 当前设备所处的模式错误,无法调用对应的API
STATUS_INVALID_CMD = 0x67 # 无效的指令
STATUS_DEVICE_SUCCESS = 0x68 # 设备相关操作成功执行
STATUS_NOT_IMPLEMENTED = 0x69 # 调用了某些未实现的操作,属于开发者遗漏的错误
STATUS_FLASH_WRITE_FAIL = 0x70 # flash写入失败
STATUS_FLASH_READ_FAIL = 0x71 # flash读取失败
DARKSIDE_CANT_FIXED_NT = 0x20 # Darkside,无法固定随机数,这个情况可能出现在UID卡上
DARKSIDE_LUCK_AUTH_OK = 0x21 # Darkside,直接验证成功了,可能刚好密钥是空的
DARKSIDE_NACK_NO_SEND = 0x22 # Darkside,卡片不响应nack,可能是一张修复了nack逻辑漏洞的卡片
DARKSIDE_TAG_CHANGED = 0x23 # Darkside,在运行darkside的过程中出现了卡片切换,可能信号问题,或者真的是两张卡迅速切换了
NESTED_TAG_IS_STATIC = 0x24 # Nested,检测到卡片应答的随机数是固定的
NESTED_TAG_IS_HARD = 0x25 # Nested,检测到卡片应答的随机数是不可预测的
LF_TAG_OK = 0x40 # 低频卡的一些操作成功!
EM410X_TAG_NO_FOUND = 0x41 # 无法搜索到有效的EM410X标签
STATUS_PAR_ERR = 0x60 # BLE指令传递的参数错误,或者是调用某些函数传递的参数错误
STATUS_DEVICE_MODE_ERROR = 0x66 # 当前设备所处的模式错误,无法调用对应的API
STATUS_INVALID_CMD = 0x67 # 无效的指令
STATUS_DEVICE_SUCCESS = 0x68 # 设备相关操作成功执行
STATUS_NOT_IMPLEMENTED = 0x69 # 调用了某些未实现的操作,属于开发者遗漏的错误
STATUS_FLASH_WRITE_FAIL = 0x70 # flash写入失败
STATUS_FLASH_READ_FAIL = 0x71 # flash读取失败
message = {
Device.HF_TAG_OK : "HF tag operation succeeded",
Device.HF_TAG_NO : "HF tag no found or lost",
Device.HF_ERRSTAT : "HF tag status error",
Device.HF_ERRCRC : "HF tag data crc error",
Device.HF_COLLISION : "HF tag collision",
Device.HF_ERRBCC : "HF tag uid bcc error",
Device.MF_ERRAUTH : "HF tag auth fail",
Device.HF_ERRPARITY : "HF tag data parity error",
Device.HF_TAG_OK: "HF tag operation succeeded",
Device.HF_TAG_NO: "HF tag no found or lost",
Device.HF_ERRSTAT: "HF tag status error",
Device.HF_ERRCRC: "HF tag data crc error",
Device.HF_COLLISION: "HF tag collision",
Device.HF_ERRBCC: "HF tag uid bcc error",
Device.MF_ERRAUTH: "HF tag auth fail",
Device.HF_ERRPARITY: "HF tag data parity error",
Device.DARKSIDE_CANT_FIXED_NT : "Darkside Can't select a nt(PRNG is unpredictable)",
Device.DARKSIDE_LUCK_AUTH_OK : "Darkside try to recover a default key",
Device.DARKSIDE_NACK_NO_SNED : "Darkside can't make tag response nack(enc)",
Device.DARKSIDE_TAG_CHANGED : "Darkside running, can't change tag",
Device.NESTED_TAG_IS_STATIC : "StaticNested tag, not weak nested",
Device.NESTED_TAG_IS_HARD : "HardNested tag, not weak nested",
Device.DARKSIDE_CANT_FIXED_NT: "Darkside Can't select a nt(PRNG is unpredictable)",
Device.DARKSIDE_LUCK_AUTH_OK: "Darkside try to recover a default key",
Device.DARKSIDE_NACK_NO_SEND: "Darkside can't make tag response nack(enc)",
Device.DARKSIDE_TAG_CHANGED: "Darkside running, can't change tag",
Device.NESTED_TAG_IS_STATIC: "StaticNested tag, not weak nested",
Device.NESTED_TAG_IS_HARD: "HardNested tag, not weak nested",
Device.LF_TAG_OK : "LF tag operation succeeded",
Device.EM410X_TAG_NO_FOUND : "EM410x tag no found",
Device.LF_TAG_OK: "LF tag operation succeeded",
Device.EM410X_TAG_NO_FOUND: "EM410x tag no found",
Device.STATUS_PAR_ERR : "API request fail, param error",
Device.STATUS_DEVIEC_MODE_ERROR : "API request fail, device mode error",
Device.STATUS_INVALID_CMD : "API request fail, cmd invalid",
Device.STATUS_DEVICE_SUCCESS : "Device operation succeeded",
Device.STATUS_NOT_IMPLEMENTED : "Some api not implemented",
Device.STATUS_FLASH_WRITE_FAIL : "Flash write failed",
Device.STATUS_FLASH_READ_FAIL : "Flash read failed"
Device.STATUS_PAR_ERR: "API request fail, param error",
Device.STATUS_DEVICE_MODE_ERROR: "API request fail, device mode error",
Device.STATUS_INVALID_CMD: "API request fail, cmd invalid",
Device.STATUS_DEVICE_SUCCESS: "Device operation succeeded",
Device.STATUS_NOT_IMPLEMENTED: "Some api not implemented",
Device.STATUS_FLASH_WRITE_FAIL: "Flash write failed",
Device.STATUS_FLASH_READ_FAIL: "Flash read failed"
}