Skip to content

Commit d9d5c63

Browse files
authored
Picopass save as seader (#81)
1 parent db08fca commit d9d5c63

File tree

6 files changed

+96
-7
lines changed

6 files changed

+96
-7
lines changed

picopass/.catalog/changelog.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 1.9
2+
- Fix bug (#77) with loclass
3+
- Better loclass notes
4+
- Read card using nr-mac
5+
- Save as Seader format
16
## 1.8
27
- Minimal changes for recent API updates
38
## 1.7

picopass/application.fam

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ App(
1010
],
1111
stack_size=4 * 1024,
1212
fap_description="App to communicate with NFC tags using the PicoPass(iClass) format",
13-
fap_version="1.8",
13+
fap_version="1.9",
1414
fap_icon="125_10px.png",
1515
fap_category="NFC",
1616
fap_libs=["mbedtls"],

picopass/picopass_device.c

+60-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,59 @@ void picopass_device_set_name(PicopassDevice* dev, const char* name) {
3434
strlcpy(dev->dev_name, name, PICOPASS_DEV_NAME_MAX_LEN);
3535
}
3636

37+
// For use with Seader's virtual card processing.
38+
static bool picopass_device_save_file_seader(
39+
PicopassDevice* dev,
40+
FlipperFormat* file,
41+
FuriString* file_path) {
42+
furi_assert(dev);
43+
PicopassPacs* pacs = &dev->dev_data.pacs;
44+
PicopassBlock* AA1 = dev->dev_data.AA1;
45+
bool result = false;
46+
47+
const char* seader_file_header = "Flipper Seader Credential";
48+
const uint32_t seader_file_version = 1;
49+
50+
do {
51+
FURI_LOG_D(
52+
TAG,
53+
"Save %s %ld to %s",
54+
seader_file_header,
55+
seader_file_version,
56+
furi_string_get_cstr(file_path));
57+
if(!flipper_format_file_open_always(file, furi_string_get_cstr(file_path))) break;
58+
if(!flipper_format_write_header_cstr(file, seader_file_header, seader_file_version)) break;
59+
if(!flipper_format_write_uint32(file, "Bits", (uint32_t*)&pacs->bitLength, 1)) break;
60+
if(!flipper_format_write_hex(file, "Credential", pacs->credential, PICOPASS_BLOCK_LEN))
61+
break;
62+
63+
FURI_LOG_D(TAG, "Pre-sio");
64+
// Seader only captures 64 byte SIO so I'm going to leave it at that
65+
uint8_t sio[64];
66+
67+
// TODO: save SR vs SE more properly
68+
if(pacs->sio) { // SR
69+
for(uint8_t i = 0; i < 8; i++) {
70+
memcpy(sio + (i * 8), AA1[10 + i].data, PICOPASS_BLOCK_LEN);
71+
}
72+
if(!flipper_format_write_hex(file, "SIO", sio, sizeof(sio))) break;
73+
} else if(pacs->se_enabled) { //SE
74+
for(uint8_t i = 0; i < 8; i++) {
75+
memcpy(sio + (i * 8), AA1[6 + i].data, PICOPASS_BLOCK_LEN);
76+
}
77+
if(!flipper_format_write_hex(file, "SIO", sio, sizeof(sio))) break;
78+
}
79+
FURI_LOG_D(TAG, "post sio");
80+
if(!flipper_format_write_hex(
81+
file, "Diversifier", AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN))
82+
break;
83+
84+
result = true;
85+
} while(false);
86+
87+
return result;
88+
}
89+
3790
static bool picopass_device_save_file_lfrfid(PicopassDevice* dev, FuriString* file_path) {
3891
furi_assert(dev);
3992
PicopassPacs* pacs = &dev->dev_data.pacs;
@@ -151,11 +204,13 @@ static bool picopass_device_save_file(
151204
}
152205
}
153206
if(!block_saved) break;
207+
saved = true;
154208
} else if(dev->format == PicopassDeviceSaveFormatLF) {
155209
saved = picopass_device_save_file_lfrfid(dev, temp_str);
210+
} else if(dev->format == PicopassDeviceSaveFormatSeader) {
211+
saved = picopass_device_save_file_seader(dev, file, temp_str);
156212
}
157-
saved = true;
158-
} while(0);
213+
} while(false);
159214

