Elite progress (#2481)
* WIP: builds * can read standard * Test standard picopass dictiony during attack * correctly save diversified key * read card on success * more logs * update file location * Call setup methods * backbutton and attempt at skip * fixed skip * remove found key state * rename dictionary attack * move notification * center button back to start menu * wait for card * Picopass: proper integer formatting * Picopass: even more proper integer formatting * remove nextState Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									8b2dfea925
								
							
						
					
					
						commit
						0161d49d80
					
				
							
								
								
									
										9
									
								
								applications/external/picopass/picopass.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								applications/external/picopass/picopass.c
									
									
									
									
										vendored
									
									
								
							| @ -73,6 +73,12 @@ Picopass* picopass_alloc() { | |||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         picopass->view_dispatcher, PicopassViewWidget, widget_get_view(picopass->widget)); |         picopass->view_dispatcher, PicopassViewWidget, widget_get_view(picopass->widget)); | ||||||
| 
 | 
 | ||||||
|  |     picopass->dict_attack = dict_attack_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         picopass->view_dispatcher, | ||||||
|  |         PicopassViewDictAttack, | ||||||
|  |         dict_attack_get_view(picopass->dict_attack)); | ||||||
|  | 
 | ||||||
|     return picopass; |     return picopass; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -103,6 +109,9 @@ void picopass_free(Picopass* picopass) { | |||||||
|     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewWidget); |     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewWidget); | ||||||
|     widget_free(picopass->widget); |     widget_free(picopass->widget); | ||||||
| 
 | 
 | ||||||
|  |     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewDictAttack); | ||||||
|  |     dict_attack_free(picopass->dict_attack); | ||||||
|  | 
 | ||||||
|     // Worker
 |     // Worker
 | ||||||
|     picopass_worker_stop(picopass->worker); |     picopass_worker_stop(picopass->worker); | ||||||
|     picopass_worker_free(picopass->worker); |     picopass_worker_free(picopass->worker); | ||||||
|  | |||||||
| @ -27,8 +27,16 @@ | |||||||
| #define PICOPASS_APP_EXTENSION ".picopass" | #define PICOPASS_APP_EXTENSION ".picopass" | ||||||
| #define PICOPASS_APP_SHADOW_EXTENSION ".pas" | #define PICOPASS_APP_SHADOW_EXTENSION ".pas" | ||||||
| 
 | 
 | ||||||
|  | #define PICOPASS_DICT_KEY_BATCH_SIZE 10 | ||||||
|  | 
 | ||||||
| typedef void (*PicopassLoadingCallback)(void* context, bool state); | typedef void (*PicopassLoadingCallback)(void* context, bool state); | ||||||
| 
 | 
 | ||||||
