Przeglądaj źródła

Picopass save as seader (#81)

Eric Betts 2 lat temu
rodzic
commit
c8d2411aec

+ 5 - 0
.catalog/changelog.md

@@ -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

+ 1 - 1
application.fam

@@ -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"],

+ 60 - 2
picopass_device.c

@@ -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;
@@ -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");
@@ -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;

+ 1 - 0
picopass_device.h

@@ -70,6 +70,7 @@ typedef enum {
 typedef enum {
     PicopassDeviceSaveFormatHF,
     PicopassDeviceSaveFormatLF,
+    PicopassDeviceSaveFormatSeader,
 } PicopassDeviceSaveFormat;
 
 typedef enum {

+ 8 - 2
protocol/picopass_poller.c

@@ -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);
             }
         }
 

+ 21 - 2
scenes/picopass_scene_card_menu.c

@@ -3,6 +3,7 @@
 enum SubmenuIndex {
     SubmenuIndexSave,
     SubmenuIndexSaveAsLF,
+    SubmenuIndexSaveAsSeader,
     SubmenuIndexChangeKey,
     SubmenuIndexWrite,
     SubmenuIndexEmulate,
@@ -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,
@@ -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",
@@ -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);