160215
if(!saved) {
161216
dialog_message_show_storage_error(dev->dialogs, "Can not save\nfile");
@@ -171,6 +226,9 @@ bool picopass_device_save(PicopassDevice* dev, const char* dev_name) {
171226
dev, dev_name, STORAGE_APP_DATA_PATH_PREFIX, PICOPASS_APP_EXTENSION, true);
172227
} else if(dev->format == PicopassDeviceSaveFormatLF) {
173228
return picopass_device_save_file(dev, dev_name, ANY_PATH("lfrfid"), ".rfid", true);
229+
} else if(dev->format == PicopassDeviceSaveFormatSeader) {
230+
return picopass_device_save_file(
231+
dev, dev_name, EXT_PATH("apps_data/seader"), ".credential", true);
174232
}
175233

176234
return false;

picopass/picopass_device.h

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ typedef enum {
7070
typedef enum {
7171
PicopassDeviceSaveFormatHF,
7272
PicopassDeviceSaveFormatLF,
73+
PicopassDeviceSaveFormatSeader,
7374
} PicopassDeviceSaveFormat;
7475

7576
typedef enum {

picopass/protocol/picopass_poller.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,14 @@ NfcCommand picopass_poller_nr_mac_auth(PicopassPoller* instance) {
286286
picopass_poller_prepare_read(instance);
287287
instance->state = PicopassPollerStateReadBlock;
288288
// Set to non-zero keys to allow emulation
289-
memset(instance->data->AA1[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0xff, PICOPASS_BLOCK_LEN);
290-
memset(instance->data->AA1[PICOPASS_SECURE_KC_BLOCK_INDEX].data, 0xff, PICOPASS_BLOCK_LEN);
289+
memset(
290+
instance->data->AA1[PICOPASS_SECURE_KD_BLOCK_INDEX].data,
291+
0xff,
292+
PICOPASS_BLOCK_LEN);
293+
memset(
294+
instance->data->AA1[PICOPASS_SECURE_KC_BLOCK_INDEX].data,
295+
0xff,
296+
PICOPASS_BLOCK_LEN);
291297
}
292298
}
293299

picopass/scenes/picopass_scene_card_menu.c

+21-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
enum SubmenuIndex {
44
SubmenuIndexSave,
55
SubmenuIndexSaveAsLF,
6+
SubmenuIndexSaveAsSeader,
67
SubmenuIndexChangeKey,
78
SubmenuIndexWrite,
89
SubmenuIndexEmulate,
@@ -31,7 +32,12 @@ void picopass_scene_card_menu_on_enter(void* context) {
3132
SubmenuIndexSave,
3233
picopass_scene_card_menu_submenu_callback,
3334
picopass);
34-
35+
submenu_add_item(
36+
submenu,
37+
"Save in Seader fmt",
38+
SubmenuIndexSaveAsSeader,
39+
picopass_scene_card_menu_submenu_callback,
40+
picopass);
3541
} else {
3642
submenu_add_item(
3743
submenu,
@@ -49,7 +55,14 @@ void picopass_scene_card_menu_on_enter(void* context) {
4955
SubmenuIndexSaveAsLF,
5056
picopass_scene_card_menu_submenu_callback,
5157
picopass);
52-
58+
if(pacs->sio) { // SR
59+
submenu_add_item(
60+
submenu,
61+
"Save in Seader fmt",
62+
SubmenuIndexSaveAsSeader,
63+
picopass_scene_card_menu_submenu_callback,
64+
picopass);
65+
}
5366
submenu_add_item(
5467
submenu,
5568
"Write",
@@ -94,6 +107,12 @@ bool picopass_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
94107
scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName);
95108
picopass->dev->format = PicopassDeviceSaveFormatHF;
96109
consumed = true;
110+
} else if(event.event == SubmenuIndexSaveAsSeader) {
111+
scene_manager_set_scene_state(
112+
picopass->scene_manager, PicopassSceneCardMenu, event.event);
113+
scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName);
114+
picopass->dev->format = PicopassDeviceSaveFormatSeader;
115+
consumed = true;
97116
} else if(event.event == SubmenuIndexSaveAsLF) {
98117
scene_manager_set_scene_state(
99118
picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexSaveAsLF);

0 commit comments

Comments
 (0)