From eed92312b4f8328903894a2b6a910ebd4b632120 Mon Sep 17 00:00:00 2001 From: nullableVoidPtr <30564701+nullableVoidPtr@users.noreply.github.com> Date: Wed, 29 Mar 2023 18:25:20 +1100 Subject: [PATCH 1/2] wip: NFC: FeliCa lite authentication --- firmware/targets/f7/api_symbols.csv | 3 +- lib/nfc/protocols/felica.c | 219 +++++++++++++++++++++++++++- lib/nfc/protocols/felica_util.c | 14 ++ lib/nfc/protocols/felica_util.h | 1 + 4 files changed, 232 insertions(+), 5 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index d68c2f471..d9468636e 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,20.1,, +Version,+,20.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -829,6 +829,7 @@ Function,-,felica_get_service_name,FuriString*,FelicaService* Function,-,felica_get_system_name,FuriString*,FelicaSystem* Function,-,felica_lite_can_read_without_mac,_Bool,"uint8_t*, uint8_t" Function,-,felica_lite_dump_data,_Bool,"FuriHalNfcTxRxContext*, FelicaReader*, FelicaData*, FelicaSystem*" +Function,-,felica_lite_is_issued,_Bool,FelicaLiteInfo* Function,-,felica_lite_prepare_unencrypted_read,uint8_t,"uint8_t*, const FelicaReader*, _Bool, const uint8_t*, uint8_t" Function,-,felica_lite_prepare_unencrypted_write,uint8_t,"uint8_t*, const FelicaReader*, const uint8_t*, uint8_t, const uint8_t*" Function,-,felica_parse_unencrypted_read,uint16_t,"uint8_t*, uint8_t, FelicaReader*, uint8_t*, uint16_t" diff --git a/lib/nfc/protocols/felica.c b/lib/nfc/protocols/felica.c index 827187564..c5823a221 100644 --- a/lib/nfc/protocols/felica.c +++ b/lib/nfc/protocols/felica.c @@ -1,4 +1,5 @@ #include +#include #include #include "felica.h" #include "nfc_util.h" @@ -151,6 +152,215 @@ FelicaICType felica_get_ic_type(uint8_t* PMm) { return FelicaICType2K; } +static void felica_lite_diversify_key(uint8_t* id_block, uint8_t* master_key, uint8_t* card_key) { + uint8_t ZERO[8] = {0}; + uint8_t L[8]; + mbedtls_des3_context ctx; + mbedtls_des3_init(&ctx); + mbedtls_des3_set3key_enc(&ctx, master_key); + mbedtls_des3_crypt_ecb(&ctx, ZERO, L); + mbedtls_des3_free(&ctx); + + uint8_t K1[8]; + for(int i = 0; i < 8; i++) { + K1[i] = L[i] << 1; + if(i < 7) { + K1[i] |= (L[i + 1] >> 7); + } + } + + if((L[0] ^ 0x80) == 0) { + K1[7] ^= 0x1B; + } + + uint8_t M1[8]; + uint8_t M2[8]; + memcpy(M1, id_block, 8); + memcpy(M2, id_block + 8, 8); + for(int i = 0; i < 8; i++) { + M2[i] ^= K1[i]; + } + + uint8_t C1[8]; + mbedtls_des3_init(&ctx); + mbedtls_des3_set3key_enc(&ctx, master_key); + mbedtls_des3_crypt_ecb(&ctx, M1, C1); + for(int i = 0; i < 8; i++) { + C1[i] ^= M2[i]; + } + + mbedtls_des3_crypt_ecb(&ctx, C1, card_key); // T + + M1[0] ^= 0x80; // M'1 + mbedtls_des3_crypt_ecb(&ctx, M1, C1); // C'1 + for(int i = 0; i < 8; i++) { + C1[i] ^= M2[i]; + } + + mbedtls_des3_crypt_ecb(&ctx, C1, card_key + 8); // T' + mbedtls_des3_free(&ctx); +} + +static void felica_lite_generate_session_key( + uint8_t* random_challenge, + uint8_t* card_key, + uint8_t* session_key) { + uint8_t RC1[8]; + uint8_t RC2[8]; + uint8_t CK[16]; + + for(int i = 0; i < 8; i++) { + RC1[i] = random_challenge[7 - i]; + RC2[i] = random_challenge[i]; + CK[i] = card_key[7 - i]; + CK[i + 8] = card_key[15 - i]; + } + + mbedtls_des3_context ctx; + + uint8_t SK1[8]; + mbedtls_des3_init(&ctx); + mbedtls_des3_set2key_enc(&ctx, CK); + mbedtls_des3_crypt_ecb(&ctx, RC1, SK1); + + uint8_t SK2[8]; + for(int i = 0; i < 8; i++) { + RC2[i] ^= SK1[i]; + } + mbedtls_des3_crypt_ecb(&ctx, RC2, SK2); + mbedtls_des3_free(&ctx); + + for(int i = 0; i < 8; i++) { + session_key[i] = SK1[7 - i]; + session_key[i + 8] = SK2[7 - i]; + } +} + +static void felica_lite_calculate_mac( + uint8_t* random_challenge, + uint8_t* session_key, + uint8_t* block_data, + size_t block_count, + uint8_t* MAC) { + uint8_t SK[16]; + + for(int i = 0; i < 8; i++) { + MAC[i] = random_challenge[7 - i]; + SK[i] = session_key[7 - i]; + SK[i + 8] = session_key[15 - i]; + } + + mbedtls_des3_context ctx; + mbedtls_des3_init(&ctx); + mbedtls_des3_set3key_enc(&ctx, SK); + + for(size_t block_num = 0; block_num < block_count; block_num++) { + for(int i = 0; i < 8; i++) { + MAC[i] ^= block_data[block_num * FELICA_BLOCK_SIZE + 7 - i]; + } + + uint8_t intermediate[8]; + mbedtls_des3_crypt_ecb(&ctx, MAC, intermediate); + for(int i = 0; i < 8; i++) { + intermediate[i] ^= block_data[block_num * FELICA_BLOCK_SIZE + 15 - i]; + } + + mbedtls_des3_crypt_ecb(&ctx, intermediate, MAC); + } + + mbedtls_des3_free(&ctx); +} + +static void felica_lite_calculate_mac_a( + uint8_t* random_challenge, + uint8_t* session_key, + uint8_t* iv, + uint8_t* block_data, + size_t block_count, + uint8_t* MAC_A) { + uint8_t SK[16]; + uint8_t intermediate_a[8]; + uint8_t intermediate_b[8]; + + for(int i = 0; i < 8; i++) { + intermediate_a[i] = iv[7 - 1] ^ random_challenge[7 - i]; + SK[i] = session_key[7 - i]; + SK[i + 8] = session_key[15 - i]; + } + + mbedtls_des3_context ctx; + mbedtls_des3_init(&ctx); + mbedtls_des3_set3key_enc(&ctx, SK); + mbedtls_des3_crypt_ecb(&ctx, intermediate_a, intermediate_b); + + for(size_t block_num = 0; block_num < block_count; block_num++) { + for(int i = 0; i < 8; i++) { + intermediate_b[i] ^= block_data[block_num * FELICA_BLOCK_SIZE + 7 - i]; + } + + mbedtls_des3_crypt_ecb(&ctx, intermediate_b, intermediate_a); + for(int i = 0; i < 8; i++) { + intermediate_a[i] ^= block_data[block_num * FELICA_BLOCK_SIZE + 7 - i]; + } + + mbedtls_des3_crypt_ecb(&ctx, intermediate_a, intermediate_b); + } + + for(int i = 0; i < 8; i++) { + MAC_A[i] = intermediate_b[7 - 1]; + } +} + +static void felica_lite_calculate_mac_a_for_write( + uint8_t* random_challenge, + uint8_t* session_key, + uint32_t write_count, + uint8_t block_number, + uint8_t* block_data, + uint8_t* MAC_A) { + uint8_t iv[8]; + nfc_util_num2bytes(write_count, 3, iv); + iv[3] = 0x00; + iv[4] = block_number; + iv[5] = 0x00; + iv[6] = 0x91; + iv[7] = 0x00; + + uint8_t SK[16]; + for(int i = 0; i < 8; i++) { + SK[i] = session_key[i + 8]; + SK[i + 8] = session_key[i]; + } + + felica_lite_calculate_mac_a(random_challenge, SK, iv, block_data, 1, MAC_A); +} + +static void felica_lite_calculate_mac_a_for_read( + uint8_t* random_challenge, + uint8_t* session_key, + uint8_t* block_list, + uint8_t block_list_count, + uint8_t* block_data, + uint8_t block_count, + uint8_t* MAC_A) { + uint8_t iv[8] = {0}; + + uint8_t block_list_to_write = MIN(block_list_count, 4); + for(int i = 0; i < block_list_to_write; i++) { + iv[i * 2] = block_list[i]; + } + if(block_list_to_write < 4) { + iv[6] = 0xFF; + iv[7] = 0xFF; + } + if(block_list_to_write < 3) { + iv[4] = 0xFF; + iv[5] = 0xFF; + } + + felica_lite_calculate_mac_a(random_challenge, session_key, iv, block_data, block_count, MAC_A); +} + /** Parse common FeliCa response headers. * * This parses and validates the most commonly occurring response header types. @@ -165,7 +375,7 @@ FelicaICType felica_get_ic_type(uint8_t* PMm) { * @param always_succeed When set to true, skip status flags (sf1 and sf2) parsing. * @return The number of bytes parsed, or 0 when response is invalid or status flags are set. */ -static uint8_t felica_consume_header( +static uint8_t felica_consume_unencrypted_header( uint8_t* buf, uint8_t len, FelicaReader* reader, @@ -261,7 +471,8 @@ uint16_t felica_parse_unencrypted_read( FelicaReader* reader, uint8_t* out, uint16_t out_len) { - uint8_t consumed = felica_consume_header(buf, len, reader, FELICA_UNENCRYPTED_READ_RES, false); + uint8_t consumed = + felica_consume_unencrypted_header(buf, len, reader, FELICA_UNENCRYPTED_READ_RES, false); if(!consumed) { return 0; } @@ -345,7 +556,7 @@ uint8_t felica_lite_prepare_unencrypted_write( bool felica_parse_unencrypted_write(uint8_t* buf, uint8_t len, FelicaReader* reader) { uint8_t consumed = - felica_consume_header(buf, len, reader, FELICA_UNENCRYPTED_WRITE_RES, false); + felica_consume_unencrypted_header(buf, len, reader, FELICA_UNENCRYPTED_WRITE_RES, false); if(!consumed) { return false; } @@ -364,7 +575,7 @@ bool felica_parse_request_system_code( FelicaReader* reader, FelicaSystemArray_t* systems) { uint8_t consumed = - felica_consume_header(buf, len, reader, FELICA_REQUEST_SYSTEM_CODE_RES, true); + felica_consume_unencrypted_header(buf, len, reader, FELICA_REQUEST_SYSTEM_CODE_RES, true); if(consumed == 0) { return false; } diff --git a/lib/nfc/protocols/felica_util.c b/lib/nfc/protocols/felica_util.c index 481ea5ed7..47f66fcc5 100644 --- a/lib/nfc/protocols/felica_util.c +++ b/lib/nfc/protocols/felica_util.c @@ -11,6 +11,20 @@ uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t uni return TIME_CONSTANT_US * scale * (base_cost_factor + unit_cost_factor * units); } +bool felica_lite_is_issued(FelicaLiteInfo* lite_info) { + // System blocks aren't writable? + if(lite_info->memory_config[2] == 0x00) { + return false; + } + + // MC is not writable? + if(lite_info->memory_config[1] & 0x80) { + return false; + } + + return true; +} + FuriString* felica_get_system_name(FelicaSystem* system) { uint16_t code = system->code; diff --git a/lib/nfc/protocols/felica_util.h b/lib/nfc/protocols/felica_util.h index e53d66805..de7ff884a 100644 --- a/lib/nfc/protocols/felica_util.h +++ b/lib/nfc/protocols/felica_util.h @@ -1,5 +1,6 @@ #include "./felica.h" uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t units); +bool felica_lite_is_issued(FelicaLiteInfo* lite_info); FuriString* felica_get_system_name(FelicaSystem* system); FuriString* felica_get_service_name(FelicaService* service); \ No newline at end of file From f36beec01bac80a7ccf84a957ef4a3328ecc9135 Mon Sep 17 00:00:00 2001 From: nullableVoidPtr <30564701+nullableVoidPtr@users.noreply.github.com> Date: Sat, 29 Apr 2023 08:24:45 +0800 Subject: [PATCH 2/2] WIP --- .../main/nfc/scenes/nfc_scene_felica_menu.c | 9 +- lib/STM32CubeWB | 2 +- lib/nfc/nfc_device.c | 234 ++++++++++++++++-- lib/nfc/protocols/felica.c | 1 + lib/nfc/protocols/felica.h | 3 +- 5 files changed, 223 insertions(+), 26 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_felica_menu.c b/applications/main/nfc/scenes/nfc_scene_felica_menu.c index b989047d6..7aaba30db 100644 --- a/applications/main/nfc/scenes/nfc_scene_felica_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_felica_menu.c @@ -4,7 +4,9 @@ enum SubmenuIndex { /* SubmenuIndexUnlock, + */ SubmenuIndexSave, + /* SubmenuIndexEmulate, */ SubmenuIndexInfo, @@ -24,8 +26,10 @@ void nfc_scene_felica_menu_on_enter(void* context) { /* submenu_add_item( submenu, "Unlock", SubmenuIndexUnlock, nfc_scene_felica_menu_submenu_callback, nfc); + */ submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_felica_menu_submenu_callback, nfc); + /* submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_felica_menu_submenu_callback, nfc); */ @@ -43,13 +47,13 @@ bool nfc_scene_felica_menu_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - /* if(event.event == SubmenuIndexSave) { nfc->dev->format = NfcDeviceSaveFormatFelica; // Clear device name nfc_device_set_name(nfc->dev, ""); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; + /* } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { @@ -61,9 +65,8 @@ bool nfc_scene_felica_menu_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexUnlock) { scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaUnlockMenu); consumed = true; - } else */ - if(event.event == SubmenuIndexInfo) { + } else if(event.event == SubmenuIndexInfo) { scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaInfoSelect); consumed = true; } diff --git a/lib/STM32CubeWB b/lib/STM32CubeWB index 06b8133fa..a9e29b431 160000 --- a/lib/STM32CubeWB +++ b/lib/STM32CubeWB @@ -1 +1 @@ -Subproject commit 06b8133fa295474507b55b1a5695d4b8bf804ed6 +Subproject commit a9e29b431f6dac95b6fc860a717834f35b7f78e5 diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 6a2bcfcc0..09d9008d6 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -20,6 +20,7 @@ static const uint32_t nfc_keys_file_version = 1; // Protocols format versions static const uint32_t nfc_mifare_classic_data_format_version = 2; static const uint32_t nfc_mifare_ultralight_data_format_version = 1; +static const uint32_t nfc_felica_data_format_version = 1; NfcDevice* nfc_device_alloc() { NfcDevice* nfc_dev = malloc(sizeof(NfcDevice)); @@ -58,6 +59,8 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, FuriString* format_ furi_string_set(format_string, "Mifare Classic"); } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { furi_string_set(format_string, "Mifare DESFire"); + } else if(dev->format == NfcDeviceSaveFormatFelica) { + furi_string_set(format_string, "FeliCa"); } else { furi_string_set(format_string, "Unknown"); } @@ -781,6 +784,192 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* return saved; } +static bool nfc_device_save_felica_lite(FlipperFormat* file, FelicaLiteInfo* info) { + bool saved = false; + FuriString* key = furi_string_alloc(); + + do { + flipper_format_write_comment_cstr(file, "Lite(-S) System"); + flipper_format_write_hex(file, "Data Format Code", info->data_format_code, sizeof(uint16_t)); + flipper_format_write_hex(file, "ID Arbitrary Value", info->ID_value, 6); + flipper_format_write_hex(file, "Memory Config", info->memory_config, FELICA_BLOCK_SIZE); + + for(uint8_t block_num = 0; block_num < 14; block_num++) { + FuriString* spad_str = furi_string_alloc(); + for(size_t i = 0; i < FELICA_BLOCK_SIZE; i++) { + if(info->S_PAD[block_num] != NULL) { + furi_string_cat_printf(spad_str, "%02X ", info->S_PAD[block_num][i]); + } else { + furi_string_cat_printf(spad_str, "?? "); + } + } + + furi_string_printf(key, "S_PAD%d", block_num); + flipper_format_write_string(file, furi_string_get_cstr(key), spad_str); + } + + FuriString* reg_str = furi_string_alloc(); + for(size_t i = 0; i < FELICA_BLOCK_SIZE; i++) { + if(info->REG != NULL) { + furi_string_cat_printf(reg_str, "%02X ", info->REG[i]); + } else { + furi_string_cat_printf(reg_str, "?? "); + } + } + flipper_format_write_string(file, "REG", reg_str); + + flipper_format_write_hex(file, "Card Key Version", &info->card_key_version, sizeof(uint16_t)); + FuriString* ck1_str = furi_string_alloc(); + for(size_t i = 0; i < FELICA_BLOCK_SIZE; i++) { + if(info->REG != NULL) { + furi_string_cat_printf(ck1_str, "%02X ", info->card_key_1[i]); + } else { + furi_string_cat_printf(ck1_str, "?? "); + } + } + flipper_format_write_string(file, "Card Key 1", ck1_str); + + FuriString* ck2_str = furi_string_alloc(); + for(size_t i = 0; i < FELICA_BLOCK_SIZE; i++) { + if(info->REG != NULL) { + furi_string_cat_printf(ck2_str, "%02X ", info->card_key_2[i]); + } else { + furi_string_cat_printf(ck2_str, "?? "); + } + } + flipper_format_write_string(file, "Card Key 2", ck2_str); + + flipper_format_write_hex(file, "Fixed Challenge MAC Response", info->MAC, 8); + + flipper_format_write_bool(file, "Is Lite-S", &info->is_lite_s, 1); + if (info->is_lite_s) { + flipper_format_write_hex(file, "Fixed Challenge MAC-A Response", info->MAC_A, 8); + flipper_format_write_uint32(file, "Write Count", &info->write_count, 1); + } + + } while(false); + + return saved; +} + +static bool nfc_device_save_felica_area(FlipperFormat* file, FelicaArea* area) { + bool saved = false; + FuriString* prefix = furi_string_alloc_printf("Area %d", area->number); + FuriString* key = furi_string_alloc(); + + do { + furi_string_printf(key, "%s Can Create Subareas", prefix); + flipper_format_write_bool(file, furi_string_get_cstr(key), &area->can_create_subareas, 1); + furi_string_printf(key, "%s End Service Code", prefix); + flipper_format_write_hex(file, furi_string_get_cstr(key), (uint8_t*)&area->end_service_code, sizeof(uint16_t)); + + bool node_saved = true; + for + M_EACH(node, area->nodes, FelicaNodeArray_t) { + if (nfc_device_save_felica_node(file, node)) { + node_saved = false; + break; + } + } + + if (!node_saved) break; + saved = true; + } while(false); + + return saved; +} + +static bool nfc_device_save_felica_service(FlipperFormat* file, FelicaService* service) { + bool saved = false; + FuriString* prefix = furi_string_alloc_printf("Service %d", service->number); + FuriString* key = furi_string_alloc(); + + do { + furi_string_printf(key, "%s Is Extended Overlap", prefix); + flipper_format_write_bool(file, furi_string_get_cstr(key), &service->is_extended_overlap, 1); + if (service->is_extended_overlap) { + furi_string_printf(key, "%s Overlap Target", prefix); + flipper_format_write_hex(file, furi_string_get_cstr(key), (uint8_t*)&service->overlap_target, sizeof(uint16_t)); + + furi_string_printf(key, "%s Block Start", prefix); + const uint32_t block_start = service->block_start; + flipper_format_write_uint32(file, furi_string_get_cstr(key), &block_start, 1); + + furi_string_printf(key, "%s Block Count", prefix); + const uint32_t block_count = service->block_count; + flipper_format_write_uint32(file, furi_string_get_cstr(key), &block_count, 1); + + uint32_t i = 0; + for + M_EACH(block, service->blocks, FelicaBlockArray_t) { + furi_string_printf(key, "%s Block %d", prefix, i); + flipper_format_write_hex(file, furi_string_get_cstr(key), block->data, FELICA_BLOCK_SIZE); + } + } else { + furi_string_printf(key, "%s Block Count", prefix); + uint32_t block_count = FelicaBlockArray_size(service->blocks); + flipper_format_write_uint32(file, furi_string_get_cstr(key), &block_count, 1); + uint32_t i = 0; + for + M_EACH(block, service->blocks, FelicaBlockArray_t) { + furi_string_printf(key, "%s Block %d", prefix, i); + flipper_format_write_hex(file, furi_string_get_cstr(key), block->data, FELICA_BLOCK_SIZE); + } + } + + saved = true; + } while(false); + +} + +static bool nfc_device_save_felica_node(FlipperFormat* file, FelicaNode* node) { + bool saved = false; + FuriString* key = furi_string_alloc(); + + do { + if(node->type == FelicaNodeTypeArea) { + if(!nfc_device_save_felica_node(file, node->area)) { + saved = false; + break; + } + } else if(node->type == FelicaNodeTypeService) { + if(!nfc_device_save_felica_service(file, node->area)) { + saved = false; + break; + } + } + + saved = true; + } while(false); + + return saved; +} + +static bool nfc_device_save_felica_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + FelicaData* data = &dev->dev_data.felica_data; + // Save FeliCa specific data + do { + if(!flipper_format_write_comment_cstr(file, "FeliCa specific data")) break; + if(!flipper_format_write_uint32( + file, "Data format version", &nfc_felica_data_format_version, 1)) + break; + + for + M_EACH(system, data->systems, FelicaSystemArray_t) { + flipper_format_write_hex(file, "System", &system->number, sizeof(uint8_t)); + flipper_format_write_hex(file, "Code", (uint8_t*)&system->code, sizeof(uint16_t)); + if (system->code == LITE_SYSTEM_CODE) { + nfc_device_save_felica_lite(file, &system->lite_info); + } else { + nfc_device_save_felica_node(file, &system->root); + } + } + } while(false); + + return saved; +} + static void nfc_device_load_mifare_classic_block( FuriString* block_str, MfClassicData* data, @@ -1069,30 +1258,35 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break; // Write nfc device type if(!flipper_format_write_comment_cstr( - file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic")) + file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic, FeliCa")) break; nfc_device_prepare_format_string(dev, temp_str); if(!flipper_format_write_string(file, "Device type", temp_str)) break; - // Write UID, ATQA, SAK - if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats")) - break; - if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break; - // Save ATQA in MSB order for correct companion apps display - uint8_t atqa[2] = {data->a_data.atqa[1], data->a_data.atqa[0]}; - if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break; - if(!flipper_format_write_hex(file, "SAK", &data->a_data.sak, 1)) break; - // Save more data if necessary - if(dev->format == NfcDeviceSaveFormatMifareUl) { - if(!nfc_device_save_mifare_ul_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { - if(!nfc_device_save_mifare_df_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { - // Save data - if(!nfc_device_save_mifare_classic_data(file, dev)) break; - // Save keys cache - if(!nfc_device_save_mifare_classic_keys(dev)) break; + if(data->type == FuriHalNfcTypeA) { + // Write UID, ATQA, SAK + if(!flipper_format_write_comment_cstr( + file, "UID, ATQA and SAK are common for all A formats")) + break; + if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break; + // Save ATQA in MSB order for correct companion apps display + uint8_t atqa[2] = {data->a_data.atqa[1], data->a_data.atqa[0]}; + if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break; + if(!flipper_format_write_hex(file, "SAK", &data->a_data.sak, 1)) break; + // Save more data if necessary + if(dev->format == NfcDeviceSaveFormatMifareUl) { + if(!nfc_device_save_mifare_ul_data(file, dev)) break; + } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { + if(!nfc_device_save_mifare_df_data(file, dev)) break; + } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { + // Save data + if(!nfc_device_save_mifare_classic_data(file, dev)) break; + // Save keys cache + if(!nfc_device_save_mifare_classic_keys(dev)) break; + } + saved = true; + } else if(data->type == FuriHalNfcTypeF) { + if(!nfc_device_save_felica_data(file, dev)) break; } - saved = true; } while(0); if(!saved) { //-V547 diff --git a/lib/nfc/protocols/felica.c b/lib/nfc/protocols/felica.c index c5823a221..bf9da65f5 100644 --- a/lib/nfc/protocols/felica.c +++ b/lib/nfc/protocols/felica.c @@ -799,6 +799,7 @@ bool felica_lite_dump_data( } } if(data->type == FelicaICTypeLiteS) { + lite_info->is_lite_s = true; const uint8_t fixed_s_blocks[] = { CARD_KEY_LITE_BLOCK, MAC_A_LITE_BLOCK, diff --git a/lib/nfc/protocols/felica.h b/lib/nfc/protocols/felica.h index f8e504102..876596bb5 100644 --- a/lib/nfc/protocols/felica.h +++ b/lib/nfc/protocols/felica.h @@ -206,6 +206,7 @@ typedef struct { uint16_t card_key_version; uint8_t memory_config[FELICA_BLOCK_SIZE]; + bool is_lite_s; // Lite-S only uint8_t MAC_A[8]; uint32_t write_count; @@ -294,8 +295,6 @@ uint8_t felica_lite_prepare_unencrypted_write( const uint8_t* block_data); bool felica_parse_unencrypted_write(uint8_t* buf, uint8_t len, FelicaReader* reader); -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_push_normal_block(FelicaService* service, uint8_t* data);