NFC: slight FeliCa refactor

This commit is contained in:
nullableVoidPtr
2022-12-28 21:32:25 +08:00
parent 8fecca3575
commit 653d0d7704
5 changed files with 223 additions and 199 deletions

View File

@@ -39,11 +39,12 @@
#include "rpc/rpc_app.h" #include "rpc/rpc_app.h"
#include <m-list.h>
#include <m-array.h> #include <m-array.h>
ARRAY_DEF(FelicaAreaPath, FelicaArea*, M_PTR_OPLIST); ARRAY_DEF(FelicaAreaPath, FelicaArea*, M_PTR_OPLIST)
ARRAY_DEF(FuriStringStack, FuriString*, M_PTR_OPLIST); LIST_DEF(FuriStringStack, FuriString*, FURI_STRING_OPLIST)
ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST); ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST)
#define NFC_TEXT_STORE_SIZE 128 #define NFC_TEXT_STORE_SIZE 128
#define NFC_APP_FOLDER ANY_PATH("nfc") #define NFC_APP_FOLDER ANY_PATH("nfc")

View File

@@ -1,8 +1,6 @@
#include "../nfc_i.h" #include "../nfc_i.h"
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#define SYSTEM_EVENT
void nfc_scene_felica_info_select_submenu_callback(void* context, uint32_t index) { void nfc_scene_felica_info_select_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = context; Nfc* nfc = context;
@@ -20,7 +18,7 @@ void nfc_scene_felica_info_select_on_enter(void* context) {
submenu_add_item(submenu, "[Actions]", 0, nfc_scene_felica_info_select_submenu_callback, nfc); submenu_add_item(submenu, "[Actions]", 0, nfc_scene_felica_info_select_submenu_callback, nfc);
uint8_t i = 1; uint8_t i = 1;
if(state->selected_system == NULL) { if(state->selected_system == NULL || state->selected_system->code == LITE_SYSTEM_CODE) {
submenu_set_header(submenu, "Systems"); submenu_set_header(submenu, "Systems");
FelicaSystemList_it_t it; FelicaSystemList_it_t it;
for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it); for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it);
@@ -59,8 +57,7 @@ void nfc_scene_felica_info_select_on_enter(void* context) {
FelicaNodeList_next(it)) { FelicaNodeList_next(it)) {
FelicaNode* node = *FelicaNodeList_ref(it); FelicaNode* node = *FelicaNodeList_ref(it);
if(node->type == FelicaNodeTypeArea) { if(node->type == FelicaNodeTypeArea) {
FuriString* area_name = FuriString* area_name = furi_string_alloc_printf("Area %d", node->area->number);
furi_string_alloc_printf("Area %d", node->ptr.area->number);
submenu_add_item( submenu_add_item(
submenu, submenu,
furi_string_get_cstr(area_name), furi_string_get_cstr(area_name),
@@ -69,7 +66,7 @@ void nfc_scene_felica_info_select_on_enter(void* context) {
nfc); nfc);
FuriStringStack_push_back(state->strings, area_name); FuriStringStack_push_back(state->strings, area_name);
} else { } else {
uint16_t service_code = node->ptr.service->number << 6; uint16_t service_code = node->service->number << 6;
FuriString* service_name = furi_string_alloc_printf("Service %04X", service_code); FuriString* service_name = furi_string_alloc_printf("Service %04X", service_code);
submenu_add_item( submenu_add_item(
submenu, submenu,
@@ -106,7 +103,11 @@ bool nfc_scene_felica_info_select_on_event(void* context, SceneManagerEvent even
index -= 1; index -= 1;
if(state->selected_system == NULL) { if(state->selected_system == NULL) {
state->selected_system = *FelicaSystemList_get(data->systems, index); state->selected_system = *FelicaSystemList_get(data->systems, index);
scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaInfoSelect); if(state->selected_system->code == LITE_SYSTEM_CODE) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaServiceData);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaInfoSelect);
}
consumed = true; consumed = true;
} else { } else {
FelicaNode* selected_node = NULL; FelicaNode* selected_node = NULL;
@@ -119,11 +120,11 @@ bool nfc_scene_felica_info_select_on_event(void* context, SceneManagerEvent even
} }
if(selected_node->type == FelicaNodeTypeArea) { if(selected_node->type == FelicaNodeTypeArea) {
FelicaAreaPath_push_back(state->selected_areas, selected_node->ptr.area); FelicaAreaPath_push_back(state->selected_areas, selected_node->area);
scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaInfoSelect); scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaInfoSelect);
consumed = true; consumed = true;
} else if(selected_node->type == FelicaNodeTypeService) { } else if(selected_node->type == FelicaNodeTypeService) {
state->selected_service = selected_node->ptr.service; state->selected_service = selected_node->service;
scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaServiceData); scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaServiceData);
consumed = true; consumed = true;
} }
@@ -146,10 +147,6 @@ void nfc_scene_felica_info_select_on_exit(void* context) {
// Clear view // Clear view
FelicaAreaPath_clear(nfc->felica_select.selected_areas); FelicaAreaPath_clear(nfc->felica_select.selected_areas);
FuriStringStack_it_t it; FuriStringStack_clear(nfc->felica_select.strings);
for(FuriStringStack_it(it, nfc->felica_select.strings); !FuriStringStack_end_p(it);
FuriStringStack_next(it)) {
furi_string_free(*FuriStringStack_ref(it));
}
submenu_reset(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@@ -4,21 +4,22 @@ void nfc_scene_felica_service_data_on_enter(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
FelicaSelectState* select_state = &nfc->felica_select; FelicaSelectState* select_state = &nfc->felica_select;
FelicaSystem* system = select_state->selected_system; FelicaSystem* system = select_state->selected_system;
FelicaService* service = select_state->selected_service; //FelicaService* service = select_state->selected_service;
TextBox* text_box = nfc->text_box; TextBox* text_box = nfc->text_box;
if(system->code == LITE_SYSTEM_CODE && service->number == 0) { if(system->code == LITE_SYSTEM_CODE) {
FelicaLiteInfo* lite_info = &system->lite_info;
uint8_t* data;
text_box_set_font(text_box, TextBoxFontHex); text_box_set_font(text_box, TextBoxFontHex);
furi_string_cat_str(nfc->text_box_store, "S_PAD:\n"); furi_string_cat_str(nfc->text_box_store, "S_PAD:\n");
for(int i = 0; i < REG_LITE_BLOCK; i++) { for(int i = 0; i < REG_LITE_BLOCK; i++) {
FelicaBlock* block = *FelicaBlockList_cget(service->blocks, i); data = lite_info->S_PAD[i];
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) { for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) {
if(!(i % 8) && i) { if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n'); furi_string_push_back(nfc->text_box_store, '\n');
} }
if(block != NULL) { if(data != NULL) {
furi_string_cat_printf( furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]);
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
} else { } else {
furi_string_cat_printf(nfc->text_box_store, "???? "); furi_string_cat_printf(nfc->text_box_store, "???? ");
} }
@@ -26,107 +27,56 @@ void nfc_scene_felica_service_data_on_enter(void* context) {
} }
furi_string_cat_str(nfc->text_box_store, "REG:\n"); furi_string_cat_str(nfc->text_box_store, "REG:\n");
FelicaBlock* block = *FelicaBlockList_cget(service->blocks, REG_LITE_BLOCK); data = lite_info->REG;
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) { for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) {
if(!(i % 8) && i) { if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n'); furi_string_push_back(nfc->text_box_store, '\n');
} }
if(block != NULL) { if(data != NULL) {
furi_string_cat_printf( furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]);
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
} else { } else {
furi_string_cat_printf(nfc->text_box_store, "???? "); furi_string_cat_printf(nfc->text_box_store, "???? ");
} }
} }
furi_string_cat_str(nfc->text_box_store, "RC:\n");
block = *FelicaBlockList_cget(service->blocks, RC_LITE_BLOCK);
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) {
if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n');
}
furi_string_cat_printf(
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
}
furi_string_cat_str(nfc->text_box_store, "MAC:\n"); furi_string_cat_str(nfc->text_box_store, "MAC:\n");
block = *FelicaBlockList_cget(service->blocks, MAC_LITE_BLOCK); data = lite_info->MAC;
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) { for(uint16_t i = 0; i < 8; i += 2) {
if(!(i % 8) && i) { if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n'); furi_string_push_back(nfc->text_box_store, '\n');
} }
furi_string_cat_printf( furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]);
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
} }
furi_string_cat_str(nfc->text_box_store, "ID:\n"); furi_string_cat_printf(nfc->text_box_store, "DFC: %04X\n", lite_info->data_format_code);
block = *FelicaBlockList_cget(service->blocks, ID_LITE_BLOCK);
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) {
if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n');
}
furi_string_cat_printf(
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
}
furi_string_cat_str(nfc->text_box_store, "D_ID:\n"); furi_string_cat_str(nfc->text_box_store, "ID data:\n");
block = *FelicaBlockList_cget(service->blocks, DEVICE_ID_LITE_BLOCK); data = lite_info->ID_value;
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) { for(uint16_t i = 0; i < 6; i += 2) {
if(!(i % 8) && i) { furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]);
furi_string_push_back(nfc->text_box_store, '\n');
}
furi_string_cat_printf(
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
} }
furi_string_cat_str(nfc->text_box_store, "\n");
furi_string_cat_str(nfc->text_box_store, "CKV:\n"); furi_string_cat_printf(nfc->text_box_store, "CKV: %04X\n", lite_info->card_key_version);
block = *FelicaBlockList_cget(service->blocks, CARD_KEY_VER_LITE_BLOCK);
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) {
if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n');
}
furi_string_cat_printf(
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
}
furi_string_cat_str(nfc->text_box_store, "MC:\n"); furi_string_cat_str(nfc->text_box_store, "MC:\n");
block = *FelicaBlockList_cget(service->blocks, MEM_CONFIG_LITE_BLOCK); data = lite_info->memory_config;
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) { for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) {
if(!(i % 8) && i) { if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n'); furi_string_push_back(nfc->text_box_store, '\n');
} }
furi_string_cat_printf( furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]);
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
} }
furi_string_cat_str(nfc->text_box_store, "WCNT:\n"); furi_string_cat_printf(nfc->text_box_store, "WCNT: %06lX\n", lite_info->write_count);
block = *FelicaBlockList_cget(service->blocks, WRITE_COUNT_LITE_BLOCK);
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) {
if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n');
}
furi_string_cat_printf(
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
}
furi_string_cat_str(nfc->text_box_store, "MAC_A:\n"); furi_string_cat_str(nfc->text_box_store, "MAC_A:\n");
block = *FelicaBlockList_cget(service->blocks, MAC_A_LITE_BLOCK); data = lite_info->MAC_A;
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) { for(uint16_t i = 0; i < 8; i += 2) {
if(!(i % 8) && i) { if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n'); furi_string_push_back(nfc->text_box_store, '\n');
} }
furi_string_cat_printf( furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]);
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
}
furi_string_cat_str(nfc->text_box_store, "CRC_CHECK:\n");
block = *FelicaBlockList_cget(service->blocks, CRC_CHECK_LITE_BLOCK);
for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) {
if(!(i % 8) && i) {
furi_string_push_back(nfc->text_box_store, '\n');
}
furi_string_cat_printf(
nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]);
} }
} }
text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store));

