Skip to content

Commit 9cc6fb0

Browse files
authored
picopass: Add wiegand parsing plugin (#205)
1 parent ae4ce84 commit 9cc6fb0

8 files changed

+145
-1
lines changed

application.fam

+12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ App(
44
apptype=FlipperAppType.EXTERNAL,
55
targets=["f7"],
66
entry_point="picopass_app",
7+
sources=[
8+
"*.c", "!plugin/*.c",
9+
],
710
requires=[
811
"storage",
912
"gui",
@@ -23,3 +26,12 @@ App(
2326
fap_icon_assets="icons",
2427
fap_file_assets="files",
2528
)
29+
30+
App(
31+
appid="plugin_wiegand",
32+
apptype=FlipperAppType.PLUGIN,
33+
entry_point="plugin_wiegand_ep",
34+
requires=["picopass"],
35+
sources=["plugin/wiegand.c"],
36+
fal_embedded=True,
37+
)

picopass.c

+23
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,27 @@ Picopass* picopass_alloc() {
9797
view_dispatcher_add_view(
9898
picopass->view_dispatcher, PicopassViewLoclass, loclass_get_view(picopass->loclass));
9999

100+
picopass->plugin_manager =
101+
plugin_manager_alloc(PLUGIN_APP_ID, PLUGIN_API_VERSION, firmware_api_interface);
102+
103+
picopass->plugin_wiegand = NULL;
104+
if(plugin_manager_load_all(picopass->plugin_manager, APP_DATA_PATH("plugins")) !=
105+
PluginManagerErrorNone) {
106+
FURI_LOG_E(TAG, "Failed to load all libs");
107+
} else {
108+
uint32_t plugin_count = plugin_manager_get_count(picopass->plugin_manager);
109+
FURI_LOG_I(TAG, "Loaded %lu plugin(s)", plugin_count);
110+
111+
for(uint32_t i = 0; i < plugin_count; i++) {
112+
const PluginWiegand* plugin = plugin_manager_get_ep(picopass->plugin_manager, i);
113+
FURI_LOG_I(TAG, "plugin name: %s", plugin->name);
114+
if(strcmp(plugin->name, "Plugin Wiegand") == 0) {
115+
// Have to cast to drop "const" qualifier
116+
picopass->plugin_wiegand = (PluginWiegand*)plugin;
117+
}
118+
}
119+
}
120+
100121
return picopass;
101122
}
102123

@@ -158,6 +179,8 @@ void picopass_free(Picopass* picopass) {
158179
furi_record_close(RECORD_NOTIFICATION);
159180
picopass->notifications = NULL;
160181

182+
plugin_manager_free(picopass->plugin_manager);
183+
161184
free(picopass);
162185
}
163186

picopass_i.h

+8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
#include "protocol/picopass_poller.h"
3535
#include "protocol/picopass_listener.h"
3636

37+
#include "plugin/interface.h"
38+
#include <flipper_application/flipper_application.h>
39+
#include <flipper_application/plugins/plugin_manager.h>
40+
#include <loader/firmware_api/firmware_api.h>
41+
3742
#define PICOPASS_TEXT_STORE_SIZE 129
3843

3944
#define PICOPASS_ICLASS_ELITE_DICT_FLIPPER_NAME APP_ASSETS_PATH("iclass_elite_dict.txt")
@@ -107,6 +112,9 @@ struct Picopass {
107112
DictAttack* dict_attack;
108113
Loclass* loclass;
109114

115+
PluginManager* plugin_manager;
116+
PluginWiegand* plugin_wiegand;
117+
110118
PicopassDictAttackContext dict_attack_ctx;
111119
PicopassWriteKeyContext write_key_context;
112120
PicopassLoclassContext loclass_context;

plugin

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 30d5c440e6ca1aa92c56999758b38c52f3972c8a

scenes/picopass_scene_card_menu.c

+24
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ enum SubmenuIndex {
44
SubmenuIndexSave,
55
SubmenuIndexSaveAsLF,
66
SubmenuIndexSaveAsSeader,
7+
SubmenuIndexParse,
78
SubmenuIndexChangeKey,
89
SubmenuIndexWrite,
910
SubmenuIndexEmulate,
@@ -22,6 +23,7 @@ void picopass_scene_card_menu_on_enter(void* context) {
2223
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
2324
PicopassBlock* card_data = picopass->dev->dev_data.card_data;
2425
PicopassDeviceAuthMethod auth = picopass->dev->dev_data.auth;
26+
PluginWiegand* plugin = picopass->plugin_wiegand;
2527

2628
bool SE = card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].valid &&
2729
0x30 == card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[0];
@@ -59,6 +61,23 @@ void picopass_scene_card_menu_on_enter(void* context) {
5961
SubmenuIndexSaveAsLF,
6062
picopass_scene_card_menu_submenu_callback,
6163
picopass);
64+
65+
if(plugin) {
66+
// Convert from byte array to uint64_t
67+
uint64_t credential = 0;
68+
memcpy(&credential, pacs->credential, sizeof(uint64_t));
69+
credential = __builtin_bswap64(credential);
70+
71+
size_t format_count = plugin->count(pacs->bitLength, credential);
72+
if(format_count > 0) {
73+
submenu_add_item(
74+
submenu,
75+
"Parse",
76+
SubmenuIndexParse,
77+
picopass_scene_card_menu_submenu_callback,
78+
picopass);
79+
}
80+
}
6281
}
6382

6483
if(auth == PicopassDeviceAuthMethodNone || auth == PicopassDeviceAuthMethodKey) {
@@ -131,6 +150,11 @@ bool picopass_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
131150
picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexChangeKey);
132151
scene_manager_next_scene(picopass->scene_manager, PicopassSceneKeyMenu);
133152
consumed = true;
153+
} else if(event.event == SubmenuIndexParse) {
154+
scene_manager_set_scene_state(
155+
picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexParse);
156+
scene_manager_next_scene(picopass->scene_manager, PicopassSceneFormats);
157+
consumed = true;
134158
}
135159
} else if(event.type == SceneManagerEventTypeBack) {
136160
consumed = scene_manager_search_and_switch_to_previous_scene(

scenes/picopass_scene_config.h

+1
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ ADD_SCENE(picopass, loclass, Loclass)
2121
ADD_SCENE(picopass, key_input, KeyInput)
2222
ADD_SCENE(picopass, nr_mac_saved, NrMacSaved)
2323
ADD_SCENE(picopass, more_info, MoreInfo)
24+
ADD_SCENE(picopass, formats, Formats)

scenes/picopass_scene_device_info.c

+22-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ void picopass_scene_device_info_on_enter(void* context) {
2323
// Setup view
2424
PicopassBlock* card_data = picopass->dev->dev_data.card_data;
2525
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
26+
PluginWiegand* plugin = picopass->plugin_wiegand;
2627
Widget* widget = picopass->widget;
2728

2829
uint8_t csn[PICOPASS_BLOCK_LEN] = {0};
@@ -77,10 +78,27 @@ void picopass_scene_device_info_on_enter(void* context) {
7778
"Back",
7879
picopass_scene_device_info_widget_callback,
7980
picopass);
81+
82+
if(plugin) {
83+
// Convert from byte array to uint64_t
84+
uint64_t credential = 0;
85+
memcpy(&credential, pacs->credential, sizeof(uint64_t));
86+
credential = __builtin_bswap64(credential);
87+
88+
size_t format_count = plugin->count(pacs->bitLength, credential);
89+
if(format_count > 0) {
90+
widget_add_button_element(
91+
picopass->widget,
92+
GuiButtonTypeCenter,
93+
"Parse",
94+
picopass_scene_device_info_widget_callback,
95+
picopass);
96+
}
97+
}
8098
widget_add_button_element(
8199
picopass->widget,
82100
GuiButtonTypeRight,
83-
"More",
101+
"Raw",
84102
picopass_scene_device_info_widget_callback,
85103
picopass);
86104

@@ -97,6 +115,9 @@ bool picopass_scene_device_info_on_event(void* context, SceneManagerEvent event)
97115
} else if(event.event == GuiButtonTypeRight) {
98116
scene_manager_next_scene(picopass->scene_manager, PicopassSceneMoreInfo);
99117
consumed = true;
118+
} else if(event.event == GuiButtonTypeCenter) {
119+
scene_manager_next_scene(picopass->scene_manager, PicopassSceneFormats);
120+
consumed = true;
100121
} else if(event.event == PicopassCustomEventViewExit) {
101122
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
102123
consumed = true;

scenes/picopass_scene_formats.c

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "../picopass_i.h"
2+
#include <dolphin/dolphin.h>
3+
4+
void picopass_scene_formats_on_enter(void* context) {
5+
Picopass* picopass = context;
6+
PluginWiegand* plugin = picopass->plugin_wiegand;
7+
PicopassDevice* dev = picopass->dev;
8+
PicopassDeviceData dev_data = dev->dev_data;
9+
PicopassPacs pacs = dev_data.pacs;
10+
11+
FuriString* str = picopass->text_box_store;
12+
furi_string_reset(str);
13+
14+
// Convert from byte array to uint64_t
15+
uint64_t credential = 0;
16+
memcpy(&credential, pacs.credential, sizeof(pacs.credential));
17+
credential = __builtin_bswap64(credential);
18+
19+
if(plugin) {
20+
FuriString* description = furi_string_alloc();
21+
size_t format_count = plugin->count(pacs.bitLength, credential);
22+
for(size_t i = 0; i < format_count; i++) {
23+
plugin->description(pacs.bitLength, credential, i, description);
24+
25+
furi_string_cat_printf(str, "%s\n", furi_string_get_cstr(description));
26+
}
27+
furi_string_free(description);
28+
}
29+
30+
text_box_set_font(picopass->text_box, TextBoxFontHex);
31+
text_box_set_text(picopass->text_box, furi_string_get_cstr(picopass->text_box_store));
32+
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewTextBox);
33+
}
34+
35+
bool picopass_scene_formats_on_event(void* context, SceneManagerEvent event) {
36+
Picopass* picopass = context;
37+
bool consumed = false;
38+
39+
if(event.type == SceneManagerEventTypeCustom) {
40+
if(event.event == GuiButtonTypeLeft) {
41+
consumed = scene_manager_previous_scene(picopass->scene_manager);
42+
}
43+
} else if(event.type == SceneManagerEventTypeBack) {
44+
consumed = scene_manager_previous_scene(picopass->scene_manager);
45+
}
46+
return consumed;
47+
}
48+
49+
void picopass_scene_formats_on_exit(void* context) {
50+
Picopass* picopass = context;
51+
52+
// Clear views
53+
text_box_reset(picopass->text_box);
54+
}

0 commit comments

Comments
 (0)