|  | typedef struct { | ||||||
|  |     IclassEliteDict* dict; | ||||||
|  |     IclassEliteDictType type; | ||||||
|  |     uint8_t current_sector; | ||||||
|  | } IclassEliteDictAttackData; | ||||||
|  | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     PicopassDeviceEncryptionUnknown = 0, |     PicopassDeviceEncryptionUnknown = 0, | ||||||
|     PicopassDeviceEncryptionNone = 0x14, |     PicopassDeviceEncryptionNone = 0x14, | ||||||
| @ -69,6 +77,7 @@ typedef struct { | |||||||
| typedef struct { | typedef struct { | ||||||
|     PicopassBlock AA1[PICOPASS_MAX_APP_LIMIT]; |     PicopassBlock AA1[PICOPASS_MAX_APP_LIMIT]; | ||||||
|     PicopassPacs pacs; |     PicopassPacs pacs; | ||||||
|  |     IclassEliteDictAttackData iclass_elite_dict_attack_data; | ||||||
| } PicopassDeviceData; | } PicopassDeviceData; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								applications/external/picopass/picopass_i.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								applications/external/picopass/picopass_i.h
									
									
									
									
										vendored
									
									
								
							| @ -21,6 +21,7 @@ | |||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| 
 | 
 | ||||||
| #include "scenes/picopass_scene.h" | #include "scenes/picopass_scene.h" | ||||||
|  | #include "views/dict_attack.h" | ||||||
| 
 | 
 | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| #include <lib/toolbox/path.h> | #include <lib/toolbox/path.h> | ||||||
| @ -36,6 +37,7 @@ enum PicopassCustomEvent { | |||||||
|     PicopassCustomEventWorkerExit, |     PicopassCustomEventWorkerExit, | ||||||
|     PicopassCustomEventByteInputDone, |     PicopassCustomEventByteInputDone, | ||||||
|     PicopassCustomEventTextInputDone, |     PicopassCustomEventTextInputDone, | ||||||
|  |     PicopassCustomEventDictAttackSkip, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -60,6 +62,7 @@ struct Picopass { | |||||||
|     Loading* loading; |     Loading* loading; | ||||||
|     TextInput* text_input; |     TextInput* text_input; | ||||||
|     Widget* widget; |     Widget* widget; | ||||||
|  |     DictAttack* dict_attack; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -68,6 +71,7 @@ typedef enum { | |||||||
|     PicopassViewLoading, |     PicopassViewLoading, | ||||||
|     PicopassViewTextInput, |     PicopassViewTextInput, | ||||||
|     PicopassViewWidget, |     PicopassViewWidget, | ||||||
|  |     PicopassViewDictAttack, | ||||||
| } PicopassView; | } PicopassView; | ||||||
| 
 | 
 | ||||||
| Picopass* picopass_alloc(); | Picopass* picopass_alloc(); | ||||||
|  | |||||||
							
								
								
									
										145
									
								
								applications/external/picopass/picopass_worker.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										145
									
								
								applications/external/picopass/picopass_worker.c
									
									
									
									
										vendored
									
									
								
							| @ -23,7 +23,7 @@ PicopassWorker* picopass_worker_alloc() { | |||||||
| 
 | 
 | ||||||
|     // Worker thread attributes
 |     // Worker thread attributes
 | ||||||
|     picopass_worker->thread = |     picopass_worker->thread = | ||||||
|         furi_thread_alloc_ex("PicopassWorker", 8192, picopass_worker_task, picopass_worker); |         furi_thread_alloc_ex("PicopassWorker", 8 * 1024, picopass_worker_task, picopass_worker); | ||||||
| 
 | 
 | ||||||
|     picopass_worker->callback = NULL; |     picopass_worker->callback = NULL; | ||||||
|     picopass_worker->context = NULL; |     picopass_worker->context = NULL; | ||||||
| @ -66,14 +66,12 @@ void picopass_worker_start( | |||||||
| 
 | 
 | ||||||
| void picopass_worker_stop(PicopassWorker* picopass_worker) { | void picopass_worker_stop(PicopassWorker* picopass_worker) { | ||||||
|     furi_assert(picopass_worker); |     furi_assert(picopass_worker); | ||||||
|     if(picopass_worker->state == PicopassWorkerStateBroken || |     furi_assert(picopass_worker->thread); | ||||||
|        picopass_worker->state == PicopassWorkerStateReady) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     picopass_worker_disable_field(ERR_NONE); |  | ||||||
| 
 | 
 | ||||||
|     picopass_worker_change_state(picopass_worker, PicopassWorkerStateStop); |     if(furi_thread_get_state(picopass_worker->thread) != FuriThreadStateStopped) { | ||||||
|     furi_thread_join(picopass_worker->thread); |         picopass_worker_change_state(picopass_worker, PicopassWorkerStateStop); | ||||||
|  |         furi_thread_join(picopass_worker->thread); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void picopass_worker_change_state(PicopassWorker* picopass_worker, PicopassWorkerState state) { | void picopass_worker_change_state(PicopassWorker* picopass_worker, PicopassWorkerState state) { | ||||||
| @ -460,6 +458,132 @@ ReturnCode picopass_write_block(PicopassBlock* AA1, uint8_t blockNo, uint8_t* ne | |||||||
|     return ERR_NONE; |     return ERR_NONE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void picopass_worker_elite_dict_attack(PicopassWorker* picopass_worker) { | ||||||
|  |     furi_assert(picopass_worker); | ||||||
|  |     furi_assert(picopass_worker->callback); | ||||||
|  | 
 | ||||||
|  |     picopass_device_data_clear(picopass_worker->dev_data); | ||||||
|  |     PicopassDeviceData* dev_data = picopass_worker->dev_data; | ||||||
|  |     PicopassBlock* AA1 = dev_data->AA1; | ||||||
|  |     PicopassPacs* pacs = &dev_data->pacs; | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) { | ||||||
|  |         memset(AA1[i].data, 0, sizeof(AA1[i].data)); | ||||||
|  |     } | ||||||
|  |     memset(pacs, 0, sizeof(PicopassPacs)); | ||||||
|  | 
 | ||||||
|  |     IclassEliteDictAttackData* dict_attack_data = | ||||||
|  |         &picopass_worker->dev_data->iclass_elite_dict_attack_data; | ||||||
|  |     bool elite = (dict_attack_data->type != IclassStandardDictTypeFlipper); | ||||||
|  | 
 | ||||||
|  |     rfalPicoPassReadCheckRes rcRes; | ||||||
|  |     rfalPicoPassCheckRes chkRes; | ||||||
|  | 
 | ||||||
|  |     ReturnCode err; | ||||||
|  |     uint8_t mac[4] = {0}; | ||||||
|  |     uint8_t ccnr[12] = {0}; | ||||||
|  | 
 | ||||||
|  |     size_t index = 0; | ||||||
|  |     uint8_t key[PICOPASS_BLOCK_LEN] = {0}; | ||||||
|  | 
 | ||||||
|  |     // Load dictionary
 | ||||||
|  |     IclassEliteDict* dict = dict_attack_data->dict; | ||||||
|  |     if(!dict) { | ||||||
|  |         FURI_LOG_E(TAG, "Dictionary not found"); | ||||||
|  |         picopass_worker->callback(PicopassWorkerEventNoDictFound, picopass_worker->context); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         if(picopass_detect_card(1000) == ERR_NONE) { | ||||||
|  |             picopass_worker->callback(PicopassWorkerEventCardDetected, picopass_worker->context); | ||||||
|  | 
 | ||||||
|  |             // Process first found device
 | ||||||
|  |             err = picopass_read_preauth(AA1); | ||||||
|  |             if(err != ERR_NONE) { | ||||||
|  |                 FURI_LOG_E(TAG, "picopass_read_preauth error %d", err); | ||||||
|  |                 picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Thank you proxmark!
 | ||||||
|  |             pacs->legacy = picopass_is_memset(AA1[5].data, 0xFF, 8); | ||||||
|  |             pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); | ||||||
|  |             if(pacs->se_enabled) { | ||||||
|  |                 FURI_LOG_D(TAG, "SE enabled"); | ||||||
|  |                 picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             break; | ||||||
|  |         } else { | ||||||
|  |             picopass_worker->callback(PicopassWorkerEventNoCardDetected, picopass_worker->context); | ||||||
|  |         } | ||||||
|  |         if(picopass_worker->state != PicopassWorkerStateEliteDictAttack) break; | ||||||
|  | 
 | ||||||
|  |         furi_delay_ms(100); | ||||||
|  |     } while(true); | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_D( | ||||||
|  |         TAG, "Start Dictionary attack, Key Count %lu", iclass_elite_dict_get_total_keys(dict)); | ||||||
|  |     while(iclass_elite_dict_get_next_key(dict, key)) { | ||||||
|  |         FURI_LOG_T(TAG, "Key %zu", index); | ||||||
|  |         if(++index % PICOPASS_DICT_KEY_BATCH_SIZE == 0) { | ||||||
|  |             picopass_worker->callback( | ||||||
|  |                 PicopassWorkerEventNewDictKeyBatch, picopass_worker->context); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         err = rfalPicoPassPollerReadCheck(&rcRes); | ||||||
|  |         if(err != ERR_NONE) { | ||||||
|  |             FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
 | ||||||
|  | 
 | ||||||
|  |         uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data; | ||||||
|  |         uint8_t* div_key = AA1[PICOPASS_KD_BLOCK_INDEX].data; | ||||||
|  | 
 | ||||||
|  |         loclass_iclass_calc_div_key(csn, key, div_key, elite); | ||||||
|  |         loclass_opt_doReaderMAC(ccnr, div_key, mac); | ||||||
|  | 
 | ||||||
|  |         err = rfalPicoPassPollerCheck(mac, &chkRes); | ||||||
|  |         if(err == ERR_NONE) { | ||||||
|  |             FURI_LOG_I(TAG, "Found key"); | ||||||
|  |             memcpy(pacs->key, key, PICOPASS_BLOCK_LEN); | ||||||
|  |             err = picopass_read_card(AA1); | ||||||
|  |             if(err != ERR_NONE) { | ||||||
|  |                 FURI_LOG_E(TAG, "picopass_read_card error %d", err); | ||||||
|  |                 picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             err = picopass_device_parse_credential(AA1, pacs); | ||||||
|  |             if(err != ERR_NONE) { | ||||||
|  |                 FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err); | ||||||
|  |                 picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             err = picopass_device_parse_wiegand(pacs->credential, &pacs->record); | ||||||
|  |             if(err != ERR_NONE) { | ||||||
|  |                 FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err); | ||||||
|  |                 picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(picopass_worker->state != PicopassWorkerStateEliteDictAttack) break; | ||||||
|  |     } | ||||||
|  |     FURI_LOG_D(TAG, "Dictionary complete"); | ||||||
|  |     if(picopass_worker->state == PicopassWorkerStateEliteDictAttack) { | ||||||
|  |         picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context); | ||||||
|  |     } else { | ||||||
|  |         picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int32_t picopass_worker_task(void* context) { | int32_t picopass_worker_task(void* context) { | ||||||
|     PicopassWorker* picopass_worker = context; |     PicopassWorker* picopass_worker = context; | ||||||
| 
 | 
 | ||||||
| @ -470,9 +594,12 @@ int32_t picopass_worker_task(void* context) { | |||||||
|         picopass_worker_write(picopass_worker); |         picopass_worker_write(picopass_worker); | ||||||
|     } else if(picopass_worker->state == PicopassWorkerStateWriteKey) { |     } else if(picopass_worker->state == PicopassWorkerStateWriteKey) { | ||||||
|         picopass_worker_write_key(picopass_worker); |         picopass_worker_write_key(picopass_worker); | ||||||
|  |     } else if(picopass_worker->state == PicopassWorkerStateEliteDictAttack) { | ||||||
|  |         picopass_worker_elite_dict_attack(picopass_worker); | ||||||
|  |     } else { | ||||||
|  |         FURI_LOG_W(TAG, "Unknown state %d", picopass_worker->state); | ||||||
|     } |     } | ||||||
|     picopass_worker_disable_field(ERR_NONE); |     picopass_worker_disable_field(ERR_NONE); | ||||||
| 
 |  | ||||||
|     picopass_worker_change_state(picopass_worker, PicopassWorkerStateReady); |     picopass_worker_change_state(picopass_worker, PicopassWorkerStateReady); | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ typedef enum { | |||||||
|     PicopassWorkerStateDetect, |     PicopassWorkerStateDetect, | ||||||
|     PicopassWorkerStateWrite, |     PicopassWorkerStateWrite, | ||||||
|     PicopassWorkerStateWriteKey, |     PicopassWorkerStateWriteKey, | ||||||
|  |     PicopassWorkerStateEliteDictAttack, | ||||||
|     // Transition
 |     // Transition
 | ||||||
|     PicopassWorkerStateStop, |     PicopassWorkerStateStop, | ||||||
| } PicopassWorkerState; | } PicopassWorkerState; | ||||||
| @ -27,8 +28,10 @@ typedef enum { | |||||||
|     PicopassWorkerEventFail, |     PicopassWorkerEventFail, | ||||||
|     PicopassWorkerEventNoCardDetected, |     PicopassWorkerEventNoCardDetected, | ||||||
|     PicopassWorkerEventSeEnabled, |     PicopassWorkerEventSeEnabled, | ||||||
| 
 |     PicopassWorkerEventAborted, | ||||||
|     PicopassWorkerEventStartReading, |     PicopassWorkerEventCardDetected, | ||||||
|  |     PicopassWorkerEventNewDictKeyBatch, | ||||||
|  |     PicopassWorkerEventNoDictFound, | ||||||
| } PicopassWorkerEvent; | } PicopassWorkerEvent; | ||||||
| 
 | 
 | ||||||
| typedef void (*PicopassWorkerCallback)(PicopassWorkerEvent event, void* context); | typedef void (*PicopassWorkerCallback)(PicopassWorkerEvent event, void* context); | ||||||
|  | |||||||
| @ -14,3 +14,4 @@ ADD_SCENE(picopass, write_card_success, WriteCardSuccess) | |||||||
| ADD_SCENE(picopass, read_factory_success, ReadFactorySuccess) | ADD_SCENE(picopass, read_factory_success, ReadFactorySuccess) | ||||||
| ADD_SCENE(picopass, write_key, WriteKey) | ADD_SCENE(picopass, write_key, WriteKey) | ||||||
| ADD_SCENE(picopass, key_menu, KeyMenu) | ADD_SCENE(picopass, key_menu, KeyMenu) | ||||||
|  | ADD_SCENE(picopass, elite_dict_attack, EliteDictAttack) | ||||||
|  | |||||||
							
								
								
									
										170
									
								
								applications/external/picopass/scenes/picopass_scene_elite_dict_attack.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								applications/external/picopass/scenes/picopass_scene_elite_dict_attack.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,170 @@ | |||||||
|  | #include "../picopass_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "IclassEliteDictAttack" | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DictAttackStateIdle, | ||||||
|  |     DictAttackStateUserDictInProgress, | ||||||
|  |     DictAttackStateFlipperDictInProgress, | ||||||
|  |     DictAttackStateStandardDictInProgress, | ||||||
|  | } DictAttackState; | ||||||
|  | 
 | ||||||
|  | void picopass_dict_attack_worker_callback(PicopassWorkerEvent event, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     view_dispatcher_send_custom_event(picopass->view_dispatcher, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_dict_attack_result_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     view_dispatcher_send_custom_event( | ||||||
|  |         picopass->view_dispatcher, PicopassCustomEventDictAttackSkip); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  |     picopass_scene_elite_dict_attack_prepare_view(Picopass* picopass, DictAttackState state) { | ||||||
|  |     IclassEliteDictAttackData* dict_attack_data = | ||||||
|  |         &picopass->dev->dev_data.iclass_elite_dict_attack_data; | ||||||
|  |     PicopassWorkerState worker_state = PicopassWorkerStateReady; | ||||||
|  |     IclassEliteDict* dict = NULL; | ||||||
|  | 
 | ||||||
|  |     // Identify scene state
 | ||||||
|  |     if(state == DictAttackStateIdle) { | ||||||
|  |         if(iclass_elite_dict_check_presence(IclassEliteDictTypeUser)) { | ||||||
|  |             FURI_LOG_D(TAG, "Starting with user dictionary"); | ||||||
|  |             state = DictAttackStateUserDictInProgress; | ||||||
|  |         } else { | ||||||
|  |             FURI_LOG_D(TAG, "Starting with standard dictionary"); | ||||||
|  |             state = DictAttackStateStandardDictInProgress; | ||||||
|  |         } | ||||||
|  |     } else if(state == DictAttackStateUserDictInProgress) { | ||||||
|  |         FURI_LOG_D(TAG, "Moving from user dictionary to standard dictionary"); | ||||||
|  |         state = DictAttackStateStandardDictInProgress; | ||||||
|  |     } else if(state == DictAttackStateStandardDictInProgress) { | ||||||
|  |         FURI_LOG_D(TAG, "Moving from standard dictionary to elite dictionary"); | ||||||
|  |         state = DictAttackStateFlipperDictInProgress; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Setup view
 | ||||||
|  |     if(state == DictAttackStateUserDictInProgress) { | ||||||
|  |         worker_state = PicopassWorkerStateEliteDictAttack; | ||||||
|  |         dict_attack_set_header(picopass->dict_attack, "Elite User Dictionary"); | ||||||
|  |         dict_attack_data->type = IclassEliteDictTypeUser; | ||||||
|  |         dict = iclass_elite_dict_alloc(IclassEliteDictTypeUser); | ||||||
|  | 
 | ||||||
|  |         // If failed to load user dictionary - try the system dictionary
 | ||||||
|  |         if(!dict) { | ||||||
|  |             FURI_LOG_E(TAG, "User dictionary not found"); | ||||||
|  |             state = DictAttackStateStandardDictInProgress; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if(state == DictAttackStateStandardDictInProgress) { | ||||||
|  |         worker_state = PicopassWorkerStateEliteDictAttack; | ||||||
|  |         dict_attack_set_header(picopass->dict_attack, "Standard System Dictionary"); | ||||||
|  |         dict_attack_data->type = IclassStandardDictTypeFlipper; | ||||||
|  |         dict = iclass_elite_dict_alloc(IclassStandardDictTypeFlipper); | ||||||
|  | 
 | ||||||
|  |         if(!dict) { | ||||||
|  |             FURI_LOG_E(TAG, "Flipper standard dictionary not found"); | ||||||
|  |             state = DictAttackStateFlipperDictInProgress; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if(state == DictAttackStateFlipperDictInProgress) { | ||||||
|  |         worker_state = PicopassWorkerStateEliteDictAttack; | ||||||
|  |         dict_attack_set_header(picopass->dict_attack, "Elite System Dictionary"); | ||||||
|  |         dict_attack_data->type = IclassEliteDictTypeFlipper; | ||||||
|  |         dict = iclass_elite_dict_alloc(IclassEliteDictTypeFlipper); | ||||||
|  |         if(!dict) { | ||||||
|  |             FURI_LOG_E(TAG, "Flipper Elite dictionary not found"); | ||||||
|  |             // Pass through to let the worker handle the failure
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // Free previous dictionary
 | ||||||
|  |     if(dict_attack_data->dict) { | ||||||
|  |         iclass_elite_dict_free(dict_attack_data->dict); | ||||||
|  |     } | ||||||
|  |     dict_attack_data->dict = dict; | ||||||
|  |     scene_manager_set_scene_state(picopass->scene_manager, PicopassSceneEliteDictAttack, state); | ||||||
|  |     dict_attack_set_callback( | ||||||
|  |         picopass->dict_attack, picopass_dict_attack_result_callback, picopass); | ||||||
|  |     dict_attack_set_current_sector(picopass->dict_attack, 0); | ||||||
|  |     dict_attack_set_card_detected(picopass->dict_attack); | ||||||
|  |     dict_attack_set_total_dict_keys( | ||||||
|  |         picopass->dict_attack, dict ? iclass_elite_dict_get_total_keys(dict) : 0); | ||||||
|  |     picopass_worker_start( | ||||||
|  |         picopass->worker, | ||||||
|  |         worker_state, | ||||||
|  |         &picopass->dev->dev_data, | ||||||
|  |         picopass_dict_attack_worker_callback, | ||||||
|  |         picopass); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_elite_dict_attack_on_enter(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     picopass_scene_elite_dict_attack_prepare_view(picopass, DictAttackStateIdle); | ||||||
|  |     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewDictAttack); | ||||||
|  |     picopass_blink_start(picopass); | ||||||
|  |     notification_message(picopass->notifications, &sequence_display_backlight_enforce_on); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool picopass_scene_elite_dict_attack_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     uint32_t state = | ||||||
|  |         scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneEliteDictAttack); | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == PicopassWorkerEventSuccess || | ||||||
|  |            event.event == PicopassWorkerEventAborted) { | ||||||
|  |             if(state == DictAttackStateUserDictInProgress || | ||||||
|  |                state == DictAttackStateStandardDictInProgress) { | ||||||
|  |                 picopass_worker_stop(picopass->worker); | ||||||
|  |                 picopass_scene_elite_dict_attack_prepare_view(picopass, state); | ||||||
|  |                 consumed = true; | ||||||
|  |             } else { | ||||||
|  |                 scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); | ||||||
|  |                 consumed = true; | ||||||
|  |             } | ||||||
|  |         } else if(event.event == PicopassWorkerEventCardDetected) { | ||||||
|  |             dict_attack_set_card_detected(picopass->dict_attack); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == PicopassWorkerEventNoCardDetected) { | ||||||
|  |             dict_attack_set_card_removed(picopass->dict_attack); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == PicopassWorkerEventNewDictKeyBatch) { | ||||||
|  |             dict_attack_inc_current_dict_key(picopass->dict_attack, PICOPASS_DICT_KEY_BATCH_SIZE); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == PicopassCustomEventDictAttackSkip) { | ||||||
|  |             if(state == DictAttackStateUserDictInProgress) { | ||||||
|  |                 picopass_worker_stop(picopass->worker); | ||||||
|  |                 consumed = true; | ||||||
|  |             } else if(state == DictAttackStateFlipperDictInProgress) { | ||||||
|  |                 picopass_worker_stop(picopass->worker); | ||||||
|  |                 consumed = true; | ||||||
|  |             } else if(state == DictAttackStateStandardDictInProgress) { | ||||||
|  |                 picopass_worker_stop(picopass->worker); | ||||||
|  |                 consumed = true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         consumed = scene_manager_previous_scene(picopass->scene_manager); | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_elite_dict_attack_on_exit(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     IclassEliteDictAttackData* dict_attack_data = | ||||||
|  |         &picopass->dev->dev_data.iclass_elite_dict_attack_data; | ||||||
|  |     // Stop worker
 | ||||||
|  |     picopass_worker_stop(picopass->worker); | ||||||
|  |     if(dict_attack_data->dict) { | ||||||
|  |         iclass_elite_dict_free(dict_attack_data->dict); | ||||||
|  |         dict_attack_data->dict = NULL; | ||||||
|  |     } | ||||||
|  |     dict_attack_reset(picopass->dict_attack); | ||||||
|  |     picopass_blink_stop(picopass); | ||||||
|  |     notification_message(picopass->notifications, &sequence_display_backlight_enforce_auto); | ||||||
|  | } | ||||||
| @ -47,8 +47,21 @@ void picopass_scene_read_card_success_on_enter(void* context) { | |||||||
|         if(pacs->se_enabled) { |         if(pacs->se_enabled) { | ||||||
|             furi_string_cat_printf(credential_str, "SE enabled"); |             furi_string_cat_printf(credential_str, "SE enabled"); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         widget_add_button_element( | ||||||
|  |             widget, | ||||||
|  |             GuiButtonTypeCenter, | ||||||
|  |             "Menu", | ||||||
|  |             picopass_scene_read_card_success_widget_callback, | ||||||
|  |             picopass); | ||||||
|     } else if(empty) { |     } else if(empty) { | ||||||
|         furi_string_cat_printf(wiegand_str, "Empty"); |         furi_string_cat_printf(wiegand_str, "Empty"); | ||||||
|  |         widget_add_button_element( | ||||||
|  |             widget, | ||||||
|  |             GuiButtonTypeCenter, | ||||||
|  |             "Menu", | ||||||
|  |             picopass_scene_read_card_success_widget_callback, | ||||||
|  |             picopass); | ||||||
|     } else if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) { |     } else if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) { | ||||||
|         // Neither of these are valid.  Indicates the block was all 0x00 or all 0xff
 |         // Neither of these are valid.  Indicates the block was all 0x00 or all 0xff
 | ||||||
|         furi_string_cat_printf(wiegand_str, "Invalid PACS"); |         furi_string_cat_printf(wiegand_str, "Invalid PACS"); | ||||||
| @ -56,6 +69,12 @@ void picopass_scene_read_card_success_on_enter(void* context) { | |||||||
|         if(pacs->se_enabled) { |         if(pacs->se_enabled) { | ||||||
|             furi_string_cat_printf(credential_str, "SE enabled"); |             furi_string_cat_printf(credential_str, "SE enabled"); | ||||||
|         } |         } | ||||||
|  |         widget_add_button_element( | ||||||
|  |             widget, | ||||||
|  |             GuiButtonTypeCenter, | ||||||
|  |             "Menu", | ||||||
|  |             picopass_scene_read_card_success_widget_callback, | ||||||
|  |             picopass); | ||||||
|     } else { |     } else { | ||||||
|         size_t bytesLength = 1 + pacs->record.bitLength / 8; |         size_t bytesLength = 1 + pacs->record.bitLength / 8; | ||||||
|         furi_string_set(credential_str, ""); |         furi_string_set(credential_str, ""); | ||||||
| @ -137,6 +156,9 @@ bool picopass_scene_read_card_success_on_event(void* context, SceneManagerEvent | |||||||
|             picopass_device_set_name(picopass->dev, ""); |             picopass_device_set_name(picopass->dev, ""); | ||||||
|             scene_manager_next_scene(picopass->scene_manager, PicopassSceneCardMenu); |             scene_manager_next_scene(picopass->scene_manager, PicopassSceneCardMenu); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == GuiButtonTypeCenter) { | ||||||
|  |             consumed = scene_manager_search_and_switch_to_another_scene( | ||||||
|  |                 picopass->scene_manager, PicopassSceneStart); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return consumed; |     return consumed; | ||||||
|  | |||||||
| @ -1,10 +1,8 @@ | |||||||
| #include "../picopass_i.h" | #include "../picopass_i.h" | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexRead, |     SubmenuIndexRead, | ||||||
|     SubmenuIndexRunScript, |     SubmenuIndexEliteDictAttack, | ||||||
|     SubmenuIndexSaved, |     SubmenuIndexSaved, | ||||||
|     SubmenuIndexAddManually, |  | ||||||
|     SubmenuIndexDebug, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void picopass_scene_start_submenu_callback(void* context, uint32_t index) { | void picopass_scene_start_submenu_callback(void* context, uint32_t index) { | ||||||
| @ -17,6 +15,12 @@ void picopass_scene_start_on_enter(void* context) { | |||||||
|     Submenu* submenu = picopass->submenu; |     Submenu* submenu = picopass->submenu; | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "Read Card", SubmenuIndexRead, picopass_scene_start_submenu_callback, picopass); |         submenu, "Read Card", SubmenuIndexRead, picopass_scene_start_submenu_callback, picopass); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Elite Dict. Attack", | ||||||
|  |         SubmenuIndexEliteDictAttack, | ||||||
|  |         picopass_scene_start_submenu_callback, | ||||||
|  |         picopass); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "Saved", SubmenuIndexSaved, picopass_scene_start_submenu_callback, picopass); |         submenu, "Saved", SubmenuIndexSaved, picopass_scene_start_submenu_callback, picopass); | ||||||
| 
 | 
 | ||||||
| @ -43,6 +47,11 @@ bool picopass_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 picopass->scene_manager, PicopassSceneStart, SubmenuIndexSaved); |                 picopass->scene_manager, PicopassSceneStart, SubmenuIndexSaved); | ||||||
|             scene_manager_next_scene(picopass->scene_manager, PicopassSceneFileSelect); |             scene_manager_next_scene(picopass->scene_manager, PicopassSceneFileSelect); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexEliteDictAttack) { | ||||||
|  |             scene_manager_set_scene_state( | ||||||
|  |                 picopass->scene_manager, PicopassSceneStart, SubmenuIndexEliteDictAttack); | ||||||
|  |             scene_manager_next_scene(picopass->scene_manager, PicopassSceneEliteDictAttack); | ||||||
|  |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										281
									
								
								applications/external/picopass/views/dict_attack.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								applications/external/picopass/views/dict_attack.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,281 @@ | |||||||
|  | #include "dict_attack.h" | ||||||
|  | 
 | ||||||
|  | #include <gui/elements.h> | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DictAttackStateRead, | ||||||
|  |     DictAttackStateCardRemoved, | ||||||
|  | } DictAttackState; | ||||||
|  | 
 | ||||||
|  | struct DictAttack { | ||||||
|  |     View* view; | ||||||
|  |     DictAttackCallback callback; | ||||||
|  |     void* context; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     DictAttackState state; | ||||||
|  |     MfClassicType type; | ||||||
|  |     FuriString* header; | ||||||
|  |     uint8_t sectors_total; | ||||||
|  |     uint8_t sectors_read; | ||||||
|  |     uint8_t sector_current; | ||||||
|  |     uint8_t keys_total; | ||||||
|  |     uint8_t keys_found; | ||||||
|  |     uint16_t dict_keys_total; | ||||||
|  |     uint16_t dict_keys_current; | ||||||
|  |     bool is_key_attack; | ||||||
|  |     uint8_t key_attack_current_sector; | ||||||
|  | } DictAttackViewModel; | ||||||
|  | 
 | ||||||
|  | static void dict_attack_draw_callback(Canvas* canvas, void* model) { | ||||||
|  |     DictAttackViewModel* m = model; | ||||||
|  |     if(m->state == DictAttackStateCardRemoved) { | ||||||
|  |         canvas_set_font(canvas, FontPrimary); | ||||||
|  |         canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!"); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         elements_multiline_text_aligned( | ||||||
|  |             canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly."); | ||||||
|  |     } else if(m->state == DictAttackStateRead) { | ||||||
|  |         char draw_str[32] = {}; | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         canvas_draw_str_aligned( | ||||||
|  |             canvas, 64, 0, AlignCenter, AlignTop, furi_string_get_cstr(m->header)); | ||||||
|  |         if(m->is_key_attack) { | ||||||
|  |             snprintf( | ||||||
|  |                 draw_str, | ||||||
|  |                 sizeof(draw_str), | ||||||
|  |                 "Reuse key check for sector: %d", | ||||||
|  |                 m->key_attack_current_sector); | ||||||
|  |         } else { | ||||||
|  |             snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->sector_current); | ||||||
|  |         } | ||||||
|  |         canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str); | ||||||
|  |         float dict_progress = m->dict_keys_total == 0 ? | ||||||
|  |                                   0 : | ||||||
|  |                                   (float)(m->dict_keys_current) / (float)(m->dict_keys_total); | ||||||
|  |         float progress = m->sectors_total == 0 ? 0 : | ||||||
|  |                                                  ((float)(m->sector_current) + dict_progress) / | ||||||
|  |                                                      (float)(m->sectors_total); | ||||||
|  |         if(progress > 1.0) { | ||||||
|  |             progress = 1.0; | ||||||
|  |         } | ||||||
|  |         if(m->dict_keys_current == 0) { | ||||||
|  |             // Cause when people see 0 they think it's broken
 | ||||||
|  |             snprintf(draw_str, sizeof(draw_str), "%d/%d", 1, m->dict_keys_total); | ||||||
|  |         } else { | ||||||
|  |             snprintf( | ||||||
|  |                 draw_str, sizeof(draw_str), "%d/%d", m->dict_keys_current, m->dict_keys_total); | ||||||
|  |         } | ||||||
|  |         elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); | ||||||
|  |         canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str); | ||||||
|  |         snprintf( | ||||||
|  |             draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total); | ||||||
|  |         canvas_draw_str_aligned(canvas, 0, 43, AlignLeft, AlignTop, draw_str); | ||||||
|  |     } | ||||||
|  |     elements_button_center(canvas, "Skip"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool dict_attack_input_callback(InputEvent* event, void* context) { | ||||||
|  |     DictAttack* dict_attack = context; | ||||||
|  |     bool consumed = false; | ||||||
|  |     if(event->type == InputTypeShort && event->key == InputKeyOk) { | ||||||
|  |         if(dict_attack->callback) { | ||||||
|  |             dict_attack->callback(dict_attack->context); | ||||||
|  |         } | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DictAttack* dict_attack_alloc() { | ||||||
|  |     DictAttack* dict_attack = malloc(sizeof(DictAttack)); | ||||||
|  |     dict_attack->view = view_alloc(); | ||||||
|  |     view_allocate_model(dict_attack->view, ViewModelTypeLocking, sizeof(DictAttackViewModel)); | ||||||
|  |     view_set_draw_callback(dict_attack->view, dict_attack_draw_callback); | ||||||
|  |     view_set_input_callback(dict_attack->view, dict_attack_input_callback); | ||||||
|  |     view_set_context(dict_attack->view, dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { model->header = furi_string_alloc(); }, | ||||||
|  |         false); | ||||||
|  |     return dict_attack; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_free(DictAttack* dict_attack) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { furi_string_free(model->header); }, | ||||||
|  |         false); | ||||||
|  |     view_free(dict_attack->view); | ||||||
|  |     free(dict_attack); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_reset(DictAttack* dict_attack) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { | ||||||
|  |             model->state = DictAttackStateRead; | ||||||
|  |             model->type = MfClassicType1k; | ||||||
|  |             model->sectors_total = 1; | ||||||
|  |             model->sectors_read = 0; | ||||||
|  |             model->sector_current = 0; | ||||||
|  |             model->keys_total = 0; | ||||||
|  |             model->keys_found = 0; | ||||||
|  |             model->dict_keys_total = 0; | ||||||
|  |             model->dict_keys_current = 0; | ||||||
|  |             model->is_key_attack = false; | ||||||
|  |             furi_string_reset(model->header); | ||||||
|  |         }, | ||||||
|  |         false); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* dict_attack_get_view(DictAttack* dict_attack) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     return dict_attack->view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     dict_attack->callback = callback; | ||||||
|  |     dict_attack->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_header(DictAttack* dict_attack, const char* header) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     furi_assert(header); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { furi_string_set(model->header, header); }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_card_detected(DictAttack* dict_attack) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { | ||||||
|  |             model->state = DictAttackStateRead; | ||||||
|  |             model->sectors_total = 1; | ||||||
|  |             model->keys_total = model->sectors_total; | ||||||
|  |         }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_card_removed(DictAttack* dict_attack) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { model->state = DictAttackStateCardRemoved; }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, DictAttackViewModel * model, { model->sectors_read = sec_read; }, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, DictAttackViewModel * model, { model->keys_found = keys_found; }, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { | ||||||
|  |             model->sector_current = curr_sec; | ||||||
|  |             model->dict_keys_current = 0; | ||||||
|  |         }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_current_sector(DictAttack* dict_attack) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { | ||||||
|  |             if(model->sector_current < model->sectors_total) { | ||||||
|  |                 model->sector_current++; | ||||||
|  |                 model->dict_keys_current = 0; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_keys_found(DictAttack* dict_attack) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { | ||||||
|  |             if(model->keys_found < model->keys_total) { | ||||||
|  |                 model->keys_found++; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { model->dict_keys_total = dict_keys_total; }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { | ||||||
|  |             if(model->dict_keys_current + keys_tried < model->dict_keys_total) { | ||||||
|  |                 model->dict_keys_current += keys_tried; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_key_attack(DictAttack* dict_attack, bool is_key_attack, uint8_t sector) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { | ||||||
|  |             model->is_key_attack = is_key_attack; | ||||||
|  |             model->key_attack_current_sector = sector; | ||||||
|  |         }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_key_attack_current_sector(DictAttack* dict_attack) { | ||||||
|  |     furi_assert(dict_attack); | ||||||
|  |     with_view_model( | ||||||
|  |         dict_attack->view, | ||||||
|  |         DictAttackViewModel * model, | ||||||
|  |         { | ||||||
|  |             if(model->key_attack_current_sector < model->sectors_total) { | ||||||
|  |                 model->key_attack_current_sector++; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         true); | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								applications/external/picopass/views/dict_attack.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								applications/external/picopass/views/dict_attack.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include <gui/modules/widget.h> | ||||||
|  | 
 | ||||||
|  | #include <lib/nfc/protocols/mifare_classic.h> | ||||||
|  | 
 | ||||||
|  | typedef struct DictAttack DictAttack; | ||||||
|  | 
 | ||||||
|  | typedef void (*DictAttackCallback)(void* context); | ||||||
|  | 
 | ||||||
|  | DictAttack* dict_attack_alloc(); | ||||||
|  | 
 | ||||||
|  | void dict_attack_free(DictAttack* dict_attack); | ||||||
|  | 
 | ||||||
|  | void dict_attack_reset(DictAttack* dict_attack); | ||||||
|  | 
 | ||||||
|  | View* dict_attack_get_view(DictAttack* dict_attack); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_header(DictAttack* dict_attack, const char* header); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_card_detected(DictAttack* dict_attack); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_card_removed(DictAttack* dict_attack); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec); | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_current_sector(DictAttack* dict_attack); | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_keys_found(DictAttack* dict_attack); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total); | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried); | ||||||
|  | 
 | ||||||
|  | void dict_attack_set_key_attack(DictAttack* dict_attack, bool is_key_attack, uint8_t sector); | ||||||
|  | 
 | ||||||
|  | void dict_attack_inc_key_attack_current_sector(DictAttack* dict_attack); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Eric Betts
						Eric Betts