From 6ff62d7715ceacbfcab5409ba118d1a8bfa3c629 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Wed, 6 Dec 2023 07:46:02 -0800 Subject: [PATCH] Picopass read card using nr-mac (#79) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- picopass_i.h | 1 + protocol/picopass_listener.c | 90 ++++++++++++--- protocol/picopass_poller.c | 133 +++++++++++++++++++++- protocol/picopass_poller_i.c | 9 +- protocol/picopass_poller_i.h | 2 + scenes/picopass_scene_card_menu.c | 79 +++++++++---- scenes/picopass_scene_config.h | 1 + scenes/picopass_scene_device_info.c | 7 +- scenes/picopass_scene_emulate.c | 3 + scenes/picopass_scene_nr_mac_saved.c | 44 +++++++ scenes/picopass_scene_read_card_success.c | 21 +++- 11 files changed, 346 insertions(+), 44 deletions(-) create mode 100644 scenes/picopass_scene_nr_mac_saved.c diff --git a/picopass_i.h b/picopass_i.h index 2dee5f28a9a..e112d809015 100644 --- a/picopass_i.h +++ b/picopass_i.h @@ -51,6 +51,7 @@ enum PicopassCustomEvent { PicopassCustomEventDictAttackUpdateView, PicopassCustomEventLoclassGotMac, PicopassCustomEventLoclassGotStandardKey, + PicopassCustomEventNrMacSaved, PicopassCustomEventPollerSuccess, PicopassCustomEventPollerFail, diff --git a/protocol/picopass_listener.c b/protocol/picopass_listener.c index f5cef44370f..3b4e2c9d8dc 100644 --- a/protocol/picopass_listener.c +++ b/protocol/picopass_listener.c @@ -1,3 +1,4 @@ +#include "picopass_i.h" #include "picopass_listener_i.h" #include "picopass_keys.h" @@ -299,6 +300,61 @@ PicopassListenerCommand return command; } +PicopassListenerCommand picopass_listener_save_mac(PicopassListener* instance, uint8_t* rx_data) { + PicopassListenerCommand command = PicopassListenerCommandSilent; + Picopass* picopass = instance->context; + + PicopassDevice* dev = picopass->dev; + + const uint8_t* csn = instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data; + const uint8_t* epurse = instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data; + + FuriString* temp_str = furi_string_alloc(); + FuriString* filename = furi_string_alloc(); + FlipperFormat* file = flipper_format_file_alloc(dev->storage); + + for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { + furi_string_cat_printf(filename, "%02x", csn[i]); + } + furi_string_cat_printf(filename, "_"); + for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { + furi_string_cat_printf(filename, "%02x", epurse[i]); + } + + furi_string_printf( + temp_str, "%s/%s%s", STORAGE_APP_DATA_PATH_PREFIX, furi_string_get_cstr(filename), ".mac"); + do { + // Open file + if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break; + + if(!flipper_format_write_hex(file, "NR-MAC", rx_data + 1, PICOPASS_BLOCK_LEN)) break; + + FURI_LOG_D( + TAG, + "Saved nr-mac: %02x %02x %02x %02x %02x %02x %02x %02x", + // Skip command byte [0] + rx_data[1], + rx_data[2], + rx_data[3], + rx_data[4], + rx_data[5], + rx_data[6], + rx_data[7], + rx_data[8]); + + notification_message(picopass->notifications, &sequence_double_vibro); + command = PicopassListenerCommandStop; + view_dispatcher_send_custom_event( + picopass->view_dispatcher, PicopassCustomEventNrMacSaved); + } while(0); + + furi_string_free(temp_str); + furi_string_free(filename); + flipper_format_free(file); + + return command; +} + PicopassListenerCommand picopass_listener_check_handler_emulation(PicopassListener* instance, BitBuffer* buf) { PicopassListenerCommand command = PicopassListenerCommandSilent; @@ -310,23 +366,31 @@ PicopassListenerCommand // Since nr isn't const in loclass_opt_doBothMAC_2() copy buffer uint8_t rx_data[9] = {}; bit_buffer_write_bytes(buf, rx_data, sizeof(rx_data)); - loclass_opt_doBothMAC_2(instance->cipher_state, &rx_data[1], rmac, tmac, key); + bool no_key = picopass_is_memset(key, 0x00, PICOPASS_BLOCK_LEN); -#ifndef PICOPASS_DEBUG_IGNORE_BAD_RMAC - if(memcmp(&rx_data[5], rmac, 4)) { - // Bad MAC from reader, do not send a response. - FURI_LOG_I(TAG, "Got bad MAC from reader"); - // Reset the cipher state since we don't do it in READCHECK - picopass_listener_init_cipher_state(instance); + if(no_key) { + // We're emulating a partial dump of an iClass SE card and should capture the NR and MAC + command = picopass_listener_save_mac(instance, rx_data); break; - } + } else { + loclass_opt_doBothMAC_2(instance->cipher_state, &rx_data[1], rmac, tmac, key); + +#ifndef PICOPASS_DEBUG_IGNORE_BAD_RMAC + if(memcmp(&rx_data[5], rmac, PICOPASS_MAC_LEN)) { + // Bad MAC from reader, do not send a response. + FURI_LOG_I(TAG, "Got bad MAC from reader"); + // Reset the cipher state since we don't do it in READCHECK + picopass_listener_init_cipher_state(instance); + break; + } #endif - bit_buffer_copy_bytes(instance->tx_buffer, tmac, sizeof(tmac)); - NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer); - if(error != NfcErrorNone) { - FURI_LOG_D(TAG, "Failed tx update response: %d", error); - break; + bit_buffer_copy_bytes(instance->tx_buffer, tmac, sizeof(tmac)); + NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer); + if(error != NfcErrorNone) { + FURI_LOG_D(TAG, "Failed tx update response: %d", error); + break; + } } command = PicopassListenerCommandProcessed; diff --git a/protocol/picopass_poller.c b/protocol/picopass_poller.c index 690dddaae78..0ca614e1726 100644 --- a/protocol/picopass_poller.c +++ b/protocol/picopass_poller.c @@ -1,3 +1,4 @@ +#include "picopass_i.h" #include "picopass_poller_i.h" #include "../loclass/optimized_cipher.h" @@ -95,7 +96,7 @@ NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) { instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]); PicopassBlock block = {}; - error = picopass_poller_read_block(instance, 1, &block); + error = picopass_poller_read_block(instance, PICOPASS_CONFIG_BLOCK_INDEX, &block); if(error != PicopassErrorNone) { instance->state = PicopassPollerStateFail; break; @@ -116,6 +117,27 @@ NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) { instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[6], instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]); + error = picopass_poller_read_block(instance, PICOPASS_SECURE_EPURSE_BLOCK_INDEX, &block); + if(error != PicopassErrorNone) { + instance->state = PicopassPollerStateFail; + break; + } + memcpy( + instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data, + block.data, + sizeof(PicopassBlock)); + FURI_LOG_D( + TAG, + "epurse %02x%02x%02x%02x%02x%02x%02x%02x", + instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[0], + instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[1], + instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[2], + instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[3], + instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[4], + instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[5], + instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[6], + instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[7]); + error = picopass_poller_read_block(instance, 5, &block); if(error != PicopassErrorNone) { instance->state = PicopassPollerStateFail; @@ -165,10 +187,114 @@ NfcCommand picopass_poller_check_security(PicopassPoller* instance) { if(instance->data->pacs.se_enabled) { FURI_LOG_D(TAG, "SE enabled"); - instance->state = PicopassPollerStateFail; + instance->state = PicopassPollerStateNrMacAuth; } else { instance->state = PicopassPollerStateAuth; } + return command; +} + +NfcCommand picopass_poller_nr_mac_auth(PicopassPoller* instance) { + NfcCommand command = NfcCommandContinue; + Picopass* picopass = instance->context; + PicopassDevice* dev = picopass->dev; + + uint8_t* csn = instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data; + uint8_t* epurse = instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data; + + FuriString* temp_str = furi_string_alloc(); + FuriString* filename = furi_string_alloc(); + FlipperFormat* file = flipper_format_file_alloc(dev->storage); + PicopassMac mac = {}; + + for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { + furi_string_cat_printf(filename, "%02x", csn[i]); + } + furi_string_cat_printf(filename, "_"); + for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { + furi_string_cat_printf(filename, "%02x", epurse[i]); + } + + furi_string_printf( + temp_str, "%s/%s%s", STORAGE_APP_DATA_PATH_PREFIX, furi_string_get_cstr(filename), ".mac"); + + FURI_LOG_D(TAG, "Looking for %s", furi_string_get_cstr(temp_str)); + uint8_t nr_mac[PICOPASS_BLOCK_LEN]; + + // Presume failure unless all steps are successful and the state is made "read block" + instance->state = PicopassPollerStateFail; + do { + //check for file + if(!flipper_format_file_open_existing(file, furi_string_get_cstr(temp_str))) break; + // FURI_LOG_D(TAG, "Found %s", furi_string_get_cstr(temp_str)); + + furi_string_printf(temp_str, "NR-MAC"); + if(!flipper_format_read_hex( + file, furi_string_get_cstr(temp_str), nr_mac, PICOPASS_BLOCK_LEN)) + break; + memcpy(mac.data, nr_mac + 4, PICOPASS_MAC_LEN); + /* + FURI_LOG_D( + TAG, + "Read nr-mac: %02x %02x %02x %02x %02x %02x %02x %02x", + nr_mac[0], + nr_mac[1], + nr_mac[2], + nr_mac[3], + nr_mac[4], + nr_mac[5], + nr_mac[6], + nr_mac[7]); + FURI_LOG_D( + TAG, "MAC: %02x %02x %02x %02x", mac.data[0], mac.data[1], mac.data[2], mac.data[3]); + */ + + uint8_t ccnr[12] = {}; + PicopassReadCheckResp read_check_resp = {}; + PicopassError error = picopass_poller_read_check(instance, &read_check_resp); + if(error == PicopassErrorTimeout) { + instance->event.type = PicopassPollerEventTypeCardLost; + instance->callback(instance->event, instance->context); + instance->state = PicopassPollerStateDetect; + break; + } else if(error != PicopassErrorNone) { + FURI_LOG_E(TAG, "Read check failed: %d", error); + break; + } + memcpy(ccnr, read_check_resp.data, sizeof(PicopassReadCheckResp)); // last 4 bytes left 0 + + /* + FURI_LOG_D( + TAG, + "CCNR: %02x %02x %02x %02x %02x %02x %02x %02x", + ccnr[0], + ccnr[1], + ccnr[2], + ccnr[3], + ccnr[4], + ccnr[5], + ccnr[6], + ccnr[7]); + */ + + //use mac + PicopassCheckResp check_resp = {}; + error = picopass_poller_check(instance, nr_mac, &mac, &check_resp); + if(error == PicopassErrorNone) { + memcpy(instance->mac.data, mac.data, sizeof(PicopassMac)); + if(instance->mode == PicopassPollerModeRead) { + picopass_poller_prepare_read(instance); + instance->state = PicopassPollerStateReadBlock; + // Set to non-zero keys to allow emulation + memset(instance->data->AA1[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0xff, PICOPASS_BLOCK_LEN); + memset(instance->data->AA1[PICOPASS_SECURE_KC_BLOCK_INDEX].data, 0xff, PICOPASS_BLOCK_LEN); + } + } + + } while(false); + furi_string_free(temp_str); + furi_string_free(filename); + flipper_format_free(file); return command; } @@ -234,7 +360,7 @@ NfcCommand picopass_poller_auth_handler(PicopassPoller* instance) { loclass_opt_doReaderMAC(ccnr, div_key, mac.data); PicopassCheckResp check_resp = {}; - error = picopass_poller_check(instance, &mac, &check_resp); + error = picopass_poller_check(instance, NULL, &mac, &check_resp); if(error == PicopassErrorNone) { FURI_LOG_I(TAG, "Found key"); memcpy(instance->mac.data, mac.data, sizeof(PicopassMac)); @@ -457,6 +583,7 @@ static const PicopassPollerStateHandler picopass_poller_state_handler[PicopassPo [PicopassPollerStateSelect] = picopass_poller_select_handler, [PicopassPollerStatePreAuth] = picopass_poller_pre_auth_handler, [PicopassPollerStateCheckSecurity] = picopass_poller_check_security, + [PicopassPollerStateNrMacAuth] = picopass_poller_nr_mac_auth, [PicopassPollerStateAuth] = picopass_poller_auth_handler, [PicopassPollerStateReadBlock] = picopass_poller_read_block_handler, [PicopassPollerStateWriteBlock] = picopass_poller_write_block_handler, diff --git a/protocol/picopass_poller_i.c b/protocol/picopass_poller_i.c index 522cff5df1a..f95c4422bae 100644 --- a/protocol/picopass_poller_i.c +++ b/protocol/picopass_poller_i.c @@ -161,15 +161,20 @@ PicopassError PicopassError picopass_poller_check( PicopassPoller* instance, + uint8_t* nr, PicopassMac* mac, PicopassCheckResp* check_resp) { PicopassError ret = PicopassErrorNone; + uint8_t null_arr[4] = {}; do { bit_buffer_reset(instance->tx_buffer); bit_buffer_append_byte(instance->tx_buffer, RFAL_PICOPASS_CMD_CHECK); - uint8_t null_arr[4] = {}; - bit_buffer_append_bytes(instance->tx_buffer, null_arr, sizeof(null_arr)); + if(nr) { + bit_buffer_append_bytes(instance->tx_buffer, nr, 4); + } else { + bit_buffer_append_bytes(instance->tx_buffer, null_arr, sizeof(null_arr)); + } bit_buffer_append_bytes(instance->tx_buffer, mac->data, sizeof(PicopassMac)); NfcError error = nfc_poller_trx( diff --git a/protocol/picopass_poller_i.h b/protocol/picopass_poller_i.h index 0d0b7373d4d..6337b716570 100644 --- a/protocol/picopass_poller_i.h +++ b/protocol/picopass_poller_i.h @@ -20,6 +20,7 @@ typedef enum { PicopassPollerStateSelect, PicopassPollerStatePreAuth, PicopassPollerStateCheckSecurity, + PicopassPollerStateNrMacAuth, PicopassPollerStateAuth, PicopassPollerStateReadBlock, PicopassPollerStateWriteBlock, @@ -75,6 +76,7 @@ PicopassError PicopassError picopass_poller_check( PicopassPoller* instance, + uint8_t* nr, PicopassMac* mac, PicopassCheckResp* check_resp); diff --git a/scenes/picopass_scene_card_menu.c b/scenes/picopass_scene_card_menu.c index c42ae67dea7..981a90d01e8 100644 --- a/scenes/picopass_scene_card_menu.c +++ b/scenes/picopass_scene_card_menu.c @@ -6,6 +6,7 @@ enum SubmenuIndex { SubmenuIndexChangeKey, SubmenuIndexWrite, SubmenuIndexEmulate, + SubmenuIndexSavePartial, }; void picopass_scene_card_menu_submenu_callback(void* context, uint32_t index) { @@ -17,29 +18,57 @@ void picopass_scene_card_menu_submenu_callback(void* context, uint32_t index) { void picopass_scene_card_menu_on_enter(void* context) { Picopass* picopass = context; Submenu* submenu = picopass->submenu; + PicopassPacs* pacs = &picopass->dev->dev_data.pacs; + PicopassBlock* AA1 = picopass->dev->dev_data.AA1; - submenu_add_item( - submenu, "Save", SubmenuIndexSave, picopass_scene_card_menu_submenu_callback, picopass); - submenu_add_item( - submenu, - "Save as LFRFID", - SubmenuIndexSaveAsLF, - picopass_scene_card_menu_submenu_callback, - picopass); - submenu_add_item( - submenu, "Write", SubmenuIndexWrite, picopass_scene_card_menu_submenu_callback, picopass); - submenu_add_item( - submenu, - "Emulate", - SubmenuIndexEmulate, - picopass_scene_card_menu_submenu_callback, - picopass); - submenu_add_item( - submenu, - "Change Key", - SubmenuIndexChangeKey, - picopass_scene_card_menu_submenu_callback, - picopass); + bool sio = 0x30 == AA1[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[0]; + + if(pacs->se_enabled) { + if(sio) { + submenu_add_item( + submenu, + "Save", + SubmenuIndexSave, + picopass_scene_card_menu_submenu_callback, + picopass); + + } else { + submenu_add_item( + submenu, + "Save Partial", + SubmenuIndexSavePartial, + picopass_scene_card_menu_submenu_callback, + picopass); + } + } else { + submenu_add_item( + submenu, "Save", SubmenuIndexSave, picopass_scene_card_menu_submenu_callback, picopass); + submenu_add_item( + submenu, + "Save as LFRFID", + SubmenuIndexSaveAsLF, + picopass_scene_card_menu_submenu_callback, + picopass); + + submenu_add_item( + submenu, + "Write", + SubmenuIndexWrite, + picopass_scene_card_menu_submenu_callback, + picopass); + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexEmulate, + picopass_scene_card_menu_submenu_callback, + picopass); + submenu_add_item( + submenu, + "Change Key", + SubmenuIndexChangeKey, + picopass_scene_card_menu_submenu_callback, + picopass); + } submenu_set_selected_item( picopass->submenu, @@ -59,6 +88,12 @@ bool picopass_scene_card_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName); picopass->dev->format = PicopassDeviceSaveFormatHF; consumed = true; + } else if(event.event == SubmenuIndexSavePartial) { + scene_manager_set_scene_state( + picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexSave); + scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName); + picopass->dev->format = PicopassDeviceSaveFormatHF; + consumed = true; } else if(event.event == SubmenuIndexSaveAsLF) { scene_manager_set_scene_state( picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexSaveAsLF); diff --git a/scenes/picopass_scene_config.h b/scenes/picopass_scene_config.h index 3241c234411..496591a2d50 100644 --- a/scenes/picopass_scene_config.h +++ b/scenes/picopass_scene_config.h @@ -19,3 +19,4 @@ ADD_SCENE(picopass, elite_dict_attack, EliteDictAttack) ADD_SCENE(picopass, emulate, Emulate) ADD_SCENE(picopass, loclass, Loclass) ADD_SCENE(picopass, key_input, KeyInput) +ADD_SCENE(picopass, nr_mac_saved, NrMacSaved) diff --git a/scenes/picopass_scene_device_info.c b/scenes/picopass_scene_device_info.c index 7c67cd6693c..de794bb4ba3 100644 --- a/scenes/picopass_scene_device_info.c +++ b/scenes/picopass_scene_device_info.c @@ -30,8 +30,11 @@ void picopass_scene_device_info_on_enter(void* context) { for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { furi_string_cat_printf(csn_str, "%02X ", csn[i]); } + bool sio = 0x30 == AA1[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[0]; - if(pacs->bitLength == 0 || pacs->bitLength == 255) { + if(sio) { + furi_string_cat_printf(wiegand_str, "SIO"); + } else if(pacs->bitLength == 0 || pacs->bitLength == 255) { // Neither of these are valid. Indicates the block was all 0x00 or all 0xff furi_string_cat_printf(wiegand_str, "Invalid PACS"); } else { @@ -46,7 +49,7 @@ void picopass_scene_device_info_on_enter(void* context) { } furi_string_cat_printf(wiegand_str, "%d bits", pacs->bitLength); - if(pacs->sio) { + if(pacs->sio) { // SR furi_string_cat_printf(credential_str, " +SIO"); } } diff --git a/scenes/picopass_scene_emulate.c b/scenes/picopass_scene_emulate.c index 8f802c65992..a8b7878f056 100644 --- a/scenes/picopass_scene_emulate.c +++ b/scenes/picopass_scene_emulate.c @@ -32,6 +32,9 @@ bool picopass_scene_emulate_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == PicopassCustomEventWorkerExit) { consumed = true; + } else if(event.event == PicopassCustomEventNrMacSaved) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneNrMacSaved); + consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { consumed = scene_manager_previous_scene(picopass->scene_manager); diff --git a/scenes/picopass_scene_nr_mac_saved.c b/scenes/picopass_scene_nr_mac_saved.c new file mode 100644 index 00000000000..ba382cf1984 --- /dev/null +++ b/scenes/picopass_scene_nr_mac_saved.c @@ -0,0 +1,44 @@ +#include "../picopass_i.h" +#include + +void picopass_scene_nr_mac_saved_popup_callback(void* context) { + Picopass* picopass = context; + view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventViewExit); +} + +void picopass_scene_nr_mac_saved_on_enter(void* context) { + Picopass* picopass = context; + dolphin_deed(DolphinDeedNfcSave); + + // Setup view + Popup* popup = picopass->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "NR-MAC\nSaved!", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, picopass); + popup_set_callback(popup, picopass_scene_nr_mac_saved_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup); +} + +bool picopass_scene_nr_mac_saved_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == PicopassCustomEventViewExit) { + scene_manager_set_scene_state( + picopass->scene_manager, PicopassSceneStart, 0); // Set back to "read card" + consumed = scene_manager_search_and_switch_to_previous_scene( + picopass->scene_manager, PicopassSceneStart); + } + } + return consumed; +} + +void picopass_scene_nr_mac_saved_on_exit(void* context) { + Picopass* picopass = context; + + // Clear view + popup_reset(picopass->popup); +} diff --git a/scenes/picopass_scene_read_card_success.c b/scenes/picopass_scene_read_card_success.c index 8579d338353..0b9179d7e25 100644 --- a/scenes/picopass_scene_read_card_success.c +++ b/scenes/picopass_scene_read_card_success.c @@ -43,6 +43,7 @@ void picopass_scene_read_card_success_on_enter(void* context) { AA1[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0x00, PICOPASS_BLOCK_LEN); bool empty = picopass_is_memset( AA1[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN); + bool sio = 0x30 == AA1[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[0]; if(no_key) { furi_string_cat_printf(wiegand_str, "Read Failed"); @@ -50,6 +51,13 @@ void picopass_scene_read_card_success_on_enter(void* context) { if(pacs->se_enabled) { furi_string_cat_printf(credential_str, "SE enabled"); + + widget_add_button_element( + widget, + GuiButtonTypeRight, + "More", + picopass_scene_read_card_success_widget_callback, + picopass); } else if(!hid_csn) { furi_string_cat_printf(credential_str, "Non-HID CSN"); } @@ -70,8 +78,11 @@ void picopass_scene_read_card_success_on_enter(void* context) { picopass); } else if(pacs->bitLength == 0 || pacs->bitLength == 255) { // Neither of these are valid. Indicates the block was all 0x00 or all 0xff - furi_string_cat_printf(wiegand_str, "Invalid PACS"); - + if(sio) { + furi_string_cat_printf(wiegand_str, "SIO"); + } else { + furi_string_cat_printf(wiegand_str, "Invalid PACS"); + } if(pacs->se_enabled) { furi_string_cat_printf(credential_str, "SE enabled"); } @@ -81,6 +92,12 @@ void picopass_scene_read_card_success_on_enter(void* context) { "Menu", picopass_scene_read_card_success_widget_callback, picopass); + widget_add_button_element( + widget, + GuiButtonTypeRight, + "More", + picopass_scene_read_card_success_widget_callback, + picopass); } else { size_t bytesLength = 1 + pacs->bitLength / 8; furi_string_set(credential_str, "");