View File

@@ -189,8 +189,8 @@ uint8_t felica_lite_prepare_unencrypted_read(
dest[9] = 1; dest[9] = 1;
uint8_t msg_len = 10; uint8_t msg_len = 10;
uint8_t service_code = uint8_t service_code =
RANDOM_TYPE_SERVICE_ATTRIBUTE | FelicaServiceTypeRandom |
((is_read_only) ? UNAUTH_RO_SERVICE_ATTRIBUTE : UNAUTH_RW_SERVICE_ATTRIBUTE); ((is_read_only) ? FelicaServiceAttributeUnauthRO : FelicaServiceAttributeUnauthRO);
dest[msg_len++] = service_code & 0xFF; dest[msg_len++] = service_code & 0xFF;
dest[msg_len++] = service_code >> 8; dest[msg_len++] = service_code >> 8;
@@ -240,7 +240,7 @@ uint16_t felica_parse_unencrypted_read(
if(len < 1) { if(len < 1) {
return 0; return 0;
} }
uint16_t data_length = *buf * 16; uint16_t data_length = *buf * FELICA_BLOCK_SIZE;
len--; len--;
buf++; buf++;
@@ -296,7 +296,7 @@ uint8_t felica_lite_prepare_unencrypted_write(
dest[9] = 1; dest[9] = 1;
uint8_t msg_len = 10; uint8_t msg_len = 10;
uint8_t service_code = RANDOM_TYPE_SERVICE_ATTRIBUTE | UNAUTH_RW_SERVICE_ATTRIBUTE; uint8_t service_code = FelicaServiceTypeRandom | FelicaServiceAttributeUnauthRW;
dest[msg_len++] = service_code & 0xFF; dest[msg_len++] = service_code & 0xFF;
dest[msg_len++] = service_code >> 8; dest[msg_len++] = service_code >> 8;
@@ -367,7 +367,6 @@ bool felica_lite_can_read_without_mac(uint8_t* mc_r_restr, uint8_t block_number)
void felica_define_normal_block(FelicaService* service, uint16_t number, uint8_t* data) { void felica_define_normal_block(FelicaService* service, uint16_t number, uint8_t* data) {
FelicaBlock* block = malloc(sizeof(FelicaBlock)); FelicaBlock* block = malloc(sizeof(FelicaBlock));
block->type = FelicaBlockTypeNormal;
memcpy(block->data, data, FELICA_BLOCK_SIZE); memcpy(block->data, data, FELICA_BLOCK_SIZE);
FelicaBlockList_set_at(service->blocks, number, block); FelicaBlockList_set_at(service->blocks, number, block);
} }
@@ -377,12 +376,13 @@ bool felica_read_lite_system(
FelicaReader* reader, FelicaReader* reader,
FelicaData* data, FelicaData* data,
FelicaSystem* system) { FelicaSystem* system) {
const uint8_t fixed_services[] = { const uint8_t fixed_blocks[] = {
SYS_CODE_LITE_BLOCK, SYS_CODE_LITE_BLOCK,
RC_LITE_BLOCK,
ID_LITE_BLOCK,
MAC_LITE_BLOCK,
DEVICE_ID_LITE_BLOCK, DEVICE_ID_LITE_BLOCK,
ID_LITE_BLOCK,
RC_LITE_BLOCK,
CARD_KEY_LITE_BLOCK,
MAC_LITE_BLOCK,
CARD_KEY_VER_LITE_BLOCK, CARD_KEY_VER_LITE_BLOCK,
MEM_CONFIG_LITE_BLOCK, MEM_CONFIG_LITE_BLOCK,
}; };
@@ -390,7 +390,7 @@ bool felica_read_lite_system(
uint8_t block_data[FELICA_BLOCK_SIZE * 4]; uint8_t block_data[FELICA_BLOCK_SIZE * 4];
tx_rx->tx_bits = tx_rx->tx_bits =
8 * felica_lite_prepare_unencrypted_read(tx_rx->tx_data, reader, true, fixed_services, 1); 8 * felica_lite_prepare_unencrypted_read(tx_rx->tx_data, reader, true, fixed_blocks, 1);
if(!furi_hal_nfc_tx_rx_full(tx_rx)) { if(!furi_hal_nfc_tx_rx_full(tx_rx)) {
FURI_LOG_W(TAG, "Bad exchange verifying Lite system code"); FURI_LOG_W(TAG, "Bad exchange verifying Lite system code");
return false; return false;
@@ -401,33 +401,56 @@ bool felica_read_lite_system(
FURI_LOG_W(TAG, "Bad response to Read without Encryption (SYS_C)"); FURI_LOG_W(TAG, "Bad response to Read without Encryption (SYS_C)");
return false; return false;
} }
if(block_data[0] != (LITE_SYSTEM_CODE >> 8) && block_data[1] != (LITE_SYSTEM_CODE & 0xFF)) { if(nfc_util_bytes2num(block_data, 2) != LITE_SYSTEM_CODE) {
FURI_LOG_W(TAG, "Unexpected SYS_C value"); FURI_LOG_W(TAG, "Unexpected SYS_C value");
return false; return false;
} }
system->code = LITE_SYSTEM_CODE;
FelicaArea* area = &system->root_area; tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read(
FelicaService* service = malloc(sizeof(FelicaService)); tx_rx->tx_data, reader, true, &fixed_blocks[1], 1);
FelicaBlockList_init(service->blocks); if(!furi_hal_nfc_tx_rx_full(tx_rx)) {
for(int i = 0; i < CRC_CHECK_LITE_BLOCK; i++) { FURI_LOG_W(TAG, "Bad exchange reading D_ID");
FelicaBlockList_push_back(service->blocks, NULL); return false;
}
if(felica_parse_unencrypted_read(
tx_rx->rx_data, tx_rx->rx_bits / 8, reader, block_data, sizeof(block_data)) !=
FELICA_BLOCK_SIZE) {
FURI_LOG_W(TAG, "Bad response to Read without Encryption (D_ID)");
return false;
}
if(memcmp(system->idm, block_data, 8) != 0 || memcmp(system->pmm, block_data + 8, 8) != 0) {
FURI_LOG_W(TAG, "Mismatching values for D_ID");
return false;
} }
area->number = 0; system->code = LITE_SYSTEM_CODE;
area->end_service_code = 0x000f;
FelicaNodeList_init(area->nodes);
FelicaNode* node = malloc(sizeof(node));
node->type = FelicaNodeTypeService, node->ptr.service = service;
FelicaNodeList_push_back(area->nodes, node);
service->number = 0; FelicaLiteInfo* lite_info = &system->lite_info;
lite_info->card_key_1 = NULL;
lite_info->card_key_2 = NULL;
felica_define_normal_block(service, SYS_CODE_LITE_BLOCK, block_data); tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read(
tx_rx->tx_data, reader, true, &fixed_blocks[2], 1);
if(!furi_hal_nfc_tx_rx_full(tx_rx)) {
FURI_LOG_W(TAG, "Bad exchange reading ID");
return false;
}
if(felica_parse_unencrypted_read(
tx_rx->rx_data, tx_rx->rx_bits / 8, reader, block_data, sizeof(block_data)) !=
FELICA_BLOCK_SIZE) {
FURI_LOG_W(TAG, "Bad response to Read without Encryption (ID)");
return false;
}
lite_info->data_format_code = nfc_util_bytes2num(block_data + 8, 2);
memcpy(lite_info->ID_value, block_data + 10, 6);
FURI_LOG_I(TAG, "ID:");
for(int i = 0; i < FELICA_BLOCK_SIZE; i++) {
FURI_LOG_I(TAG, "%02X", block_data[i]);
}
memset(block_data, 0, FELICA_BLOCK_SIZE); memset(block_data, 0, FELICA_BLOCK_SIZE);
tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_write( tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_write(
tx_rx->tx_data, reader, &fixed_services[1], 1, block_data); tx_rx->tx_data, reader, &fixed_blocks[3], 1, block_data);
if(!furi_hal_nfc_tx_rx_full(tx_rx)) { if(!furi_hal_nfc_tx_rx_full(tx_rx)) {
FURI_LOG_W(TAG, "Bad exchange writing random challenge"); FURI_LOG_W(TAG, "Bad exchange writing random challenge");
return false; return false;
@@ -436,51 +459,49 @@ bool felica_read_lite_system(
FURI_LOG_W(TAG, "Bad response to Write without Encryption (RC)"); FURI_LOG_W(TAG, "Bad response to Write without Encryption (RC)");
return false; return false;
} }
felica_define_normal_block(service, RC_LITE_BLOCK, block_data);
tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read( tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read(
tx_rx->tx_data, reader, true, &fixed_services[2], 2); tx_rx->tx_data, reader, true, &fixed_blocks[4], 2);
if(!furi_hal_nfc_tx_rx_full(tx_rx)) { if(!furi_hal_nfc_tx_rx_full(tx_rx)) {
FURI_LOG_W(TAG, "Bad exchange reading ID with MAC"); FURI_LOG_W(TAG, "Bad exchange reading CK and MAC");
return false; return false;
} }
if(felica_parse_unencrypted_read( if(felica_parse_unencrypted_read(
tx_rx->rx_data, tx_rx->rx_bits / 8, reader, block_data, sizeof(block_data)) != tx_rx->rx_data, tx_rx->rx_bits / 8, reader, block_data, sizeof(block_data)) !=
FELICA_BLOCK_SIZE * 2) { FELICA_BLOCK_SIZE * 2) {
FURI_LOG_W(TAG, "Bad response to Read without Encryption (ID, MAC)"); FURI_LOG_W(TAG, "Bad response to Read without Encryption (CK, MAC)");
return false; return false;
} }
felica_define_normal_block(service, ID_LITE_BLOCK, block_data); memcpy(lite_info->MAC, block_data + FELICA_BLOCK_SIZE, 8);
felica_define_normal_block(service, MAC_LITE_BLOCK, block_data + FELICA_BLOCK_SIZE);
FURI_LOG_I(TAG, "ID:");
for(int i = 0; i < 16; i++) {
FURI_LOG_I(TAG, "%02X", block_data[i]);
}
FURI_LOG_I(TAG, "MAC:"); FURI_LOG_I(TAG, "MAC:");
for(int i = 0; i < 16; i++) { for(int i = 0; i < FELICA_BLOCK_SIZE; i++) {
FURI_LOG_I(TAG, "%02X", block_data[i + FELICA_BLOCK_SIZE]); FURI_LOG_I(TAG, "%02X", block_data[i + FELICA_BLOCK_SIZE]);
} }
tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read( tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read(
tx_rx->tx_data, reader, true, &fixed_services[4], 3); tx_rx->tx_data, reader, true, &fixed_blocks[6], 2);
if(!furi_hal_nfc_tx_rx_full(tx_rx)) { if(!furi_hal_nfc_tx_rx_full(tx_rx)) {
FURI_LOG_W(TAG, "Bad exchange reading blocks"); FURI_LOG_W(TAG, "Bad exchange reading CKV and MC");
return false; return false;
} }
if(felica_parse_unencrypted_read( if(felica_parse_unencrypted_read(
tx_rx->rx_data, tx_rx->rx_bits / 8, reader, block_data, sizeof(block_data)) != tx_rx->rx_data, tx_rx->rx_bits / 8, reader, block_data, sizeof(block_data)) !=
FELICA_BLOCK_SIZE * 3) { FELICA_BLOCK_SIZE * 2) {
FURI_LOG_W(TAG, "Bad response to Read without Encryption (D_ID, CKV, MC)"); FURI_LOG_W(TAG, "Bad response to Read without Encryption (CKV, MC)");
return false; return false;
} }
felica_define_normal_block(service, DEVICE_ID_LITE_BLOCK, block_data); lite_info->card_key_version = nfc_util_bytes2num(block_data, 2);
felica_define_normal_block(service, CARD_KEY_VER_LITE_BLOCK, block_data + FELICA_BLOCK_SIZE); memcpy(lite_info->memory_config, block_data + FELICA_BLOCK_SIZE, FELICA_BLOCK_SIZE);
felica_define_normal_block(service, MEM_CONFIG_LITE_BLOCK, block_data + FELICA_BLOCK_SIZE * 2);
// Read SPAD and REG accordingly to MC // Read SPAD and REG accordingly to MC
uint8_t* mc_data = block_data + (FELICA_BLOCK_SIZE * 2); uint8_t* mc_data = lite_info->memory_config;
for(uint8_t block_number = 0; block_number <= REG_LITE_BLOCK; block_number++) { for(uint8_t block_number = 0; block_number <= REG_LITE_BLOCK; block_number++) {
if(!felica_lite_can_read_without_mac(mc_data + 6, block_number)) { if(!felica_lite_can_read_without_mac(mc_data + 6, block_number)) {
if(block_number < REG_LITE_BLOCK) {
lite_info->S_PAD[block_number] = NULL;
} else {
lite_info->REG = NULL;
}
continue; continue;
} }
@@ -496,18 +517,24 @@ bool felica_read_lite_system(
FURI_LOG_W(TAG, "Bad response to Read without Encryption (block %d)", block_number); FURI_LOG_W(TAG, "Bad response to Read without Encryption (block %d)", block_number);
return false; return false;
} }
felica_define_normal_block(service, block_number, block_data); uint8_t* block = malloc(FELICA_BLOCK_SIZE);
memcpy(block, block_data, FELICA_BLOCK_SIZE);
if(block_number < REG_LITE_BLOCK) {
lite_info->S_PAD[block_number] = block;
} else {
lite_info->REG = block;
}
} }
if(data->type == FelicaICTypeLiteS) { if(data->type == FelicaICTypeLiteS) {
const uint8_t fixed_s_services[] = { const uint8_t fixed_s_blocks[] = {
ID_LITE_BLOCK, CARD_KEY_LITE_BLOCK,
MAC_A_LITE_BLOCK, MAC_A_LITE_BLOCK,
WRITE_COUNT_LITE_BLOCK, WRITE_COUNT_LITE_BLOCK,
CRC_CHECK_LITE_BLOCK, CRC_CHECK_LITE_BLOCK,
}; };
tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read( tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read(
tx_rx->tx_data, reader, true, fixed_s_services, 2); tx_rx->tx_data, reader, true, fixed_s_blocks, 2);
if(!furi_hal_nfc_tx_rx_full(tx_rx)) { if(!furi_hal_nfc_tx_rx_full(tx_rx)) {
FURI_LOG_W(TAG, "Bad exchange reading ID with MAC_A"); FURI_LOG_W(TAG, "Bad exchange reading ID with MAC_A");
return false; return false;
@@ -515,14 +542,13 @@ bool felica_read_lite_system(
if(felica_parse_unencrypted_read( if(felica_parse_unencrypted_read(
tx_rx->rx_data, tx_rx->rx_bits / 8, reader, block_data, sizeof(block_data)) != tx_rx->rx_data, tx_rx->rx_bits / 8, reader, block_data, sizeof(block_data)) !=
FELICA_BLOCK_SIZE * 2) { FELICA_BLOCK_SIZE * 2) {
FURI_LOG_W(TAG, "Bad response to Read without Encryption (ID, MAC_A)"); FURI_LOG_W(TAG, "Bad response to Read without Encryption (CK, MAC_A)");
return false; return false;
} }
felica_define_normal_block(service, ID_LITE_BLOCK, block_data); memcpy(lite_info->MAC_A, block_data + FELICA_BLOCK_SIZE, FELICA_BLOCK_SIZE);
felica_define_normal_block(service, MAC_A_LITE_BLOCK, block_data + FELICA_BLOCK_SIZE);
tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read( tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read(
tx_rx->tx_data, reader, true, &fixed_s_services[2], 2); tx_rx->tx_data, reader, true, &fixed_s_blocks[2], 2);
if(!furi_hal_nfc_tx_rx_full(tx_rx)) { if(!furi_hal_nfc_tx_rx_full(tx_rx)) {
FURI_LOG_W(TAG, "Bad exchange reading ID with MAC_A"); FURI_LOG_W(TAG, "Bad exchange reading ID with MAC_A");
return false; return false;
@@ -533,8 +559,8 @@ bool felica_read_lite_system(
FURI_LOG_W(TAG, "Bad response to Read without Encryption (WC, CRC_CHECK)"); FURI_LOG_W(TAG, "Bad response to Read without Encryption (WC, CRC_CHECK)");
return false; return false;
} }
felica_define_normal_block(service, WRITE_COUNT_LITE_BLOCK, block_data); lite_info->write_count = nfc_util_bytes2num(block_data, 3);
felica_define_normal_block(service, CRC_CHECK_LITE_BLOCK, block_data + FELICA_BLOCK_SIZE); lite_info->crc_valid = block_data[FELICA_BLOCK_SIZE] == 0x00;
} }
return true; return true;
@@ -582,14 +608,34 @@ void felica_service_clear(FelicaService* service) {
FelicaBlockList_clear(service->blocks); FelicaBlockList_clear(service->blocks);
} }
void felica_lite_clear(FelicaLiteInfo* lite_info) {
for(int i = 0; i < REG_LITE_BLOCK; i++) {
uint8_t* block = lite_info->S_PAD[i];
if(block != NULL) {
free(block);
}
}
if(lite_info->REG != NULL) {
free(lite_info->REG);
}
if(lite_info->card_key_1 != NULL) {
free(lite_info->card_key_1);
}
if(lite_info->card_key_2 != NULL) {
free(lite_info->card_key_2);
}
}
void felica_area_clear(FelicaArea* area) { void felica_area_clear(FelicaArea* area) {
FelicaNodeList_it_t it; FelicaNodeList_it_t it;
for(FelicaNodeList_it(it, area->nodes); !FelicaNodeList_end_p(it); FelicaNodeList_next(it)) { for(FelicaNodeList_it(it, area->nodes); !FelicaNodeList_end_p(it); FelicaNodeList_next(it)) {
FelicaNode* node = *FelicaNodeList_ref(it); FelicaNode* node = *FelicaNodeList_ref(it);
if(node->type == FelicaNodeTypeArea) { if(node->type == FelicaNodeTypeArea) {
felica_area_clear(node->ptr.area); felica_area_clear(node->area);
} else if(node->type == FelicaNodeTypeService) { } else if(node->type == FelicaNodeTypeService) {
felica_service_clear(node->ptr.service); felica_service_clear(node->service);
} }
free(node); free(node);
} }
@@ -601,7 +647,12 @@ void felica_clear(FelicaData* data) {
for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it); for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it);
FelicaSystemList_next(it)) { FelicaSystemList_next(it)) {
FelicaSystem* system = *FelicaSystemList_ref(it); FelicaSystem* system = *FelicaSystemList_ref(it);
felica_area_clear(&system->root_area); if(system->code == LITE_SYSTEM_CODE) {
felica_lite_clear(&system->lite_info);
;
} else {
felica_area_clear(&system->root_area);
}
} }
FelicaSystemList_clear(data->systems); FelicaSystemList_clear(data->systems);
} }

View File

@@ -2,6 +2,7 @@
#include <furi_hal_nfc.h> #include <furi_hal_nfc.h>
#include <m-array.h> #include <m-array.h>
#include <m-dict.h>
#define NFCF_F_SIG (13560000.0) #define NFCF_F_SIG (13560000.0)
#define MRT_T_SIG 302064.89 //ns, 256 * 16 / NFC_F_SIG * 1e9 #define MRT_T_SIG 302064.89 //ns, 256 * 16 / NFC_F_SIG * 1e9
@@ -9,21 +10,29 @@
#define MRT_T_SIG_x16 4833038.24 //ns, MRT_T_SIG * (4 ** 2) #define MRT_T_SIG_x16 4833038.24 //ns, MRT_T_SIG * (4 ** 2)
#define MRT_T_SIG_x64 19332152.96 //ns, MRT_T_SIG * (4 ** 2) #define MRT_T_SIG_x64 19332152.96 //ns, MRT_T_SIG * (4 ** 2)
#define FELICA_VARIABLE_MRT 0
#define FELICA_FIXED_MRT 1
#define FELICA_MUTUAL_AUTH_MRT 2
#define FELICA_READ_MRT 3
#define FELICA_WRITE_MRT 4
#define FELICA_OTHER_MRT 5
#define FELICA_BLOCK_SIZE 16 #define FELICA_BLOCK_SIZE 16
#define SUICA_SYSTEM_CODE 0x0003 #define CYBERNET_SYSTEM_CODE 0x0003
#define NDEF_SYSTEM_CODE 0x12fc #define NDEF_SYSTEM_CODE 0x12fc
#define HCE_F_SYSTEM_CODE 0x4000 #define HCE_F_SYSTEM_CODE 0x4000
#define OCTOPUS_SYSTEM_CODE 0x8008 #define OCTOPUS_SYSTEM_CODE 0x8008
#define IRUCA_SYSTEM_CODE 0x80de
#define EDY_SYSTEM_CODE 0x811d #define EDY_SYSTEM_CODE 0x811d
#define PASPY_SYSTEM_CODE 0x8592 #define PASPY_SYSTEM_CODE 0x8592
#define BLACKBOARD_SYSTEM_CODE 0x8620 #define BLACKBOARD_SYSTEM_CODE 0x8620
#define SAPICA_SYSTEM_CODE 0x865e #define SAPICA_SYSTEM_CODE 0x865e
#define SUICA_SYSTEM_CODE 0x86a7
#define LITE_SYSTEM_CODE 0x88b4 #define LITE_SYSTEM_CODE 0x88b4
#define RYUTO_SYSTEM_CODE 0x8b5d #define RYUTO_SYSTEM_CODE 0x8b5d
#define OKICA_SYSTEM_CODE 0x8fc1 #define OKICA_SYSTEM_CODE 0x8fc1
#define SECURE_ID_SYSTEM_CODE 0x957a #define SECURE_ID_SYSTEM_CODE 0x957a
#define IRUCA_SYSTEM_CODE 0xde80
#define COMMON_AREA_SYSTEM_CODE 0xfe00 #define COMMON_AREA_SYSTEM_CODE 0xfe00
#define PLUG_SYSTEM_CODE 0xfee1 #define PLUG_SYSTEM_CODE 0xfee1
@@ -42,24 +51,6 @@
#define STATE_LITE_BLOCK 0x92 #define STATE_LITE_BLOCK 0x92
#define CRC_CHECK_LITE_BLOCK 0xA0 #define CRC_CHECK_LITE_BLOCK 0xA0
#define RANDOM_TYPE_SERVICE_ATTRIBUTE (0b0010 << 2)
#define CYCLIC_TYPE_SERVICE_ATTRIBUTE (0b0011 << 2)
#define PURSE_TYPE_SERVICE_ATTRIBUTE (0b010 << 3)
#define AUTH_RW_SERVICE_ATTRIBUTE (0b00)
#define UNAUTH_RW_SERVICE_ATTRIBUTE (0b01)
#define AUTH_RO_SERVICE_ATTRIBUTE (0b10)
#define UNAUTH_RO_SERVICE_ATTRIBUTE (0b11)
#define AUTH_DIRECT_ACCESS_SERVICE_ATTRIBUTE (0b000)
#define UNAUTH_DIRECT_ACCESS_SERVICE_ATTRIBUTE (0b001)
#define AUTH_CASHBACK_DECREMENT_SERVICE_ATTRIBUTE (0b010)
#define UNAUTH_CASHBACK_DECREMENT_SERVICE_ATTRIBUTE (0b011)
#define AUTH_DECREMENT_SERVICE_ATTRIBUTE (0b100)
#define UNAUTH_DECREMENT_SERVICE_ATTRIBUTE (0b101)
#define AUTH_RO_PURSE_SERVICE_ATTRIBUTE (0b110)
#define UNAUTH_RO_PURSE_SERVICE_ATTRIBUTE (0b111)
#define IS_2_BYTE_BLOCK_LIST_ELEMENT 0x80 #define IS_2_BYTE_BLOCK_LIST_ELEMENT 0x80
#define FELICA_UNENCRYPTED_READ_CMD 0x06 #define FELICA_UNENCRYPTED_READ_CMD 0x06
@@ -105,35 +96,51 @@ typedef struct {
} FelicaMRTParts; } FelicaMRTParts;
typedef enum { typedef enum {
FelicaMRTCommandTypeVariable = 0, FelicaServiceTypeRandom = (0b0010 << 2),
FelicaMRTCommandTypeFixed = 1, FelicaServiceTypeCyclic = (0b0011 << 2),
FelicaMRTCommandTypeMutualAuth = 2, FelicaServiceTypePurse = (0b010 << 3),
FelicaMRTCommandTypeDataRead = 3, } FelicaServiceType;
FelicaMRTCommandTypeDataWrite = 4, typedef enum {
FelicaMRTCommandTypeDataOther = 4, FelicaServiceAttributeAuthRW = 0b00,
} FelicaMRTCommandType; FelicaServiceAttributeUnauthRW = 0b01,
FelicaServiceAttributeAuthRO = 0b10,
FelicaServiceAttributeUnauthRO = 0b11,
FelicaServiceAttributeAuthDirectAccess = 0b000,
FelicaServiceAttributeUnauthDirectAccess = 0b001,
FelicaServiceAttributeAuthCashbackDecrement = 0b010,
FelicaServiceAttributeUnauthCashbackDecrement = 0b011,
FelicaServiceAttributeAuthDecrement = 0b100,
FelicaServiceAttributeUnauthDecrement = 0b101,
FelicaServiceAttributeAuthPurseRO = 0b110,
FelicaServiceAttributeUnauthPurseRO = 0b111,
} FelicaServiceAttribute;
DICT_SET_DEF(
FelicaServiceAttributeList,
FelicaServiceAttribute,
M_ENUM_OPLIST(FelicaServiceAttribute, FelicaServiceAttributeAuthRW))
typedef FelicaMRTParts FelicaMRTParameters[6]; typedef FelicaMRTParts FelicaMRTParameters[6];
typedef enum {
FelicaBlockTypeNormal,
FelicaBlockTypeOverlap,
FelicaBlockTypeExtended,
} FelicaBlockType;
typedef struct { typedef struct {
FelicaBlockType type; uint8_t data[FELICA_BLOCK_SIZE];
union {
uint8_t data[FELICA_BLOCK_SIZE];
};
} FelicaBlock; } FelicaBlock;
// typedef struct {} FelicaOverlapBlock; ARRAY_DEF(FelicaBlockList, FelicaBlock*, M_PTR_OPLIST)
ARRAY_DEF(FelicaBlockList, FelicaBlock*, M_PTR_OPLIST);
typedef struct { typedef struct {
uint16_t number; uint16_t number;
FelicaBlockList_t blocks; FelicaServiceAttributeList_t access_control_list; // accounts for overlap services
bool is_extended_overlap;
union {
FelicaBlockList_t blocks;
struct {
uint16_t overlap_target;
uint8_t block_start;
uint8_t block_count;
};
};
} FelicaService; } FelicaService;
typedef enum { typedef enum {
@@ -147,9 +154,10 @@ typedef struct {
union { union {
struct _FelicaArea_t* area; struct _FelicaArea_t* area;
FelicaService* service; FelicaService* service;
} ptr; };
} FelicaNode; } FelicaNode;
ARRAY_DEF(FelicaNodeList, FelicaNode*, M_PTR_OPLIST);
ARRAY_DEF(FelicaNodeList, FelicaNode*, M_PTR_OPLIST)
typedef struct _FelicaArea_t { typedef struct _FelicaArea_t {
uint16_t number; uint16_t number;
@@ -157,9 +165,26 @@ typedef struct _FelicaArea_t {
uint16_t end_service_code; uint16_t end_service_code;
FelicaNodeList_t nodes; FelicaNodeList_t nodes;
} FelicaArea; } FelicaArea;
typedef struct {
uint8_t* S_PAD[14];
uint8_t* REG;
// MACs of all zero bytes (read from CK)
uint8_t MAC[8];
uint16_t data_format_code;
uint8_t ID_value[6];
uint8_t* card_key_1;
uint8_t* card_key_2;
uint16_t card_key_version;
uint8_t memory_config[FELICA_BLOCK_SIZE];
// Lite-S only
uint8_t MAC_A[8];
uint32_t write_count;
bool crc_valid;
} FelicaLiteInfo;
typedef struct _FelicaSystem_t { typedef struct _FelicaSystem_t {
uint8_t number; uint8_t number;
uint16_t code; uint16_t code;
@@ -167,13 +192,13 @@ typedef struct _FelicaSystem_t {
uint8_t pmm[8]; uint8_t pmm[8];
FelicaMRTParameters maximum_response_times; FelicaMRTParameters maximum_response_times;
/** This struct represents area 0, union {
* which always exists on a given system FelicaLiteInfo lite_info;
*/ FelicaArea root_area;
FelicaArea root_area; };
} FelicaSystem; } FelicaSystem;
ARRAY_DEF(FelicaSystemList, FelicaSystem*, M_PTR_OPLIST); ARRAY_DEF(FelicaSystemList, FelicaSystem*, M_PTR_OPLIST)
typedef struct { typedef struct {
FelicaICType type; FelicaICType type;