From 653d0d7704beebe577df7e3c2483db52858805d2 Mon Sep 17 00:00:00 2001 From: nullableVoidPtr <30564701+nullableVoidPtr@users.noreply.github.com> Date: Wed, 28 Dec 2022 21:32:25 +0800 Subject: [PATCH] NFC: slight FeliCa refactor --- applications/main/nfc/nfc_i.h | 7 +- .../nfc/scenes/nfc_scene_felica_info_select.c | 25 ++- .../scenes/nfc_scene_felica_service_data.c | 102 +++-------- lib/nfc/protocols/felica.c | 167 ++++++++++++------ lib/nfc/protocols/felica.h | 121 ++++++++----- 5 files changed, 223 insertions(+), 199 deletions(-) diff --git a/applications/main/nfc/nfc_i.h b/applications/main/nfc/nfc_i.h index 21a3d4333..a5a389737 100644 --- a/applications/main/nfc/nfc_i.h +++ b/applications/main/nfc/nfc_i.h @@ -39,11 +39,12 @@ #include "rpc/rpc_app.h" +#include #include -ARRAY_DEF(FelicaAreaPath, FelicaArea*, M_PTR_OPLIST); -ARRAY_DEF(FuriStringStack, FuriString*, M_PTR_OPLIST); -ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST); +ARRAY_DEF(FelicaAreaPath, FelicaArea*, M_PTR_OPLIST) +LIST_DEF(FuriStringStack, FuriString*, FURI_STRING_OPLIST) +ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST) #define NFC_TEXT_STORE_SIZE 128 #define NFC_APP_FOLDER ANY_PATH("nfc") diff --git a/applications/main/nfc/scenes/nfc_scene_felica_info_select.c b/applications/main/nfc/scenes/nfc_scene_felica_info_select.c index 30fbf71b2..6ed7b61a4 100644 --- a/applications/main/nfc/scenes/nfc_scene_felica_info_select.c +++ b/applications/main/nfc/scenes/nfc_scene_felica_info_select.c @@ -1,8 +1,6 @@ #include "../nfc_i.h" #include -#define SYSTEM_EVENT - void nfc_scene_felica_info_select_submenu_callback(void* context, uint32_t index) { 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); 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"); FelicaSystemList_it_t 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)) { FelicaNode* node = *FelicaNodeList_ref(it); if(node->type == FelicaNodeTypeArea) { - FuriString* area_name = - furi_string_alloc_printf("Area %d", node->ptr.area->number); + FuriString* area_name = furi_string_alloc_printf("Area %d", node->area->number); submenu_add_item( submenu, furi_string_get_cstr(area_name), @@ -69,7 +66,7 @@ void nfc_scene_felica_info_select_on_enter(void* context) { nfc); FuriStringStack_push_back(state->strings, area_name); } 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); submenu_add_item( submenu, @@ -106,7 +103,11 @@ bool nfc_scene_felica_info_select_on_event(void* context, SceneManagerEvent even index -= 1; if(state->selected_system == NULL) { 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; } else { 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) { - 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); consumed = true; } 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); consumed = true; } @@ -146,10 +147,6 @@ void nfc_scene_felica_info_select_on_exit(void* context) { // Clear view FelicaAreaPath_clear(nfc->felica_select.selected_areas); - FuriStringStack_it_t it; - for(FuriStringStack_it(it, nfc->felica_select.strings); !FuriStringStack_end_p(it); - FuriStringStack_next(it)) { - furi_string_free(*FuriStringStack_ref(it)); - } + FuriStringStack_clear(nfc->felica_select.strings); submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_felica_service_data.c b/applications/main/nfc/scenes/nfc_scene_felica_service_data.c index 68cd71a4f..5153d7d37 100644 --- a/applications/main/nfc/scenes/nfc_scene_felica_service_data.c +++ b/applications/main/nfc/scenes/nfc_scene_felica_service_data.c @@ -4,21 +4,22 @@ void nfc_scene_felica_service_data_on_enter(void* context) { Nfc* nfc = context; FelicaSelectState* select_state = &nfc->felica_select; FelicaSystem* system = select_state->selected_system; - FelicaService* service = select_state->selected_service; + //FelicaService* service = select_state->selected_service; 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); furi_string_cat_str(nfc->text_box_store, "S_PAD:\n"); 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) { if(!(i % 8) && i) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(block != NULL) { - furi_string_cat_printf( - nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]); + if(data != NULL) { + furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]); } else { 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"); - FelicaBlock* block = *FelicaBlockList_cget(service->blocks, REG_LITE_BLOCK); + data = lite_info->REG; for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) { if(!(i % 8) && i) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(block != NULL) { - furi_string_cat_printf( - nfc->text_box_store, "%02X%02X ", block->data[i], block->data[i + 1]); + if(data != NULL) { + furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]); } else { 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"); - block = *FelicaBlockList_cget(service->blocks, MAC_LITE_BLOCK); - for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) { + data = lite_info->MAC; + for(uint16_t i = 0; i < 8; 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_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]); } - furi_string_cat_str(nfc->text_box_store, "ID:\n"); - 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_printf(nfc->text_box_store, "DFC: %04X\n", lite_info->data_format_code); - furi_string_cat_str(nfc->text_box_store, "D_ID:\n"); - block = *FelicaBlockList_cget(service->blocks, DEVICE_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, "ID data:\n"); + data = lite_info->ID_value; + for(uint16_t i = 0; i < 6; i += 2) { + furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]); } + furi_string_cat_str(nfc->text_box_store, "\n"); - furi_string_cat_str(nfc->text_box_store, "CKV:\n"); - 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_printf(nfc->text_box_store, "CKV: %04X\n", lite_info->card_key_version); 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) { 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_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]); } - furi_string_cat_str(nfc->text_box_store, "WCNT:\n"); - 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_printf(nfc->text_box_store, "WCNT: %06lX\n", lite_info->write_count); furi_string_cat_str(nfc->text_box_store, "MAC_A:\n"); - block = *FelicaBlockList_cget(service->blocks, MAC_A_LITE_BLOCK); - for(uint16_t i = 0; i < FELICA_BLOCK_SIZE; i += 2) { + data = lite_info->MAC_A; + for(uint16_t i = 0; i < 8; 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, "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]); + furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data[i], data[i + 1]); } } text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); diff --git a/lib/nfc/protocols/felica.c b/lib/nfc/protocols/felica.c index e6f585437..d9489cb50 100644 --- a/lib/nfc/protocols/felica.c +++ b/lib/nfc/protocols/felica.c @@ -189,8 +189,8 @@ uint8_t felica_lite_prepare_unencrypted_read( dest[9] = 1; uint8_t msg_len = 10; uint8_t service_code = - RANDOM_TYPE_SERVICE_ATTRIBUTE | - ((is_read_only) ? UNAUTH_RO_SERVICE_ATTRIBUTE : UNAUTH_RW_SERVICE_ATTRIBUTE); + FelicaServiceTypeRandom | + ((is_read_only) ? FelicaServiceAttributeUnauthRO : FelicaServiceAttributeUnauthRO); dest[msg_len++] = service_code & 0xFF; dest[msg_len++] = service_code >> 8; @@ -240,7 +240,7 @@ uint16_t felica_parse_unencrypted_read( if(len < 1) { return 0; } - uint16_t data_length = *buf * 16; + uint16_t data_length = *buf * FELICA_BLOCK_SIZE; len--; buf++; @@ -296,7 +296,7 @@ uint8_t felica_lite_prepare_unencrypted_write( dest[9] = 1; 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 >> 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) { FelicaBlock* block = malloc(sizeof(FelicaBlock)); - block->type = FelicaBlockTypeNormal; memcpy(block->data, data, FELICA_BLOCK_SIZE); FelicaBlockList_set_at(service->blocks, number, block); } @@ -377,12 +376,13 @@ bool felica_read_lite_system( FelicaReader* reader, FelicaData* data, FelicaSystem* system) { - const uint8_t fixed_services[] = { + const uint8_t fixed_blocks[] = { SYS_CODE_LITE_BLOCK, - RC_LITE_BLOCK, - ID_LITE_BLOCK, - MAC_LITE_BLOCK, DEVICE_ID_LITE_BLOCK, + ID_LITE_BLOCK, + RC_LITE_BLOCK, + CARD_KEY_LITE_BLOCK, + MAC_LITE_BLOCK, CARD_KEY_VER_LITE_BLOCK, MEM_CONFIG_LITE_BLOCK, }; @@ -390,7 +390,7 @@ bool felica_read_lite_system( uint8_t block_data[FELICA_BLOCK_SIZE * 4]; 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)) { FURI_LOG_W(TAG, "Bad exchange verifying Lite system code"); return false; @@ -401,33 +401,56 @@ bool felica_read_lite_system( FURI_LOG_W(TAG, "Bad response to Read without Encryption (SYS_C)"); 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"); return false; } - system->code = LITE_SYSTEM_CODE; - FelicaArea* area = &system->root_area; - FelicaService* service = malloc(sizeof(FelicaService)); - FelicaBlockList_init(service->blocks); - for(int i = 0; i < CRC_CHECK_LITE_BLOCK; i++) { - FelicaBlockList_push_back(service->blocks, NULL); + tx_rx->tx_bits = 8 * felica_lite_prepare_unencrypted_read( + tx_rx->tx_data, reader, true, &fixed_blocks[1], 1); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange reading D_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 (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; - 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); + system->code = LITE_SYSTEM_CODE; - 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); 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)) { FURI_LOG_W(TAG, "Bad exchange writing random challenge"); return false; @@ -436,51 +459,49 @@ bool felica_read_lite_system( FURI_LOG_W(TAG, "Bad response to Write without Encryption (RC)"); 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_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)) { - FURI_LOG_W(TAG, "Bad exchange reading ID with MAC"); + FURI_LOG_W(TAG, "Bad exchange reading CK and MAC"); 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 * 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; } - felica_define_normal_block(service, ID_LITE_BLOCK, block_data); - 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]); - } + memcpy(lite_info->MAC, block_data + FELICA_BLOCK_SIZE, 8); 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]); } 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)) { - FURI_LOG_W(TAG, "Bad exchange reading blocks"); + FURI_LOG_W(TAG, "Bad exchange reading CKV and MC"); 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 * 3) { - FURI_LOG_W(TAG, "Bad response to Read without Encryption (D_ID, CKV, MC)"); + FELICA_BLOCK_SIZE * 2) { + FURI_LOG_W(TAG, "Bad response to Read without Encryption (CKV, MC)"); return false; } - felica_define_normal_block(service, DEVICE_ID_LITE_BLOCK, block_data); - felica_define_normal_block(service, CARD_KEY_VER_LITE_BLOCK, block_data + FELICA_BLOCK_SIZE); - felica_define_normal_block(service, MEM_CONFIG_LITE_BLOCK, block_data + FELICA_BLOCK_SIZE * 2); + lite_info->card_key_version = nfc_util_bytes2num(block_data, 2); + memcpy(lite_info->memory_config, block_data + FELICA_BLOCK_SIZE, FELICA_BLOCK_SIZE); // 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++) { 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; } @@ -496,18 +517,24 @@ bool felica_read_lite_system( FURI_LOG_W(TAG, "Bad response to Read without Encryption (block %d)", block_number); 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) { - const uint8_t fixed_s_services[] = { - ID_LITE_BLOCK, + const uint8_t fixed_s_blocks[] = { + CARD_KEY_LITE_BLOCK, MAC_A_LITE_BLOCK, WRITE_COUNT_LITE_BLOCK, CRC_CHECK_LITE_BLOCK, }; 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)) { FURI_LOG_W(TAG, "Bad exchange reading ID with MAC_A"); return false; @@ -515,14 +542,13 @@ bool felica_read_lite_system( if(felica_parse_unencrypted_read( tx_rx->rx_data, tx_rx->rx_bits / 8, reader, block_data, sizeof(block_data)) != 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; } - felica_define_normal_block(service, ID_LITE_BLOCK, block_data); - felica_define_normal_block(service, MAC_A_LITE_BLOCK, block_data + FELICA_BLOCK_SIZE); + memcpy(lite_info->MAC_A, block_data + FELICA_BLOCK_SIZE, FELICA_BLOCK_SIZE); 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)) { FURI_LOG_W(TAG, "Bad exchange reading ID with MAC_A"); return false; @@ -533,8 +559,8 @@ bool felica_read_lite_system( FURI_LOG_W(TAG, "Bad response to Read without Encryption (WC, CRC_CHECK)"); return false; } - felica_define_normal_block(service, WRITE_COUNT_LITE_BLOCK, block_data); - felica_define_normal_block(service, CRC_CHECK_LITE_BLOCK, block_data + FELICA_BLOCK_SIZE); + lite_info->write_count = nfc_util_bytes2num(block_data, 3); + lite_info->crc_valid = block_data[FELICA_BLOCK_SIZE] == 0x00; } return true; @@ -582,14 +608,34 @@ void felica_service_clear(FelicaService* service) { 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) { FelicaNodeList_it_t it; for(FelicaNodeList_it(it, area->nodes); !FelicaNodeList_end_p(it); FelicaNodeList_next(it)) { FelicaNode* node = *FelicaNodeList_ref(it); if(node->type == FelicaNodeTypeArea) { - felica_area_clear(node->ptr.area); + felica_area_clear(node->area); } else if(node->type == FelicaNodeTypeService) { - felica_service_clear(node->ptr.service); + felica_service_clear(node->service); } free(node); } @@ -601,7 +647,12 @@ void felica_clear(FelicaData* data) { for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it); FelicaSystemList_next(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); } \ No newline at end of file diff --git a/lib/nfc/protocols/felica.h b/lib/nfc/protocols/felica.h index f79d28ce6..fa81cba2f 100644 --- a/lib/nfc/protocols/felica.h +++ b/lib/nfc/protocols/felica.h @@ -2,6 +2,7 @@ #include #include +#include #define NFCF_F_SIG (13560000.0) #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_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 SUICA_SYSTEM_CODE 0x0003 +#define CYBERNET_SYSTEM_CODE 0x0003 #define NDEF_SYSTEM_CODE 0x12fc #define HCE_F_SYSTEM_CODE 0x4000 #define OCTOPUS_SYSTEM_CODE 0x8008 +#define IRUCA_SYSTEM_CODE 0x80de #define EDY_SYSTEM_CODE 0x811d #define PASPY_SYSTEM_CODE 0x8592 #define BLACKBOARD_SYSTEM_CODE 0x8620 #define SAPICA_SYSTEM_CODE 0x865e +#define SUICA_SYSTEM_CODE 0x86a7 #define LITE_SYSTEM_CODE 0x88b4 #define RYUTO_SYSTEM_CODE 0x8b5d #define OKICA_SYSTEM_CODE 0x8fc1 #define SECURE_ID_SYSTEM_CODE 0x957a -#define IRUCA_SYSTEM_CODE 0xde80 #define COMMON_AREA_SYSTEM_CODE 0xfe00 #define PLUG_SYSTEM_CODE 0xfee1 @@ -42,24 +51,6 @@ #define STATE_LITE_BLOCK 0x92 #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 FELICA_UNENCRYPTED_READ_CMD 0x06 @@ -105,35 +96,51 @@ typedef struct { } FelicaMRTParts; typedef enum { - FelicaMRTCommandTypeVariable = 0, - FelicaMRTCommandTypeFixed = 1, - FelicaMRTCommandTypeMutualAuth = 2, - FelicaMRTCommandTypeDataRead = 3, - FelicaMRTCommandTypeDataWrite = 4, - FelicaMRTCommandTypeDataOther = 4, -} FelicaMRTCommandType; + FelicaServiceTypeRandom = (0b0010 << 2), + FelicaServiceTypeCyclic = (0b0011 << 2), + FelicaServiceTypePurse = (0b010 << 3), +} FelicaServiceType; +typedef enum { + FelicaServiceAttributeAuthRW = 0b00, + 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 enum { - FelicaBlockTypeNormal, - FelicaBlockTypeOverlap, - FelicaBlockTypeExtended, -} FelicaBlockType; typedef struct { - FelicaBlockType type; - union { - uint8_t data[FELICA_BLOCK_SIZE]; - }; + uint8_t data[FELICA_BLOCK_SIZE]; } FelicaBlock; -// typedef struct {} FelicaOverlapBlock; - -ARRAY_DEF(FelicaBlockList, FelicaBlock*, M_PTR_OPLIST); +ARRAY_DEF(FelicaBlockList, FelicaBlock*, M_PTR_OPLIST) typedef struct { 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; typedef enum { @@ -147,9 +154,10 @@ typedef struct { union { struct _FelicaArea_t* area; FelicaService* service; - } ptr; + }; } FelicaNode; -ARRAY_DEF(FelicaNodeList, FelicaNode*, M_PTR_OPLIST); + +ARRAY_DEF(FelicaNodeList, FelicaNode*, M_PTR_OPLIST) typedef struct _FelicaArea_t { uint16_t number; @@ -157,9 +165,26 @@ typedef struct _FelicaArea_t { uint16_t end_service_code; FelicaNodeList_t nodes; - } 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 { uint8_t number; uint16_t code; @@ -167,13 +192,13 @@ typedef struct _FelicaSystem_t { uint8_t pmm[8]; FelicaMRTParameters maximum_response_times; - /** This struct represents area 0, - * which always exists on a given system - */ - FelicaArea root_area; + union { + FelicaLiteInfo lite_info; + FelicaArea root_area; + }; } FelicaSystem; -ARRAY_DEF(FelicaSystemList, FelicaSystem*, M_PTR_OPLIST); +ARRAY_DEF(FelicaSystemList, FelicaSystem*, M_PTR_OPLIST) typedef struct { FelicaICType type;