mirror of
https://github.com/RfidResearchGroup/ChameleonUltra.git
synced 2026-05-12 11:22:59 -07:00
Merge remote-tracking branch 'origin/main' into cli-overhaul
This commit is contained in:
@@ -377,6 +377,14 @@ data_frame_tx_t* cmd_processor_set_em410x_emu_id(uint16_t cmd, uint16_t status,
|
||||
return data_frame_make(cmd, status, 0, NULL);
|
||||
}
|
||||
|
||||
data_frame_tx_t* cmd_processor_get_em410x_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
tag_data_buffer_t* buffer = get_buffer_by_tag_type(TAG_TYPE_EM410X);
|
||||
uint8_t responseData[LF_EM410X_TAG_ID_SIZE];
|
||||
memcpy(responseData, buffer->buffer, LF_EM410X_TAG_ID_SIZE);
|
||||
status = STATUS_DEVICE_SUCCESS;
|
||||
return data_frame_make(cmd, status, LF_EM410X_TAG_ID_SIZE, responseData);
|
||||
}
|
||||
|
||||
data_frame_tx_t* cmd_processor_set_mf1_detection_enable(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length == 1 && (data[0] == 0 || data[0] == 1)) {
|
||||
nfc_tag_mf1_detection_log_clear();
|
||||
@@ -456,6 +464,33 @@ data_frame_tx_t* cmd_processor_set_mf1_emulator_block(uint16_t cmd, uint16_t sta
|
||||
return data_frame_make(cmd, status, 0, NULL);
|
||||
}
|
||||
|
||||
data_frame_tx_t* cmd_processor_get_mf1_emulator_block(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length == 3) {
|
||||
uint8_t block_index = data[0];
|
||||
uint16_t block_count = data[1] | (data[2] << 8);
|
||||
if (block_count == 0 || block_index + block_count > NFC_TAG_MF1_BLOCK_MAX) {
|
||||
status = STATUS_PAR_ERR;
|
||||
}
|
||||
else {
|
||||
tag_data_buffer_t* buffer = get_buffer_by_tag_type(TAG_TYPE_MIFARE_4096);
|
||||
nfc_tag_mf1_information_t *info = (nfc_tag_mf1_information_t *)buffer->buffer;
|
||||
uint16_t result_length = block_count * NFC_TAG_MF1_DATA_SIZE;
|
||||
uint8_t result_buffer[result_length];
|
||||
for (int i = 0, j = block_index; i < result_length; i += NFC_TAG_MF1_DATA_SIZE, j++) {
|
||||
uint8_t *p_block = &result_buffer[i];
|
||||
memcpy(p_block, info->memory[j], NFC_TAG_MF1_DATA_SIZE);
|
||||
}
|
||||
|
||||
return data_frame_make(cmd, status, result_length, result_buffer);
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = STATUS_PAR_ERR;
|
||||
}
|
||||
|
||||
return data_frame_make(cmd, status, 0, NULL);
|
||||
}
|
||||
|
||||
data_frame_tx_t* cmd_processor_set_mf1_anti_collision_res(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length > 13) {
|
||||
// sak(1) + atqa(2) + uid(10)
|
||||
@@ -463,7 +498,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 +563,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,16 +767,29 @@ 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 },
|
||||
{ DATA_CMD_GET_EM410X_EMU_ID, NULL, cmd_processor_get_em410x_emu_id, NULL },
|
||||
|
||||
{ DATA_CMD_GET_MF1_DETECTION_STATUS, NULL, cmd_processor_get_mf1_detection_status, NULL },
|
||||
{ DATA_CMD_SET_MF1_DETECTION_ENABLE, NULL, cmd_processor_set_mf1_detection_enable, NULL },
|
||||
{ DATA_CMD_GET_MF1_DETECTION_COUNT, NULL, cmd_processor_get_mf1_detection_count, NULL },
|
||||
{ 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_LOAD_MF1_EMU_BLOCK_DATA, NULL, cmd_processor_set_mf1_emulator_block, NULL },
|
||||
{ DATA_CMD_READ_MF1_EMU_BLOCK_DATA, NULL, cmd_processor_get_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 },
|
||||
|
||||
@@ -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)
|
||||
//
|
||||
// ******************************************************************
|
||||
|
||||
@@ -67,8 +68,24 @@
|
||||
// Range from 4000 -> 4999
|
||||
// ******************************************************************
|
||||
//
|
||||
#define DATA_CMD_LOAD_MF1_BLOCK_DATA (4000)
|
||||
#define DATA_CMD_LOAD_MF1_EMU_BLOCK_DATA (4000)
|
||||
#define DATA_CMD_SET_MF1_ANTI_COLLISION_RES (4001)
|
||||
#define DATA_CMD_SET_MF1_ANTICOLLISION_INFO (4002)
|
||||
#define DATA_CMD_SET_MF1_ATS_RESOURCE (4003)
|
||||
#define DATA_CMD_SET_MF1_DETECTION_ENABLE (4004)
|
||||
#define DATA_CMD_GET_MF1_DETECTION_COUNT (4005)
|
||||
#define DATA_CMD_GET_MF1_DETECTION_RESULT (4006)
|
||||
#define DATA_CMD_GET_MF1_DETECTION_STATUS (4007)
|
||||
#define DATA_CMD_READ_MF1_EMU_BLOCK_DATA (4008)
|
||||
#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)
|
||||
//
|
||||
// ******************************************************************
|
||||
|
||||
@@ -82,11 +99,6 @@
|
||||
//
|
||||
// ******************************************************************
|
||||
#define DATA_CMD_SET_EM410X_EMU_ID (5000)
|
||||
#define DATA_CMD_SET_MF1_ANTICOLLISION_INFO (5001)
|
||||
#define DATA_CMD_SET_MF1_ATS_RESOURCE (5002)
|
||||
#define DATA_CMD_SET_MF1_DETECTION_ENABLE (5003)
|
||||
#define DATA_CMD_GET_MF1_DETECTION_COUNT (5004)
|
||||
#define DATA_CMD_GET_MF1_DETECTION_RESULT (5005)
|
||||
#define DATA_CMD_GET_MF1_DETECTION_STATUS (5006)
|
||||
#define DATA_CMD_GET_EM410X_EMU_ID (5001)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include <nrfx.h>
|
||||
|
||||
#if NRFX_CHECK(NRFX_NFCT_ENABLED)
|
||||
// ChameleonUltra: workaround because NFC IRQ gets repetitively called when in HF field once a comm has started
|
||||
#include "bsp_wdt.h"
|
||||
|
||||
#include <nrfx_nfct.h>
|
||||
|
||||
@@ -907,6 +909,8 @@ void nrfx_nfct_irq_handler(void)
|
||||
m_nfct_cb.config.cb(&nfct_evt);
|
||||
}
|
||||
}
|
||||
// ChameleonUltra: workaround because NFC IRQ gets repetitively called when in HF field once a comm has started
|
||||
bsp_wdt_feed();
|
||||
}
|
||||
|
||||
#endif // NRFX_CHECK(NRFX_NFCT_ENABLED)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
import enum
|
||||
import struct
|
||||
|
||||
import chameleon_com
|
||||
import chameleon_status
|
||||
@@ -33,6 +34,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
|
||||
@@ -47,13 +50,28 @@ DATA_CMD_MF1_WRITE_ONE_BLOCK = 2009
|
||||
DATA_CMD_SCAN_EM410X_TAG = 3000
|
||||
DATA_CMD_WRITE_EM410X_TO_T5577 = 3001
|
||||
|
||||
DATA_CMD_LOAD_MF1_BLOCK_DATA = 4000
|
||||
DATA_CMD_LOAD_MF1_EMU_BLOCK_DATA = 4000
|
||||
DATA_CMD_SET_MF1_ANTI_COLLISION_RES = 4001
|
||||
|
||||
DATA_CMD_SET_MF1_DETECTION_ENABLE = 4004
|
||||
DATA_CMD_GET_MF1_DETECTION_COUNT = 4005
|
||||
DATA_CMD_GET_MF1_DETECTION_RESULT = 4006
|
||||
|
||||
DATA_CMD_READ_MF1_EMU_BLOCK_DATA = 4008
|
||||
|
||||
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
|
||||
DATA_CMD_GET_EM410X_EMU_ID = 5001
|
||||
|
||||
|
||||
@enum.unique
|
||||
class SlotNumber(enum.IntEnum):
|
||||
@@ -67,7 +85,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
|
||||
|
||||
@@ -79,13 +97,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):
|
||||
@@ -101,18 +118,19 @@ class TagSenseType(enum.IntEnum):
|
||||
return "HF"
|
||||
return "None"
|
||||
|
||||
|
||||
@enum.unique
|
||||
class TagSpecificType(enum.IntEnum):
|
||||
# 特定的且必须存在的标志不存在的类型
|
||||
# Empty slot
|
||||
TAG_TYPE_UNKNOWN = 0
|
||||
# 125khz(ID卡)系列
|
||||
# 125 kHz(ID)cards
|
||||
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
|
||||
@@ -144,6 +162,33 @@ 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 ChameleonCMD:
|
||||
"""
|
||||
Chameleon cmd function
|
||||
@@ -159,25 +204,25 @@ class ChameleonCMD:
|
||||
"""
|
||||
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 +230,7 @@ class ChameleonCMD:
|
||||
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):
|
||||
@@ -202,21 +247,21 @@ class ChameleonCMD:
|
||||
扫描场内的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):
|
||||
"""
|
||||
@@ -326,7 +371,7 @@ class ChameleonCMD:
|
||||
读取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)
|
||||
|
||||
@expect_response(chameleon_status.Device.LF_TAG_OK)
|
||||
def write_em_410x_to_t55xx(self, id_bytes: bytearray):
|
||||
@@ -336,10 +381,7 @@ class ChameleonCMD:
|
||||
: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()
|
||||
@@ -354,20 +396,20 @@ class ChameleonCMD:
|
||||
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)
|
||||
|
||||
@expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS)
|
||||
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
|
||||
@@ -420,7 +462,7 @@ class ChameleonCMD:
|
||||
return self.device.send_cmd_sync(DATA_CMD_SET_SLOT_ENABLE, 0X00, data)
|
||||
|
||||
@expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS)
|
||||
def set_em140x_sim_id(self, id_bytes: bytearray):
|
||||
def set_em410x_sim_id(self, id_bytes: bytearray):
|
||||
"""
|
||||
设置EM410x模拟的卡号
|
||||
:param id_bytes: 卡号的字节
|
||||
@@ -429,6 +471,12 @@ class ChameleonCMD:
|
||||
if len(id_bytes) != 5:
|
||||
raise ValueError("The id bytes length must equal 5")
|
||||
return self.device.send_cmd_sync(DATA_CMD_SET_EM410X_EMU_ID, 0x00, id_bytes)
|
||||
|
||||
def get_em410x_sim_id(self):
|
||||
"""
|
||||
Get the simulated EM410x card id
|
||||
"""
|
||||
return self.device.send_cmd_sync(DATA_CMD_GET_EM410X_EMU_ID, 0x00)
|
||||
|
||||
@expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS)
|
||||
def set_mf1_detection_enable(self, enable: bool):
|
||||
@@ -446,7 +494,7 @@ class ChameleonCMD:
|
||||
获取当前侦测记录的统计个数
|
||||
: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)
|
||||
|
||||
@expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS)
|
||||
def get_mf1_detection_log(self, index: int):
|
||||
@@ -470,7 +518,14 @@ class ChameleonCMD:
|
||||
data = bytearray()
|
||||
data.append(block_start & 0xFF)
|
||||
data.extend(block_data)
|
||||
return self.device.send_cmd_sync(DATA_CMD_LOAD_MF1_BLOCK_DATA, 0x00, data)
|
||||
return self.device.send_cmd_sync(DATA_CMD_LOAD_MF1_EMU_BLOCK_DATA, 0x00, data)
|
||||
|
||||
def get_mf1_block_data(self, block_start: int, block_count: int):
|
||||
"""
|
||||
Gets data for selected block range
|
||||
"""
|
||||
data = struct.pack('<BH', block_start, block_count)
|
||||
return self.device.send_cmd_sync(DATA_CMD_READ_MF1_EMU_BLOCK_DATA, 0x00, data)
|
||||
|
||||
@expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS)
|
||||
def set_mf1_anti_collision_res(self, sak: bytearray, atqa: bytearray, uid: bytearray):
|
||||
@@ -508,20 +563,55 @@ class ChameleonCMD:
|
||||
设置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):
|
||||
"""
|
||||
@@ -529,19 +619,25 @@ class ChameleonCMD:
|
||||
: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
|
||||
@@ -553,7 +649,7 @@ class ChameleonCMD:
|
||||
Store settings to flash memory
|
||||
"""
|
||||
return self.device.send_cmd_sync(DATA_CMD_SAVE_SETTINGS, 0x00)
|
||||
|
||||
|
||||
def factory_reset(self):
|
||||
"""
|
||||
Reset to factory settings
|
||||
@@ -568,12 +664,12 @@ if __name__ == '__main__':
|
||||
cml = ChameleonCMD(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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user