Skip to content

Commit

Permalink
Picopass save as seader (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
bettse authored Dec 7, 2023
1 parent 6ff62d7 commit c8d2411
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .catalog/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 1.9
- Fix bug (#77) with loclass
- Better loclass notes
- Read card using nr-mac
- Save as Seader format
## 1.8
- Minimal changes for recent API updates
## 1.7
Expand Down
2 changes: 1 addition & 1 deletion application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ App(
],
stack_size=4 * 1024,
fap_description="App to communicate with NFC tags using the PicoPass(iClass) format",
fap_version="1.8",
fap_version="1.9",
fap_icon="125_10px.png",
fap_category="NFC",
fap_libs=["mbedtls"],
Expand Down
62 changes: 60 additions & 2 deletions picopass_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,59 @@ void picopass_device_set_name(PicopassDevice* dev, const char* name) {
strlcpy(dev->dev_name, name, PICOPASS_DEV_NAME_MAX_LEN);
}

// For use with Seader's virtual card processing.
static bool picopass_device_save_file_seader(
PicopassDevice* dev,
FlipperFormat* file,
FuriString* file_path) {
furi_assert(dev);
PicopassPacs* pacs = &dev->dev_data.pacs;
PicopassBlock* AA1 = dev->dev_data.AA1;
bool result = false;

const char* seader_file_header = "Flipper Seader Credential";
const uint32_t seader_file_version = 1;

do {
FURI_LOG_D(
TAG,
"Save %s %ld to %s",
seader_file_header,
seader_file_version,
furi_string_get_cstr(file_path));
if(!flipper_format_file_open_always(file, furi_string_get_cstr(file_path))) break;
if(!flipper_format_write_header_cstr(file, seader_file_header, seader_file_version)) break;
if(!flipper_format_write_uint32(file, "Bits", (uint32_t*)&pacs->bitLength, 1)) break;
if(!flipper_format_write_hex(file, "Credential", pacs->credential, PICOPASS_BLOCK_LEN))
break;

FURI_LOG_D(TAG, "Pre-sio");
// Seader only captures 64 byte SIO so I'm going to leave it at that
uint8_t sio[64];

// TODO: save SR vs SE more properly
if(pacs->sio) { // SR
for(uint8_t i = 0; i < 8; i++) {
memcpy(sio + (i * 8), AA1[10 + i].data, PICOPASS_BLOCK_LEN);
}
if(!flipper_format_write_hex(file, "SIO", sio, sizeof(sio))) break;
} else if(pacs->se_enabled) { //SE
for(uint8_t i = 0; i < 8; i++) {
memcpy(sio + (i * 8), AA1[6 + i].data, PICOPASS_BLOCK_LEN);
}
if(!flipper_format_write_hex(file, "SIO", sio, sizeof(sio))) break;
}
FURI_LOG_D(TAG, "post sio");
if(!flipper_format_write_hex(
file, "Diversifier", AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN))
break;

result = true;
} while(false);

return result;
}

static bool picopass_device_save_file_lfrfid(PicopassDevice* dev, FuriString* file_path) {
furi_assert(dev);
PicopassPacs* pacs = &dev->dev_data.pacs;
Expand Down Expand Up @@ -151,11 +204,13 @@ static bool picopass_device_save_file(
}
}
if(!block_saved) break;
saved = true;
} else if(dev->format == PicopassDeviceSaveFormatLF) {
saved = picopass_device_save_file_lfrfid(dev, temp_str);
} else if(dev->format == PicopassDeviceSaveFormatSeader) {
saved = picopass_device_save_file_seader(dev, file, temp_str);
}
saved = true;
} while(0);
} while(false);

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

return false;
Expand Down
1 change: 1 addition & 0 deletions picopass_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ typedef enum {
typedef enum {
PicopassDeviceSaveFormatHF,
PicopassDeviceSaveFormatLF,
PicopassDeviceSaveFormatSeader,
} PicopassDeviceSaveFormat;

typedef enum {
Expand Down
10 changes: 8 additions & 2 deletions protocol/picopass_poller.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,14 @@ NfcCommand picopass_poller_nr_mac_auth(PicopassPoller* instance) {
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);
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);
}
}

Expand Down
23 changes: 21 additions & 2 deletions scenes/picopass_scene_card_menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
enum SubmenuIndex {
SubmenuIndexSave,
SubmenuIndexSaveAsLF,
SubmenuIndexSaveAsSeader,
SubmenuIndexChangeKey,
SubmenuIndexWrite,
SubmenuIndexEmulate,
Expand Down Expand Up @@ -31,7 +32,12 @@ void picopass_scene_card_menu_on_enter(void* context) {
SubmenuIndexSave,
picopass_scene_card_menu_submenu_callback,
picopass);

submenu_add_item(
submenu,
"Save in Seader fmt",
SubmenuIndexSaveAsSeader,
picopass_scene_card_menu_submenu_callback,
picopass);
} else {
submenu_add_item(
submenu,
Expand All @@ -49,7 +55,14 @@ void picopass_scene_card_menu_on_enter(void* context) {
SubmenuIndexSaveAsLF,
picopass_scene_card_menu_submenu_callback,
picopass);

if(pacs->sio) { // SR
submenu_add_item(
submenu,
"Save in Seader fmt",
SubmenuIndexSaveAsSeader,
picopass_scene_card_menu_submenu_callback,
picopass);
}
submenu_add_item(
submenu,
"Write",
Expand Down Expand Up @@ -94,6 +107,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 == SubmenuIndexSaveAsSeader) {
scene_manager_set_scene_state(
picopass->scene_manager, PicopassSceneCardMenu, event.event);
scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName);
picopass->dev->format = PicopassDeviceSaveFormatSeader;
consumed = true;
} else if(event.event == SubmenuIndexSaveAsLF) {
scene_manager_set_scene_state(
picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexSaveAsLF);
Expand Down

0 comments on commit c8d2411

Please sign in to comment.