diff --git a/picopass_device.c b/picopass_device.c index 92bd8f3889c..9f28aad12b0 100644 --- a/picopass_device.c +++ b/picopass_device.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -15,6 +16,7 @@ static const uint32_t picopass_file_version = 1; const uint8_t picopass_iclass_decryptionkey[] = {0xb4, 0x21, 0x2c, 0xca, 0xb7, 0xed, 0x21, 0x0f, 0x7b, 0x93, 0xd4, 0x59, 0x39, 0xc7, 0xdd, 0x36}; +const char unknown_block[] = "?? ?? ?? ?? ?? ?? ?? ??"; PicopassDevice* picopass_device_alloc() { PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice)); @@ -169,6 +171,7 @@ static bool picopass_device_save_file( if(dev->format == PicopassDeviceSaveFormatPartial) { // Clear key that may have been set when doing key tests for legacy memset(card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0, PICOPASS_BLOCK_LEN); + card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid = false; } do { @@ -203,13 +206,21 @@ static bool picopass_device_save_file( PICOPASS_MAX_APP_LIMIT; for(size_t i = 0; i < app_limit; i++) { furi_string_printf(temp_str, "Block %d", i); - if(!flipper_format_write_hex( - file, - furi_string_get_cstr(temp_str), - card_data[i].data, - PICOPASS_BLOCK_LEN)) { - block_saved = false; - break; + if(card_data[i].valid) { + if(!flipper_format_write_hex( + file, + furi_string_get_cstr(temp_str), + card_data[i].data, + PICOPASS_BLOCK_LEN)) { + block_saved = false; + break; + } + } else { + if(!flipper_format_write_string_cstr( + file, furi_string_get_cstr(temp_str), unknown_block)) { + block_saved = false; + break; + } } } if(!block_saved) break; @@ -246,6 +257,19 @@ bool picopass_device_save(PicopassDevice* dev, const char* dev_name) { return false; } +bool picopass_hex_str_to_uint8(const char* value_str, uint8_t* value) { + furi_check(value_str); + furi_check(value); + + bool parse_success = false; + while(*value_str && value_str[1]) { + parse_success = hex_char_to_uint8(*value_str, value_str[1], value++); + if(!parse_success) break; + value_str += 3; + } + return parse_success; +} + static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, bool show_dialog) { bool parsed = false; FlipperFormat* file = flipper_format_file_alloc(dev->storage); @@ -260,26 +284,39 @@ static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, boo } do { + picopass_device_data_clear(&dev->dev_data); if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break; // Read and verify file header uint32_t version = 0; if(!flipper_format_read_header(file, temp_str, &version)) break; - if(furi_string_cmp_str(temp_str, picopass_file_header) || + if(!furi_string_equal_str(temp_str, picopass_file_header) || (version != picopass_file_version)) { deprecated_version = true; break; } + FuriString* block_str = furi_string_alloc(); // Parse header blocks bool block_read = true; for(size_t i = 0; i < 6; i++) { furi_string_printf(temp_str, "Block %d", i); - if(!flipper_format_read_hex( - file, furi_string_get_cstr(temp_str), card_data[i].data, PICOPASS_BLOCK_LEN)) { + if(!flipper_format_read_string(file, furi_string_get_cstr(temp_str), block_str)) { block_read = false; break; } + if(furi_string_equal_str(block_str, unknown_block)) { + FURI_LOG_D(TAG, "Block %i: %s (unknown)", i, furi_string_get_cstr(block_str)); + card_data[i].valid = false; + memset(card_data[i].data, 0, PICOPASS_BLOCK_LEN); + } else { + FURI_LOG_D(TAG, "Block %i: %s (hex)", i, furi_string_get_cstr(block_str)); + if(!picopass_hex_str_to_uint8(furi_string_get_cstr(block_str), card_data[i].data)) { + block_read = false; + break; + } + card_data[i].valid = true; + } } size_t app_limit = card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[0]; @@ -287,16 +324,29 @@ static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, boo if(app_limit > PICOPASS_MAX_APP_LIMIT) app_limit = PICOPASS_MAX_APP_LIMIT; for(size_t i = 6; i < app_limit; i++) { furi_string_printf(temp_str, "Block %d", i); - if(!flipper_format_read_hex( - file, furi_string_get_cstr(temp_str), card_data[i].data, PICOPASS_BLOCK_LEN)) { + if(!flipper_format_read_string(file, furi_string_get_cstr(temp_str), block_str)) { block_read = false; break; } + if(furi_string_equal_str(block_str, unknown_block)) { + FURI_LOG_D(TAG, "Block %i: %s (unknown)", i, furi_string_get_cstr(block_str)); + card_data[i].valid = false; + memset(card_data[i].data, 0, PICOPASS_BLOCK_LEN); + } else { + FURI_LOG_D(TAG, "Block %i: %s (hex)", i, furi_string_get_cstr(block_str)); + if(!picopass_hex_str_to_uint8(furi_string_get_cstr(block_str), card_data[i].data)) { + block_read = false; + break; + } + card_data[i].valid = true; + } } if(!block_read) break; - picopass_device_parse_credential(card_data, pacs); - picopass_device_parse_wiegand(pacs->credential, pacs); + if(card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].valid) { + picopass_device_parse_credential(card_data, pacs); + picopass_device_parse_wiegand(pacs); + } parsed = true; } while(false); @@ -371,10 +421,14 @@ void picopass_device_data_clear(PicopassDeviceData* dev_data) { memset(dev_data->card_data[i].data, 0, sizeof(dev_data->card_data[i].data)); dev_data->card_data[i].valid = false; } + + memset(dev_data->pacs.credential, 0, sizeof(dev_data->pacs.credential)); dev_data->pacs.legacy = false; dev_data->pacs.se_enabled = false; dev_data->pacs.elite_kdf = false; + dev_data->pacs.sio = false; dev_data->pacs.pin_length = 0; + dev_data->pacs.bitLength = 0; } bool picopass_device_delete(PicopassDevice* dev, bool use_load_path) { @@ -450,7 +504,8 @@ void picopass_device_parse_credential(PicopassBlock* card_data, PicopassPacs* pa pacs->sio = (card_data[10].data[0] == 0x30); // rough check } -void picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs) { +void picopass_device_parse_wiegand(PicopassPacs* pacs) { + uint8_t* credential = pacs->credential; uint32_t* halves = (uint32_t*)credential; if(halves[0] == 0) { uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1])); diff --git a/picopass_device.h b/picopass_device.h index 4b4bed36699..53edcd71fc5 100644 --- a/picopass_device.h +++ b/picopass_device.h @@ -150,5 +150,5 @@ void picopass_device_set_loading_callback( void* context); void picopass_device_parse_credential(PicopassBlock* card_data, PicopassPacs* pacs); -void picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs); +void picopass_device_parse_wiegand(PicopassPacs* pacs); bool picopass_device_hid_csn(PicopassDevice* dev); diff --git a/protocol/picopass_listener.c b/protocol/picopass_listener.c index 15db3b44b1c..1a91a9c681c 100644 --- a/protocol/picopass_listener.c +++ b/protocol/picopass_listener.c @@ -378,7 +378,7 @@ PicopassListenerCommand uint8_t rmac[4] = {}; uint8_t tmac[4] = {}; const uint8_t* key = instance->data->card_data[instance->key_block_num].data; - bool no_key = picopass_is_memset(key, 0x00, PICOPASS_BLOCK_LEN); + bool no_key = !instance->data->card_data[instance->key_block_num].valid; const uint8_t* rx_data = bit_buffer_get_data(buf); if(no_key) { diff --git a/protocol/picopass_poller.c b/protocol/picopass_poller.c index ec6023915ef..4c9b74d2105 100644 --- a/protocol/picopass_poller.c +++ b/protocol/picopass_poller.c @@ -463,7 +463,7 @@ NfcCommand picopass_poller_parse_credential_handler(PicopassPoller* instance) { NfcCommand picopass_poller_parse_wiegand_handler(PicopassPoller* instance) { NfcCommand command = NfcCommandContinue; - picopass_device_parse_wiegand(instance->data->pacs.credential, &instance->data->pacs); + picopass_device_parse_wiegand(&instance->data->pacs); instance->state = PicopassPollerStateSuccess; return command; } diff --git a/scenes/picopass_scene_card_menu.c b/scenes/picopass_scene_card_menu.c index 68081c4f360..6caf5588713 100644 --- a/scenes/picopass_scene_card_menu.c +++ b/scenes/picopass_scene_card_menu.c @@ -28,8 +28,7 @@ void picopass_scene_card_menu_on_enter(void* context) { bool zero_config = picopass_is_memset( card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0x00, PICOPASS_BLOCK_LEN); bool no_credential = picopass_is_memset(pacs->credential, 0x00, sizeof(pacs->credential)); - bool no_key = picopass_is_memset( - card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN); + bool no_key = !card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid; if(secured && zero_config) { submenu_add_item( diff --git a/scenes/picopass_scene_device_info.c b/scenes/picopass_scene_device_info.c index 17d66fdf1d2..c08adfda236 100644 --- a/scenes/picopass_scene_device_info.c +++ b/scenes/picopass_scene_device_info.c @@ -102,8 +102,7 @@ bool picopass_scene_device_info_on_event(void* context, SceneManagerEvent event) consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); - consumed = true; + consumed = scene_manager_previous_scene(picopass->scene_manager); } return consumed; } diff --git a/scenes/picopass_scene_more_info.c b/scenes/picopass_scene_more_info.c index 4c075825c4d..28790fd5a5b 100644 --- a/scenes/picopass_scene_more_info.c +++ b/scenes/picopass_scene_more_info.c @@ -19,8 +19,12 @@ void picopass_scene_more_info_on_enter(void* context) { for(size_t i = 0; i < app_limit; i++) { for(size_t j = 0; j < PICOPASS_BLOCK_LEN; j += 2) { - furi_string_cat_printf( - str, "%02X%02X ", card_data[i].data[j], card_data[i].data[j + 1]); + if(card_data[i].valid) { + furi_string_cat_printf( + str, "%02X%02X ", card_data[i].data[j], card_data[i].data[j + 1]); + } else { + furi_string_cat_printf(str, "???? "); + } } } diff --git a/scenes/picopass_scene_read_card_success.c b/scenes/picopass_scene_read_card_success.c index 18e9e2d56c0..6c303374054 100644 --- a/scenes/picopass_scene_read_card_success.c +++ b/scenes/picopass_scene_read_card_success.c @@ -133,8 +133,7 @@ void picopass_scene_read_card_success_on_enter(void* context) { furi_string_cat_printf(credential_str, " +SIO"); } - bool no_key = picopass_is_memset( - card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN); + bool no_key = !card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid; if(no_key) { furi_string_cat_printf(key_str, "No Key: used NR-MAC");