This commit is contained in:
RogueMaster
2022-11-29 01:01:12 -05:00
parent 557ed1ca8c
commit d0a29e2544
6 changed files with 686 additions and 472 deletions
@@ -114,39 +114,81 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
furi_string_cat_printf(temp_str, "\n");
switch(dev_data->nfcv_data.type) {
case NfcVTypePlain:
furi_string_cat_printf(temp_str, "Type: Plain\n");
break;
case NfcVTypeSlix:
furi_string_cat_printf(temp_str, "Type: SLIX\n");
furi_string_cat_printf(temp_str, "Keys:\n");
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
break;
case NfcVTypeSlixS:
furi_string_cat_printf(temp_str, "Type: SLIX-S\n");
furi_string_cat_printf(temp_str, "Keys:\n");
furi_string_cat_printf(temp_str, " Read %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read));
furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write));
furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
break;
case NfcVTypeSlixL:
furi_string_cat_printf(temp_str, "Type: SLIX-L\n");
furi_string_cat_printf(temp_str, "Keys:\n");
furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
break;
case NfcVTypeSlix2:
furi_string_cat_printf(temp_str, "Type: SLIX2\n");
furi_string_cat_printf(temp_str, "Keys:\n");
furi_string_cat_printf(temp_str, " Read %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read));
furi_string_cat_printf(temp_str, " Write %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write));
furi_string_cat_printf(temp_str, " Privacy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
furi_string_cat_printf(temp_str, " Destroy %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
furi_string_cat_printf(temp_str, " EAS %08lX\n", nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
break;
case NfcVTypePlain:
furi_string_cat_printf(temp_str, "Type: Plain\n");
break;
case NfcVTypeSlix:
furi_string_cat_printf(temp_str, "Type: SLIX\n");
furi_string_cat_printf(temp_str, "Keys:\n");
furi_string_cat_printf(
temp_str,
" EAS %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
break;
case NfcVTypeSlixS:
furi_string_cat_printf(temp_str, "Type: SLIX-S\n");
furi_string_cat_printf(temp_str, "Keys:\n");
furi_string_cat_printf(
temp_str,
" Read %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read));
furi_string_cat_printf(
temp_str,
" Write %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write));
furi_string_cat_printf(
temp_str,
" Privacy %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
furi_string_cat_printf(
temp_str,
" Destroy %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
furi_string_cat_printf(
temp_str,
" EAS %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
break;
case NfcVTypeSlixL:
furi_string_cat_printf(temp_str, "Type: SLIX-L\n");
furi_string_cat_printf(temp_str, "Keys:\n");
furi_string_cat_printf(
temp_str,
" Privacy %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
furi_string_cat_printf(
temp_str,
" Destroy %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
furi_string_cat_printf(
temp_str,
" EAS %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
break;
case NfcVTypeSlix2:
furi_string_cat_printf(temp_str, "Type: SLIX2\n");
furi_string_cat_printf(temp_str, "Keys:\n");
furi_string_cat_printf(
temp_str,
" Read %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read));
furi_string_cat_printf(
temp_str,
" Write %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write));
furi_string_cat_printf(
temp_str,
" Privacy %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy));
furi_string_cat_printf(
temp_str,
" Destroy %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy));
furi_string_cat_printf(
temp_str,
" EAS %08lX\n",
nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas));
break;
default:
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
break;
+1 -1
View File
@@ -159,7 +159,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
FuriHalNfcTxRxContext tx_rx = {};
uint8_t *key_data = nfcv_data->sub_data.slix.key_privacy;
uint8_t* key_data = nfcv_data->sub_data.slix.key_privacy;
uint32_t key = 0;
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
+359 -247
View File
@@ -22,8 +22,7 @@ ReturnCode nfcv_inventory(uint8_t* uid) {
for(int tries = 0; tries < 5; tries++) {
/* TODO: needs proper abstraction via fury_hal(_ll)_* */
ret = rfalNfcvPollerInventory(
RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received);
ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received);
if(ret == ERR_NONE) {
break;
@@ -39,10 +38,7 @@ ReturnCode nfcv_inventory(uint8_t* uid) {
return ret;
}
ReturnCode nfcv_read_blocks(
NfcVReader* reader,
NfcVData* data) {
ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data) {
UNUSED(reader);
uint16_t received = 0;
@@ -53,8 +49,7 @@ ReturnCode nfcv_read_blocks(
ReturnCode ret = ERR_NONE;
for(int tries = 0; tries < 5; tries++) {
ret = rfalNfcvPollerReadSingleBlock(
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block,
rxBuf, sizeof(rxBuf), &received);
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block, rxBuf, sizeof(rxBuf), &received);
if(ret == ERR_NONE) {
break;
@@ -65,9 +60,13 @@ ReturnCode nfcv_read_blocks(
return ret;
}
memcpy(&(data->data[block * data->block_size]), &rxBuf[1], data->block_size);
FURI_LOG_D(TAG, " %02X %02X %02X %02X",
data->data[block * data->block_size + 0], data->data[block * data->block_size + 1],
data->data[block * data->block_size + 2], data->data[block * data->block_size + 3]);
FURI_LOG_D(
TAG,
" %02X %02X %02X %02X",
data->data[block * data->block_size + 0],
data->data[block * data->block_size + 1],
data->data[block * data->block_size + 2],
data->data[block * data->block_size + 3]);
}
return ERR_NONE;
@@ -102,10 +101,25 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data) {
data->block_num = rxBuf[12] + 1;
data->block_size = rxBuf[13] + 1;
data->ic_ref = rxBuf[14];
FURI_LOG_D(TAG, " UID: %02X %02X %02X %02X %02X %02X %02X %02X",
nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3],
nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]);
FURI_LOG_D(TAG, " DSFID %d, AFI %d, Blocks %d, Size %d, IC Ref %d", data->dsfid, data->afi, data->block_num, data->block_size, data->ic_ref);
FURI_LOG_D(
TAG,
" UID: %02X %02X %02X %02X %02X %02X %02X %02X",
nfc_data->uid[0],
nfc_data->uid[1],
nfc_data->uid[2],
nfc_data->uid[3],
nfc_data->uid[4],
nfc_data->uid[5],
nfc_data->uid[6],
nfc_data->uid[7]);
FURI_LOG_D(
TAG,
" DSFID %d, AFI %d, Blocks %d, Size %d, IC Ref %d",
data->dsfid,
data->afi,
data->block_num,
data->block_size,
data->ic_ref);
return ret;
}
FURI_LOG_D(TAG, "Failed: %d", ret);
@@ -113,10 +127,7 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data) {
return ret;
}
bool nfcv_read_card(
NfcVReader* reader,
FuriHalNfcDevData* nfc_data,
NfcVData* nfcv_data) {
bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
furi_assert(reader);
furi_assert(nfc_data);
furi_assert(nfcv_data);
@@ -148,15 +159,13 @@ bool nfcv_read_card(
return true;
}
void nfcv_crc(uint8_t* data, uint32_t length) {
uint32_t reg = 0xFFFF;
for (size_t i = 0; i < length; i++) {
for(size_t i = 0; i < length; i++) {
reg = reg ^ ((uint32_t)data[i]);
for (size_t j = 0; j < 8; j++) {
if (reg & 0x0001) {
for(size_t j = 0; j < 8; j++) {
if(reg & 0x0001) {
reg = (reg >> 1) ^ 0x8408;
} else {
reg = (reg >> 1);
@@ -198,15 +207,18 @@ void nfcv_emu_alloc(NfcVData* data) {
/* unmodulated 256/fc signal as building block */
data->emu_air.nfcv_resp_unmod_256 = digital_signal_alloc(4);
data->emu_air.nfcv_resp_unmod_256->start_level = false;
data->emu_air.nfcv_resp_unmod_256->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S);
data->emu_air.nfcv_resp_unmod_256->edge_timings[0] =
(uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S);
data->emu_air.nfcv_resp_unmod_256->edge_cnt = 1;
}
if(!data->emu_air.nfcv_resp_pulse_32) {
/* modulated fc/32 pulse as building block */
data->emu_air.nfcv_resp_pulse_32 = digital_signal_alloc(4);
data->emu_air.nfcv_resp_pulse_32->start_level = true;
data->emu_air.nfcv_resp_pulse_32->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
data->emu_air.nfcv_resp_pulse_32->edge_timings[1] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
data->emu_air.nfcv_resp_pulse_32->edge_timings[0] =
(uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
data->emu_air.nfcv_resp_pulse_32->edge_timings[1] =
(uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
data->emu_air.nfcv_resp_pulse_32->edge_cnt = 2;
}
if(!data->emu_air.nfcv_resp_one) {
@@ -250,16 +262,26 @@ void nfcv_emu_alloc(NfcVData* data) {
digital_signal_append(data->emu_air.nfcv_resp_eof, data->emu_air.nfcv_resp_unmod_256);
}
digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_SOF, data->emu_air.nfcv_resp_sof);
digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_BIT0, data->emu_air.nfcv_resp_zero);
digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_BIT1, data->emu_air.nfcv_resp_one);
digital_sequence_set_signal(data->emu_air.nfcv_signal, NFCV_SIG_EOF, data->emu_air.nfcv_resp_eof);
digital_sequence_set_signal(
data->emu_air.nfcv_signal, NFCV_SIG_SOF, data->emu_air.nfcv_resp_sof);
digital_sequence_set_signal(
data->emu_air.nfcv_signal, NFCV_SIG_BIT0, data->emu_air.nfcv_resp_zero);
digital_sequence_set_signal(
data->emu_air.nfcv_signal, NFCV_SIG_BIT1, data->emu_air.nfcv_resp_one);
digital_sequence_set_signal(
data->emu_air.nfcv_signal, NFCV_SIG_EOF, data->emu_air.nfcv_resp_eof);
}
void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint8_t length, NfcVSendFlags flags) {
void nfcv_emu_send(
FuriHalNfcTxRxContext* tx_rx,
NfcVData* nfcv,
uint8_t* data,
uint8_t length,
NfcVSendFlags flags) {
/* picked default value (0) to match the most common format */
if(!flags) {
flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof | NfcVSendFlagsOneSubcarrier | NfcVSendFlagsHighRate;
flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof |
NfcVSendFlagsOneSubcarrier | NfcVSendFlagsHighRate;
}
if(flags & NfcVSendFlagsCrc) {
@@ -278,7 +300,8 @@ void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data,
uint32_t bit_pos = bit_total % 8;
uint8_t bit_val = 0x01 << bit_pos;
digital_sequence_add(nfcv->emu_air.nfcv_signal, (data[byte_pos] & bit_val) ? NFCV_SIG_BIT1 : NFCV_SIG_BIT0);
digital_sequence_add(
nfcv->emu_air.nfcv_signal, (data[byte_pos] & bit_val) ? NFCV_SIG_BIT1 : NFCV_SIG_BIT0);
}
if(flags & NfcVSendFlagsEof) {
@@ -295,35 +318,40 @@ void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data,
}
}
static void nfcv_uidcpy(uint8_t *dst, uint8_t *src) {
static void nfcv_uidcpy(uint8_t* dst, uint8_t* src) {
for(int pos = 0; pos < 8; pos++) {
dst[pos] = src[7-pos];
dst[pos] = src[7 - pos];
}
}
static int nfcv_uidcmp(uint8_t *dst, uint8_t *src) {
static int nfcv_uidcmp(uint8_t* dst, uint8_t* src) {
for(int pos = 0; pos < 8; pos++) {
if(dst[pos] != src[7-pos]) {
if(dst[pos] != src[7 - pos]) {
return 1;
}
}
return 0;
}
void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint8_t* payload, uint32_t payload_length) {
void nfcv_emu_handle_packet(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
void* nfcv_data_in,
uint8_t* payload,
uint32_t payload_length) {
if(!payload_length) {
return;
}
NfcVData* nfcv_data = (NfcVData*)nfcv_data_in;
NfcVEmuProtocolCtx* ctx = &nfcv_data->emu_protocol_ctx;
ctx->frame = payload;
ctx->frame_length = payload_length;
ctx->flags = ctx->frame[0];
ctx->command = ctx->frame[1];
ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && (ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS);
ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) &&
(ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS);
ctx->advanced = (ctx->command >= 0xA0);
ctx->address_offset = 2 + (ctx->advanced ? 1 : 0);
ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0);
@@ -340,116 +368,165 @@ void nfcv_emu_handle_packet(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc
uint8_t* address = &ctx->frame[ctx->address_offset];
if(nfcv_uidcmp(address, nfc_data->uid)) {
FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", ctx->command);
FURI_LOG_D(TAG, " dest: %02X%02X%02X%02X%02X%02X%02X%02X", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]);
FURI_LOG_D(TAG, " our UID: %02X%02X%02X%02X%02X%02X%02X%02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3], nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]);
FURI_LOG_D(
TAG,
" dest: %02X%02X%02X%02X%02X%02X%02X%02X",
address[7],
address[6],
address[5],
address[4],
address[3],
address[2],
address[1],
address[0]);
FURI_LOG_D(
TAG,
" our UID: %02X%02X%02X%02X%02X%02X%02X%02X",
nfc_data->uid[0],
nfc_data->uid[1],
nfc_data->uid[2],
nfc_data->uid[3],
nfc_data->uid[4],
nfc_data->uid[5],
nfc_data->uid[6],
nfc_data->uid[7]);
return;
}
}
/* unfortunately our response is quicker than the original NFC tag which causes frame misses */
furi_delay_us(270);
switch(ctx->command) {
case ISO15693_INVENTORY: {
ctx->response_buffer[0] = ISO15693_NOERROR;
ctx->response_buffer[1] = nfcv_data->dsfid;
nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid);
case ISO15693_INVENTORY: {
ctx->response_buffer[0] = ISO15693_NOERROR;
ctx->response_buffer[1] = nfcv_data->dsfid;
nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid);
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY");
break;
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY");
break;
}
case ISO15693_STAYQUIET: {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "STAYQUIET");
break;
}
case ISO15693_LOCKBLOCK: {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCKBLOCK");
break;
}
case ISO15693_SELECT: {
ctx->response_buffer[0] = ISO15693_NOERROR;
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT");
break;
}
case ISO15693_READ_MULTI_BLOCK:
case ISO15693_READBLOCK: {
uint8_t block = ctx->frame[ctx->payload_offset];
uint8_t blocks = 1;
if(ctx->command == ISO15693_READ_MULTI_BLOCK) {
blocks = ctx->frame[ctx->payload_offset + 1] + 1;
}
case ISO15693_STAYQUIET: {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "STAYQUIET");
break;
}
case ISO15693_LOCKBLOCK: {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCKBLOCK");
break;
}
case ISO15693_SELECT: {
ctx->response_buffer[0] = ISO15693_NOERROR;
if(block + blocks > nfcv_data->block_num) {
ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC;
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT");
break;
} else {
ctx->response_buffer[0] = ISO15693_NOERROR;
memcpy(
&ctx->response_buffer[1],
&nfcv_data->data[nfcv_data->block_size * block],
nfcv_data->block_size * blocks);
nfcv_emu_send(
tx_rx,
nfcv_data,
ctx->response_buffer,
1 + nfcv_data->block_size * blocks,
ctx->response_flags);
}
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block);
break;
}
case ISO15693_WRITE_MULTI_BLOCK:
case ISO15693_WRITEBLOCK: {
uint8_t block = ctx->frame[ctx->payload_offset];
uint8_t blocks = 1;
uint8_t data_pos = 1;
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
blocks = ctx->frame[ctx->payload_offset + 1] + 1;
data_pos++;
}
case ISO15693_READ_MULTI_BLOCK:
case ISO15693_READBLOCK: {
uint8_t block = ctx->frame[ctx->payload_offset];
uint8_t blocks = 1;
uint8_t* data = &ctx->frame[ctx->payload_offset + data_pos];
uint32_t data_len = nfcv_data->block_size * blocks;
if(ctx->command == ISO15693_READ_MULTI_BLOCK) {
blocks = ctx->frame[ctx->payload_offset + 1] + 1;
}
if(block + blocks > nfcv_data->block_num) {
ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC;
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
} else {
ctx->response_buffer[0] = ISO15693_NOERROR;
memcpy(&ctx->response_buffer[1], &nfcv_data->data[nfcv_data->block_size * block], nfcv_data->block_size * blocks);
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1 + nfcv_data->block_size * blocks, ctx->response_flags);
}
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block);
break;
if(block + blocks > nfcv_data->block_num ||
ctx->payload_offset + data_len + 2 > payload_length) {
ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC;
} else {
ctx->response_buffer[0] = ISO15693_NOERROR;
memcpy(
&nfcv_data->data[nfcv_data->block_size * block],
&ctx->frame[ctx->payload_offset + data_pos],
data_len);
}
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
case ISO15693_WRITE_MULTI_BLOCK:
case ISO15693_WRITEBLOCK: {
uint8_t block = ctx->frame[ctx->payload_offset];
uint8_t blocks = 1;
uint8_t data_pos = 1;
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
blocks = ctx->frame[ctx->payload_offset + 1] + 1;
data_pos++;
}
uint8_t *data = &ctx->frame[ctx->payload_offset + data_pos];
uint32_t data_len = nfcv_data->block_size * blocks;
if(block + blocks > nfcv_data->block_num || ctx->payload_offset + data_len + 2 > payload_length) {
ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC;
} else {
ctx->response_buffer[0] = ISO15693_NOERROR;
memcpy(&nfcv_data->data[nfcv_data->block_size * block], &ctx->frame[ctx->payload_offset + data_pos], data_len);
}
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE MULTI BLOCK %d, %d blocks", block, blocks);
} else {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE BLOCK %d <- %02X %02X %02X %02X", block, data[0], data[1], data[2], data[3]);
}
break;
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"WRITE MULTI BLOCK %d, %d blocks",
block,
blocks);
} else {
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"WRITE BLOCK %d <- %02X %02X %02X %02X",
block,
data[0],
data[1],
data[2],
data[3]);
}
break;
}
case ISO15693_GET_SYSTEM_INFO: {
ctx->response_buffer[0] = ISO15693_NOERROR;
ctx->response_buffer[1] = 0x0F;
nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid);
ctx->response_buffer[10] = nfcv_data->dsfid; /* DSFID */
ctx->response_buffer[11] = nfcv_data->afi; /* AFI */
ctx->response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */
ctx->response_buffer[13] = nfcv_data->block_size - 1; /* block size */
ctx->response_buffer[14] = nfcv_data->ic_ref; /* IC reference */
case ISO15693_GET_SYSTEM_INFO: {
ctx->response_buffer[0] = ISO15693_NOERROR;
ctx->response_buffer[1] = 0x0F;
nfcv_uidcpy(&ctx->response_buffer[2], nfc_data->uid);
ctx->response_buffer[10] = nfcv_data->dsfid; /* DSFID */
ctx->response_buffer[11] = nfcv_data->afi; /* AFI */
ctx->response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */
ctx->response_buffer[13] = nfcv_data->block_size - 1; /* block size */
ctx->response_buffer[14] = nfcv_data->ic_ref; /* IC reference */
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 15, ctx->response_flags);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO");
break;
}
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 15, ctx->response_flags);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO");
break;
}
default:
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "unsupported: %02X", ctx->command);
break;
default:
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"unsupported: %02X",
ctx->command);
break;
}
if(strlen(nfcv_data->last_command) > 0) {
FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command);
FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command);
}
}
@@ -467,30 +544,38 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
nfcv_data->emu_protocol_handler = &nfcv_emu_handle_packet;
FURI_LOG_D(TAG, "Starting NfcV emulation");
FURI_LOG_D(TAG, " UID: %02X %02X %02X %02X %02X %02X %02X %02X",
nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3],
nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]);
FURI_LOG_D(
TAG,
" UID: %02X %02X %02X %02X %02X %02X %02X %02X",
nfc_data->uid[0],
nfc_data->uid[1],
nfc_data->uid[2],
nfc_data->uid[3],
nfc_data->uid[4],
nfc_data->uid[5],
nfc_data->uid[6],
nfc_data->uid[7]);
switch(nfcv_data->type) {
case NfcVTypeSlixL:
FURI_LOG_D(TAG, " Card type: SLIX-L");
slix_l_prepare(nfcv_data);
break;
case NfcVTypeSlixS:
FURI_LOG_D(TAG, " Card type: SLIX-S");
slix_s_prepare(nfcv_data);
break;
case NfcVTypeSlix2:
FURI_LOG_D(TAG, " Card type: SLIX2");
slix2_prepare(nfcv_data);
break;
case NfcVTypeSlix:
FURI_LOG_D(TAG, " Card type: SLIX");
slix_prepare(nfcv_data);
break;
case NfcVTypePlain:
FURI_LOG_D(TAG, " Card type: Plain");
break;
case NfcVTypeSlixL:
FURI_LOG_D(TAG, " Card type: SLIX-L");
slix_l_prepare(nfcv_data);
break;
case NfcVTypeSlixS:
FURI_LOG_D(TAG, " Card type: SLIX-S");
slix_s_prepare(nfcv_data);
break;
case NfcVTypeSlix2:
FURI_LOG_D(TAG, " Card type: SLIX2");
slix2_prepare(nfcv_data);
break;
case NfcVTypeSlix:
FURI_LOG_D(TAG, " Card type: SLIX");
slix_prepare(nfcv_data);
break;
case NfcVTypePlain:
FURI_LOG_D(TAG, " Card type: Plain");
break;
}
/* allocate a 512 edge buffer, more than enough */
@@ -510,8 +595,11 @@ void nfcv_emu_deinit(NfcVData* nfcv_data) {
pulse_reader_free(nfcv_data->emu_air.reader_signal);
}
bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms) {
bool nfcv_emu_loop(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
NfcVData* nfcv_data,
uint32_t timeout_ms) {
bool ret = false;
uint32_t frame_state = NFCV_FRAME_STATE_SOF1;
uint32_t periods_previous = 0;
@@ -523,8 +611,8 @@ bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, Nf
bool wait_for_pulse = false;
while(true) {
uint32_t periods = pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000);
uint32_t periods =
pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000);
if(periods == PULSE_READER_NO_EDGE) {
break;
@@ -533,113 +621,137 @@ bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, Nf
if(wait_for_pulse) {
wait_for_pulse = false;
if(periods != 1) {
snprintf(reset_reason, sizeof(reset_reason), "SOF: Expected a single low pulse in state %lu, but got %lu", frame_state, periods);
snprintf(
reset_reason,
sizeof(reset_reason),
"SOF: Expected a single low pulse in state %lu, but got %lu",
frame_state,
periods);
frame_state = NFCV_FRAME_STATE_RESET;
}
continue;
}
switch(frame_state) {
case NFCV_FRAME_STATE_SOF1:
if(periods == 1) {
frame_state = NFCV_FRAME_STATE_SOF2;
} else {
frame_state = NFCV_FRAME_STATE_SOF1;
break;
}
case NFCV_FRAME_STATE_SOF1:
if(periods == 1) {
frame_state = NFCV_FRAME_STATE_SOF2;
} else {
frame_state = NFCV_FRAME_STATE_SOF1;
break;
}
break;
case NFCV_FRAME_STATE_SOF2:
/* waiting for the second low period, telling us about coding */
if(periods == 6) {
frame_state = NFCV_FRAME_STATE_CODING_256;
periods_previous = 0;
wait_for_pulse = true;
} else if(periods == 4) {
frame_state = NFCV_FRAME_STATE_CODING_4;
periods_previous = 2;
wait_for_pulse = true;
} else {
snprintf(reset_reason, sizeof(reset_reason), "SOF: Expected 4/6 periods, got %lu", periods);
frame_state = NFCV_FRAME_STATE_SOF1;
}
break;
case NFCV_FRAME_STATE_CODING_256:
if(periods_previous > periods) {
snprintf(reset_reason, sizeof(reset_reason), "1oo256: Missing %lu periods from previous symbol, got %lu", periods_previous, periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
/* previous symbol left us with some pulse periods */
periods -= periods_previous;
if(periods > 512) {
snprintf(reset_reason, sizeof(reset_reason), "1oo256: %lu periods is too much", periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
if(periods == 2) {
frame_state = NFCV_FRAME_STATE_EOF;
break;
}
periods_previous = 512 - (periods + 1);
byte_value = (periods - 1) / 2;
frame_payload[frame_pos++] = (uint8_t)byte_value;
wait_for_pulse = true;
break;
case NFCV_FRAME_STATE_CODING_4:
if(periods_previous > periods) {
snprintf(reset_reason, sizeof(reset_reason), "1oo4: Missing %lu periods from previous symbol, got %lu", periods_previous, periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
/* previous symbol left us with some pulse periods */
periods -= periods_previous;
case NFCV_FRAME_STATE_SOF2:
/* waiting for the second low period, telling us about coding */
if(periods == 6) {
frame_state = NFCV_FRAME_STATE_CODING_256;
periods_previous = 0;
byte_value >>= 2;
bits_received += 2;
if(periods == 1) {
byte_value |= 0x00 << 6;
periods_previous = 6;
} else if(periods == 3) {
byte_value |= 0x01 << 6;
periods_previous = 4;
} else if(periods == 5) {
byte_value |= 0x02 << 6;
periods_previous = 2;
} else if(periods == 7) {
byte_value |= 0x03 << 6;
periods_previous = 0;
} else if(periods == 2) {
frame_state = NFCV_FRAME_STATE_EOF;
break;
} else {
snprintf(reset_reason, sizeof(reset_reason), "1oo4: Expected 1/3/5/7 low pulses, but got %lu", periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
if(bits_received >= 8) {
frame_payload[frame_pos++] = (uint8_t)byte_value;
bits_received = 0;
}
wait_for_pulse = true;
} else if(periods == 4) {
frame_state = NFCV_FRAME_STATE_CODING_4;
periods_previous = 2;
wait_for_pulse = true;
} else {
snprintf(
reset_reason,
sizeof(reset_reason),
"SOF: Expected 4/6 periods, got %lu",
periods);
frame_state = NFCV_FRAME_STATE_SOF1;
}
break;
case NFCV_FRAME_STATE_CODING_256:
if(periods_previous > periods) {
snprintf(
reset_reason,
sizeof(reset_reason),
"1oo256: Missing %lu periods from previous symbol, got %lu",
periods_previous,
periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
/* previous symbol left us with some pulse periods */
periods -= periods_previous;
if(periods > 512) {
snprintf(
reset_reason, sizeof(reset_reason), "1oo256: %lu periods is too much", periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
if(periods == 2) {
frame_state = NFCV_FRAME_STATE_EOF;
break;
}
periods_previous = 512 - (periods + 1);
byte_value = (periods - 1) / 2;
frame_payload[frame_pos++] = (uint8_t)byte_value;
wait_for_pulse = true;
break;
case NFCV_FRAME_STATE_CODING_4:
if(periods_previous > periods) {
snprintf(
reset_reason,
sizeof(reset_reason),
"1oo4: Missing %lu periods from previous symbol, got %lu",
periods_previous,
periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
/* previous symbol left us with some pulse periods */
periods -= periods_previous;
periods_previous = 0;
byte_value >>= 2;
bits_received += 2;
if(periods == 1) {
byte_value |= 0x00 << 6;
periods_previous = 6;
} else if(periods == 3) {
byte_value |= 0x01 << 6;
periods_previous = 4;
} else if(periods == 5) {
byte_value |= 0x02 << 6;
periods_previous = 2;
} else if(periods == 7) {
byte_value |= 0x03 << 6;
periods_previous = 0;
} else if(periods == 2) {
frame_state = NFCV_FRAME_STATE_EOF;
break;
} else {
snprintf(
reset_reason,
sizeof(reset_reason),
"1oo4: Expected 1/3/5/7 low pulses, but got %lu",
periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
if(bits_received >= 8) {
frame_payload[frame_pos++] = (uint8_t)byte_value;
bits_received = 0;
}
wait_for_pulse = true;
break;
}
/* post-state-machine cleanup and reset */
if(frame_state == NFCV_FRAME_STATE_RESET) {
frame_state = NFCV_FRAME_STATE_SOF1;
FURI_LOG_D(TAG, "Resetting state machine, reason: '%s'", reset_reason);
} else if(frame_state == NFCV_FRAME_STATE_EOF) {
break;
+57 -41
View File
@@ -34,33 +34,33 @@
#define NFCV_SIG_EOF 3
/* ISO15693 command codes */
#define ISO15693_INVENTORY 0x01
#define ISO15693_STAYQUIET 0x02
#define ISO15693_READBLOCK 0x20
#define ISO15693_WRITEBLOCK 0x21
#define ISO15693_LOCKBLOCK 0x22
#define ISO15693_READ_MULTI_BLOCK 0x23
#define ISO15693_WRITE_MULTI_BLOCK 0x24
#define ISO15693_SELECT 0x25
#define ISO15693_RESET_TO_READY 0x26
#define ISO15693_WRITE_AFI 0x27
#define ISO15693_LOCK_AFI 0x28
#define ISO15693_WRITE_DSFID 0x29
#define ISO15693_LOCK_DSFID 0x2A
#define ISO15693_GET_SYSTEM_INFO 0x2B
#define ISO15693_READ_MULTI_SECSTATUS 0x2C
#define ISO15693_INVENTORY 0x01
#define ISO15693_STAYQUIET 0x02
#define ISO15693_READBLOCK 0x20
#define ISO15693_WRITEBLOCK 0x21
#define ISO15693_LOCKBLOCK 0x22
#define ISO15693_READ_MULTI_BLOCK 0x23
#define ISO15693_WRITE_MULTI_BLOCK 0x24
#define ISO15693_SELECT 0x25
#define ISO15693_RESET_TO_READY 0x26
#define ISO15693_WRITE_AFI 0x27
#define ISO15693_LOCK_AFI 0x28
#define ISO15693_WRITE_DSFID 0x29
#define ISO15693_LOCK_DSFID 0x2A
#define ISO15693_GET_SYSTEM_INFO 0x2B
#define ISO15693_READ_MULTI_SECSTATUS 0x2C
/* ISO15693 RESPONSE ERROR CODES */
#define ISO15693_NOERROR 0x00
#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported
#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error)
#define ISO15693_ERROR_CMD_OPTION 0x03 // Command option not supported
#define ISO15693_ERROR_GENERIC 0x0F // No additional Info about this error
#define ISO15693_ERROR_BLOCK_UNAVAILABLE 0x10
#define ISO15693_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again
#define ISO15693_ERROR_BLOCK_LOCKED 0x12 // cannot be changed
#define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful
#define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful
#define ISO15693_NOERROR 0x00
#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported
#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error)
#define ISO15693_ERROR_CMD_OPTION 0x03 // Command option not supported
#define ISO15693_ERROR_GENERIC 0x0F // No additional Info about this error
#define ISO15693_ERROR_BLOCK_UNAVAILABLE 0x10
#define ISO15693_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again
#define ISO15693_ERROR_BLOCK_LOCKED 0x12 // cannot be changed
#define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful
#define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful
typedef enum {
NfcVAuthMethodManual,
@@ -113,24 +113,31 @@ typedef struct {
DigitalSequence* nfcv_signal;
} NfcVEmuAir;
typedef struct {
uint8_t* frame; /* ISO15693-2 incoming raw data from air layer */
uint8_t frame_length; /* ISO15693-2 length of incoming data */
uint8_t* frame; /* ISO15693-2 incoming raw data from air layer */
uint8_t frame_length; /* ISO15693-2 length of incoming data */
uint8_t flags; /* ISO15693-3 flags of the header as specified */
uint8_t command; /* ISO15693-3 command at offset 1 as specified */
bool addressed; /* ISO15693-3 flags: addressed frame */
bool advanced; /* ISO15693-3 command: advanced command */
uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */
uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */
uint8_t flags; /* ISO15693-3 flags of the header as specified */
uint8_t command; /* ISO15693-3 command at offset 1 as specified */
bool addressed; /* ISO15693-3 flags: addressed frame */
bool advanced; /* ISO15693-3 command: advanced command */
uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */
uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */
uint8_t response_buffer[128]; /* pre-allocated response buffer */
NfcVSendFlags response_flags; /* flags to use when sending response */
uint8_t response_buffer[128]; /* pre-allocated response buffer */
NfcVSendFlags response_flags; /* flags to use when sending response */
} NfcVEmuProtocolCtx;
typedef void (*NfcVEmuProtocolHandler) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data, uint8_t* payload, uint32_t payload_length);
typedef bool (*NfcVEmuProtocolFilter) (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data);
typedef void (*NfcVEmuProtocolHandler)(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
void* nfcv_data,
uint8_t* payload,
uint32_t payload_length);
typedef bool (*NfcVEmuProtocolFilter)(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
void* nfcv_data);
typedef struct {
/* common ISO15693 fields */
@@ -161,7 +168,7 @@ typedef struct {
int16_t blocks_read;
} NfcVReader;
ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data);
ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data);
ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data);
ReturnCode nfcv_inventory(uint8_t* uid);
bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* data);
@@ -169,5 +176,14 @@ bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* d
void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data);
void nfcv_emu_deinit(NfcVData* nfcv_data);
bool nfcv_emu_loop(FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms);
void nfcv_emu_send(FuriHalNfcTxRxContext* tx_rx, NfcVData* nfcv, uint8_t* data, uint8_t length, NfcVSendFlags flags);
bool nfcv_emu_loop(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
NfcVData* nfcv_data,
uint32_t timeout_ms);
void nfcv_emu_send(
FuriHalNfcTxRxContext* tx_rx,
NfcVData* nfcv,
uint8_t* data,
uint8_t length,
NfcVSendFlags flags);
+177 -134
View File
@@ -9,7 +9,7 @@
#define TAG "SLIX"
static uint32_t slix_read_be(uint8_t *data, uint32_t length) {
static uint32_t slix_read_be(uint8_t* data, uint32_t length) {
uint32_t value = 0;
for(uint32_t pos = 0; pos < length; pos++) {
@@ -87,33 +87,32 @@ ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) {
uint16_t received = 0;
uint8_t rxBuf[32];
uint8_t cmd_set_pass[] = {
password_id,
data->sub_data.slix.rand[1],
data->sub_data.slix.rand[0],
data->sub_data.slix.rand[1],
data->sub_data.slix.rand[0]
};
uint8_t *password = NULL;
uint8_t cmd_set_pass[] = {
password_id,
data->sub_data.slix.rand[1],
data->sub_data.slix.rand[0],
data->sub_data.slix.rand[1],
data->sub_data.slix.rand[0]};
uint8_t* password = NULL;
switch(password_id) {
case SLIX_PASS_READ:
password = data->sub_data.slix.key_read;
break;
case SLIX_PASS_WRITE:
password = data->sub_data.slix.key_write;
break;
case SLIX_PASS_PRIVACY:
password = data->sub_data.slix.key_privacy;
break;
case SLIX_PASS_DESTROY:
password = data->sub_data.slix.key_destroy;
break;
case SLIX_PASS_EASAFI:
password = data->sub_data.slix.key_eas;
break;
default:
break;
case SLIX_PASS_READ:
password = data->sub_data.slix.key_read;
break;
case SLIX_PASS_WRITE:
password = data->sub_data.slix.key_write;
break;
case SLIX_PASS_PRIVACY:
password = data->sub_data.slix.key_privacy;
break;
case SLIX_PASS_DESTROY:
password = data->sub_data.slix.key_destroy;
break;
case SLIX_PASS_EASAFI:
password = data->sub_data.slix.key_eas;
break;
default:
break;
}
if(!password) {
@@ -138,21 +137,26 @@ ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) {
return ret;
}
bool slix_generic_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in, uint32_t password_supported) {
bool slix_generic_protocol_filter(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
void* nfcv_data_in,
uint32_t password_supported) {
furi_assert(tx_rx);
furi_assert(nfc_data);
furi_assert(nfcv_data_in);
NfcVData* nfcv_data = (NfcVData*)nfcv_data_in;
NfcVEmuProtocolCtx* ctx = &nfcv_data->emu_protocol_ctx;
NfcVSlixData* slix = &nfcv_data->sub_data.slix;
if(slix->privacy &&
ctx->command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER &&
ctx->command != ISO15693_CMD_NXP_SET_PASSWORD) {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
"command 0x%02X ignored, privacy mode", ctx->command);
if(slix->privacy && ctx->command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER &&
ctx->command != ISO15693_CMD_NXP_SET_PASSWORD) {
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"command 0x%02X ignored, privacy mode",
ctx->command);
FURI_LOG_D(TAG, "%s", nfcv_data->last_command);
return true;
}
@@ -160,115 +164,137 @@ bool slix_generic_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevDa
bool handled = false;
switch(ctx->command) {
case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: {
slix->rand[0] = furi_hal_random_get();
slix->rand[1] = furi_hal_random_get();
case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: {
slix->rand[0] = furi_hal_random_get();
slix->rand[1] = furi_hal_random_get();
ctx->response_buffer[0] = ISO15693_NOERROR;
ctx->response_buffer[1] = slix->rand[1];
ctx->response_buffer[2] = slix->rand[0];
ctx->response_buffer[0] = ISO15693_NOERROR;
ctx->response_buffer[1] = slix->rand[1];
ctx->response_buffer[2] = slix->rand[0];
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
"GET_RANDOM_NUMBER -> 0x%02X%02X", slix->rand[0], slix->rand[1]);
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags);
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"GET_RANDOM_NUMBER -> 0x%02X%02X",
slix->rand[0],
slix->rand[1]);
handled = true;
handled = true;
break;
}
case ISO15693_CMD_NXP_SET_PASSWORD: {
uint8_t password_id = ctx->frame[ctx->payload_offset];
if(!(password_id & password_supported)) {
break;
}
case ISO15693_CMD_NXP_SET_PASSWORD: {
uint8_t password_id = ctx->frame[ctx->payload_offset];
uint8_t* password_xored = &ctx->frame[ctx->payload_offset + 1];
uint8_t* rand = slix->rand;
uint8_t* password = NULL;
uint8_t password_rcv[4];
if(!(password_id & password_supported)) {
switch(password_id) {
case SLIX_PASS_READ:
password = slix->key_read;
break;
case SLIX_PASS_WRITE:
password = slix->key_write;
break;
case SLIX_PASS_PRIVACY:
password = slix->key_privacy;
break;
case SLIX_PASS_DESTROY:
password = slix->key_destroy;
break;
case SLIX_PASS_EASAFI:
password = slix->key_eas;
break;
default:
break;
}
for(int pos = 0; pos < 4; pos++) {
password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2];
}
uint32_t pass_expect = slix_read_be(password, 4);
uint32_t pass_received = slix_read_be(password_rcv, 4);
/* if the password is all-zeroes, just accept any password*/
if(!pass_expect || pass_expect == pass_received) {
switch(password_id) {
case SLIX_PASS_READ:
break;
case SLIX_PASS_WRITE:
break;
case SLIX_PASS_PRIVACY:
slix->privacy = false;
break;
case SLIX_PASS_DESTROY:
FURI_LOG_D(TAG, "Pooof! Got destroyed");
break;
case SLIX_PASS_EASAFI:
break;
default:
break;
}
uint8_t *password_xored = &ctx->frame[ctx->payload_offset + 1];
uint8_t *rand = slix->rand;
uint8_t *password = NULL;
uint8_t password_rcv[4];
switch(password_id) {
case SLIX_PASS_READ:
password = slix->key_read;
break;
case SLIX_PASS_WRITE:
password = slix->key_write;
break;
case SLIX_PASS_PRIVACY:
password = slix->key_privacy;
break;
case SLIX_PASS_DESTROY:
password = slix->key_destroy;
break;
case SLIX_PASS_EASAFI:
password = slix->key_eas;
break;
default:
break;
}
for(int pos = 0; pos < 4; pos++) {
password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2];
}
uint32_t pass_expect = slix_read_be(password, 4);
uint32_t pass_received = slix_read_be(password_rcv, 4);
/* if the password is all-zeroes, just accept any password*/
if(!pass_expect || pass_expect == pass_received) {
switch(password_id) {
case SLIX_PASS_READ:
break;
case SLIX_PASS_WRITE:
break;
case SLIX_PASS_PRIVACY:
slix->privacy = false;
break;
case SLIX_PASS_DESTROY:
FURI_LOG_D(TAG, "Pooof! Got destroyed");
break;
case SLIX_PASS_EASAFI:
break;
default:
break;
}
ctx->response_buffer[0] = ISO15693_NOERROR;
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
"SET_PASSWORD #%02X 0x%08lX OK", password_id, pass_received);
} else {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
"SET_PASSWORD #%02X 0x%08lX/%08lX FAIL", password_id, pass_received, pass_expect);
}
handled = true;
break;
}
case ISO15693_CMD_NXP_ENABLE_PRIVACY: {
ctx->response_buffer[0] = ISO15693_NOERROR;
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
"ISO15693_CMD_NXP_ENABLE_PRIVACY");
slix->privacy = true;
handled = true;
break;
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"SET_PASSWORD #%02X 0x%08lX OK",
password_id,
pass_received);
} else {
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"SET_PASSWORD #%02X 0x%08lX/%08lX FAIL",
password_id,
pass_received,
pass_expect);
}
handled = true;
break;
}
case ISO15693_CMD_NXP_ENABLE_PRIVACY: {
ctx->response_buffer[0] = ISO15693_NOERROR;
nfcv_emu_send(tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags);
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"ISO15693_CMD_NXP_ENABLE_PRIVACY");
slix->privacy = true;
handled = true;
break;
}
}
return handled;
}
bool slix_l_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) {
bool slix_l_protocol_filter(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
void* nfcv_data_in) {
furi_assert(tx_rx);
furi_assert(nfc_data);
furi_assert(nfcv_data_in);
bool handled = false;
/* many SLIX share some of the functions, place that in a generic handler */
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) {
if(slix_generic_protocol_filter(
tx_rx,
nfc_data,
nfcv_data_in,
SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) {
return true;
}
@@ -276,21 +302,26 @@ bool slix_l_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nf
}
void slix_l_prepare(NfcVData* nfcv_data) {
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(
TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
FURI_LOG_D(
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
nfcv_data->emu_protocol_filter = &slix_l_protocol_filter;
}
bool slix_s_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) {
bool slix_s_protocol_filter(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
void* nfcv_data_in) {
furi_assert(tx_rx);
furi_assert(nfc_data);
furi_assert(nfcv_data_in);
bool handled = false;
/* many SLIX share some of the functions, place that in a generic handler */
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) {
return true;
@@ -300,21 +331,26 @@ bool slix_s_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nf
}
void slix_s_prepare(NfcVData* nfcv_data) {
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(
TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
FURI_LOG_D(
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
nfcv_data->emu_protocol_filter = &slix_s_protocol_filter;
}
bool slix_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) {
bool slix_protocol_filter(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
void* nfcv_data_in) {
furi_assert(tx_rx);
furi_assert(nfc_data);
furi_assert(nfcv_data_in);
bool handled = false;
/* many SLIX share some of the functions, place that in a generic handler */
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) {
return true;
@@ -324,21 +360,26 @@ bool slix_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_
}
void slix_prepare(NfcVData* nfcv_data) {
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(
TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
FURI_LOG_D(
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
nfcv_data->emu_protocol_filter = &slix_protocol_filter;
}
bool slix2_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) {
bool slix2_protocol_filter(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
void* nfcv_data_in) {
furi_assert(tx_rx);
furi_assert(nfc_data);
furi_assert(nfcv_data_in);
bool handled = false;
/* many SLIX share some of the functions, place that in a generic handler */
if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) {
return true;
@@ -348,8 +389,10 @@ bool slix2_protocol_filter (FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc
}
void slix2_prepare(NfcVData* nfcv_data) {
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
FURI_LOG_D(TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(
TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
FURI_LOG_D(
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
+17 -16
View File
@@ -5,31 +5,32 @@
#include "nfc_util.h"
#include <furi_hal_nfc.h>
#define ISO15693_MANUFACTURER_NXP 0x04
#define ISO15693_MANUFACTURER_NXP 0x04
/* ISO15693-3 CUSTOM NXP COMMANDS */
#define ISO15693_CMD_NXP_SET_EAS 0xA2
#define ISO15693_CMD_NXP_RESET_EAS 0xA3
#define ISO15693_CMD_NXP_LOCK_EAS 0xA4
#define ISO15693_CMD_NXP_EAS_ALARM 0xA5
#define ISO15693_CMD_NXP_SET_EAS 0xA2
#define ISO15693_CMD_NXP_RESET_EAS 0xA3
#define ISO15693_CMD_NXP_LOCK_EAS 0xA4
#define ISO15693_CMD_NXP_EAS_ALARM 0xA5
#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6
#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0
#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4
#define ISO15693_CMD_NXP_DESTROY 0xB9
#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4
#define ISO15693_CMD_NXP_DESTROY 0xB9
#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA
/* available passwords */
#define SLIX_PASS_READ 0x01
#define SLIX_PASS_WRITE 0x02
#define SLIX_PASS_READ 0x01
#define SLIX_PASS_WRITE 0x02
#define SLIX_PASS_PRIVACY 0x04
#define SLIX_PASS_DESTROY 0x08
#define SLIX_PASS_EASAFI 0x10
#define SLIX_PASS_EASAFI 0x10
#define SLIX_PASS_ALL (SLIX_PASS_READ|SLIX_PASS_WRITE|SLIX_PASS_PRIVACY|SLIX_PASS_DESTROY|SLIX_PASS_EASAFI)
#define SLIX_PASS_ALL \
(SLIX_PASS_READ | SLIX_PASS_WRITE | SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)
bool slix_check_card_type(FuriHalNfcDevData* nfc_data);
bool slix2_check_card_type(FuriHalNfcDevData* nfc_data);