MX 2 лет назад
Родитель
Сommit
17e059f482

+ 82 - 53
picopass_device.c

@@ -4,6 +4,10 @@
 #include <flipper_format/flipper_format.h>
 #include <picopass_icons.h>
 
+#include <toolbox/protocols/protocol_dict.h>
+#include <lfrfid/protocols/lfrfid_protocols.h>
+#include <lfrfid/lfrfid_dict_file.h>
+
 #define TAG "PicopassDevice"
 
 static const char* picopass_file_header = "Flipper Picopass device";
@@ -30,6 +34,69 @@ void picopass_device_set_name(PicopassDevice* dev, const char* name) {
     strlcpy(dev->dev_name, name, PICOPASS_DEV_NAME_MAX_LEN);
 }
 
+static bool picopass_device_save_file_lfrfid(PicopassDevice* dev, FuriString* file_path) {
+    furi_assert(dev);
+    PicopassPacs* pacs = &dev->dev_data.pacs;
+    ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
+    ProtocolId protocol = LFRFIDProtocolHidGeneric;
+
+    bool result = false;
+    uint64_t target = 0;
+    uint64_t sentinel = 1ULL << pacs->bitLength;
+    memcpy(&target, pacs->credential, RFAL_PICOPASS_BLOCK_LEN);
+    target = __builtin_bswap64(target);
+    FURI_LOG_D(TAG, "Original (%d): %016llx", pacs->bitLength, target);
+
+    if(pacs->bitLength == 26) {
+        //3 bytes
+        protocol = LFRFIDProtocolH10301;
+        // Remove parity
+        target = (target >> 1) & 0xFFFFFF;
+        // Reverse order since it'll get reversed again
+        target = __builtin_bswap64(target) >> (64 - 24);
+    } else if(pacs->bitLength < 44) {
+        // https://gist.github.com/blark/e8f125e402f576bdb7e2d7b3428bdba6
+        protocol = LFRFIDProtocolHidGeneric;
+        if(pacs->bitLength <= 36) {
+            uint64_t header = 1ULL << 37;
+            target = __builtin_bswap64((target | sentinel | header) << 4) >> (64 - 48);
+        } else {
+            target = __builtin_bswap64((target | sentinel) << 4) >> (64 - 48);
+        }
+    } else {
+        //8 bytes
+        protocol = LFRFIDProtocolHidExGeneric;
+        target = __builtin_bswap64(target);
+    }
+
+    size_t data_size = protocol_dict_get_data_size(dict, protocol);
+    uint8_t* data = malloc(data_size);
+    if(data_size < 8) {
+        memcpy(data, (void*)&target, data_size);
+    } else {
+        // data_size 12 for LFRFIDProtocolHidExGeneric
+        memcpy(data + 4, (void*)&target, 8);
+    }
+
+    protocol_dict_set_data(dict, protocol, data, data_size);
+    free(data);
+
+    FuriString* briefStr;
+    briefStr = furi_string_alloc();
+    protocol_dict_render_brief_data(dict, briefStr, protocol);
+    FURI_LOG_D(TAG, "LFRFID Brief: %s", furi_string_get_cstr(briefStr));
+
+    result = lfrfid_dict_file_save(dict, protocol, furi_string_get_cstr(file_path));
+    if(result) {
+        FURI_LOG_D(TAG, "Written: %d", result);
+    } else {
+        FURI_LOG_D(TAG, "Failed to write");
+    }
+
+    protocol_dict_free(dict);
+    return result;
+}
+
 static bool picopass_device_save_file(
     PicopassDevice* dev,
     const char* dev_name,
@@ -37,6 +104,7 @@ static bool picopass_device_save_file(
     const char* extension,
     bool use_load_path) {
     furi_assert(dev);
+    FURI_LOG_D(TAG, "Save File");
 
     bool saved = false;
     FlipperFormat* file = flipper_format_file_alloc(dev->storage);
@@ -55,30 +123,18 @@ static bool picopass_device_save_file(
             // First remove picopass device file if it was saved
             furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
         }
-        // Open file
-        if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
 
         if(dev->format == PicopassDeviceSaveFormatHF) {
-            uint32_t fc = pacs->record.FacilityCode;
-            uint32_t cn = pacs->record.CardNumber;
+            // Open file
+            if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
+
             // Write header
             if(!flipper_format_write_header_cstr(file, picopass_file_header, picopass_file_version))
                 break;
-            if(pacs->record.valid) {
-                if(!flipper_format_write_uint32(file, "Facility Code", &fc, 1)) break;
-                if(!flipper_format_write_uint32(file, "Card Number", &cn, 1)) break;
-                if(!flipper_format_write_hex(
-                       file, "Credential", pacs->credential, RFAL_PICOPASS_BLOCK_LEN))
-                    break;
-                if(pacs->pin_length > 0) {
-                    if(!flipper_format_write_hex(
-                           file, "PIN\t\t", pacs->pin0, RFAL_PICOPASS_BLOCK_LEN))
-                        break;
-                    if(!flipper_format_write_hex(
-                           file, "PIN(cont.)\t", pacs->pin1, RFAL_PICOPASS_BLOCK_LEN))
-                        break;
-                }
-            }
+            if(!flipper_format_write_hex(
+                   file, "Credential", pacs->credential, RFAL_PICOPASS_BLOCK_LEN))
+                break;
+
             // TODO: Add elite
             if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break;
             bool block_saved = true;
@@ -99,20 +155,7 @@ static bool picopass_device_save_file(
             }
             if(!block_saved) break;
         } else if(dev->format == PicopassDeviceSaveFormatLF) {
-            const char* lf_header = "Flipper RFID key";
-            // Write header
-            if(!flipper_format_write_header_cstr(file, lf_header, 1)) break;
-            if(!flipper_format_write_comment_cstr(
-                   file,
-                   "This was generated from the Picopass plugin and may not match current lfrfid"))
-                break;
-            // When lfrfid supports more formats, update this
-            if(!flipper_format_write_string_cstr(file, "Key type", "H10301")) break;
-            uint8_t H10301[3] = {0};
-            H10301[0] = pacs->record.FacilityCode;
-            H10301[1] = pacs->record.CardNumber >> 8;
-            H10301[2] = pacs->record.CardNumber & 0x00FF;
-            if(!flipper_format_write_hex(file, "Data", H10301, 3)) break;
+            saved = picopass_device_save_file_lfrfid(dev, temp_str);
         }
         saved = true;
     } while(0);
@@ -186,7 +229,7 @@ static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, boo
         if(!block_read) break;
 
         if(picopass_device_parse_credential(AA1, pacs) != ERR_NONE) break;
-        if(picopass_device_parse_wiegand(pacs->credential, &pacs->record) != ERR_NONE) break;
+        if(picopass_device_parse_wiegand(pacs->credential, pacs) != ERR_NONE) break;
 
         parsed = true;
     } while(false);
@@ -356,37 +399,23 @@ ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pa
     return ERR_NONE;
 }
 
-ReturnCode picopass_device_parse_wiegand(uint8_t* credential, PicopassWiegandRecord* record) {
+ReturnCode picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs) {
     uint32_t* halves = (uint32_t*)credential;
     if(halves[0] == 0) {
         uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1]));
-        record->bitLength = 31 - leading0s;
+        pacs->bitLength = 31 - leading0s;
     } else {
         uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[0]));
-        record->bitLength = 63 - leading0s;
+        pacs->bitLength = 63 - leading0s;
     }
-    FURI_LOG_D(TAG, "bitLength: %d", record->bitLength);
 
     // Remove sentinel bit from credential.  Byteswapping to handle array of bytes vs 64bit value
-    uint64_t sentinel = __builtin_bswap64(1ULL << record->bitLength);
+    uint64_t sentinel = __builtin_bswap64(1ULL << pacs->bitLength);
     uint64_t swapped = 0;
     memcpy(&swapped, credential, sizeof(uint64_t));
     swapped = swapped ^ sentinel;
     memcpy(credential, &swapped, sizeof(uint64_t));
-    FURI_LOG_D(TAG, "PACS: (%d) %016llx", record->bitLength, swapped);
+    FURI_LOG_D(TAG, "PACS: (%d) %016llx", pacs->bitLength, swapped);
 
-    if(record->bitLength == 26) {
-        uint8_t* v4 = credential + 4;
-        uint32_t bot = v4[3] | (v4[2] << 8) | (v4[1] << 16) | (v4[0] << 24);
-
-        record->CardNumber = (bot >> 1) & 0xFFFF;
-        record->FacilityCode = (bot >> 17) & 0xFF;
-        FURI_LOG_D(TAG, "FC: %u CN: %u", record->FacilityCode, record->CardNumber);
-        record->valid = true;
-    } else {
-        record->CardNumber = 0;
-        record->FacilityCode = 0;
-        record->valid = false;
-    }
     return ERR_NONE;
 }

+ 2 - 9
picopass_device.h

@@ -72,13 +72,6 @@ typedef enum {
     PicopassEmulatorStateSelected,
 } PicopassEmulatorState;
 
-typedef struct {
-    bool valid;
-    uint8_t bitLength;
-    uint8_t FacilityCode;
-    uint16_t CardNumber;
-} PicopassWiegandRecord;
-
 typedef struct {
     bool legacy;
     bool se_enabled;
@@ -88,10 +81,10 @@ typedef struct {
     bool elite_kdf;
     uint8_t pin_length;
     PicopassEncryption encryption;
+    uint8_t bitLength;
     uint8_t credential[8];
     uint8_t pin0[8];
     uint8_t pin1[8];
-    PicopassWiegandRecord record;
 } PicopassPacs;
 
 typedef struct {
@@ -146,4 +139,4 @@ void picopass_device_set_loading_callback(
     void* context);
 
 ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs);
-ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record);
+ReturnCode picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs);

+ 2 - 2
picopass_worker.c

@@ -606,7 +606,7 @@ void picopass_worker_elite_dict_attack(PicopassWorker* picopass_worker) {
                 break;
             }
 
-            err = picopass_device_parse_wiegand(pacs->credential, &pacs->record);
+            err = picopass_device_parse_wiegand(pacs->credential, pacs);
             if(err != ERR_NONE) {
                 FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err);
                 picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context);
@@ -715,7 +715,7 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
             }
 
             if(nextState == PicopassWorkerEventSuccess) {
-                err = picopass_device_parse_wiegand(pacs->credential, &pacs->record);
+                err = picopass_device_parse_wiegand(pacs->credential, pacs);
                 if(err != ERR_NONE) {
                     FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err);
                     nextState = PicopassWorkerEventFail;

+ 6 - 8
scenes/picopass_scene_card_menu.c

@@ -20,14 +20,12 @@ void picopass_scene_card_menu_on_enter(void* context) {
 
     submenu_add_item(
         submenu, "Save", SubmenuIndexSave, picopass_scene_card_menu_submenu_callback, picopass);
-    if(picopass->dev->dev_data.pacs.record.valid) {
-        submenu_add_item(
-            submenu,
-            "Save as LF",
-            SubmenuIndexSaveAsLF,
-            picopass_scene_card_menu_submenu_callback,
-            picopass);
-    }
+    submenu_add_item(
+        submenu,
+        "Save as LFRFID",
+        SubmenuIndexSaveAsLF,
+        picopass_scene_card_menu_submenu_callback,
+        picopass);
     submenu_add_item(
         submenu, "Write", SubmenuIndexWrite, picopass_scene_card_menu_submenu_callback, picopass);
     submenu_add_item(

+ 4 - 10
scenes/picopass_scene_device_info.c

@@ -31,12 +31,12 @@ void picopass_scene_device_info_on_enter(void* context) {
         furi_string_cat_printf(csn_str, "%02X ", csn[i]);
     }
 
-    if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) {
+    if(pacs->bitLength == 0 || pacs->bitLength == 255) {
         // Neither of these are valid.  Indicates the block was all 0x00 or all 0xff
         furi_string_cat_printf(wiegand_str, "Invalid PACS");
     } else {
-        size_t bytesLength = pacs->record.bitLength / 8;
-        if(pacs->record.bitLength % 8 > 0) {
+        size_t bytesLength = pacs->bitLength / 8;
+        if(pacs->bitLength % 8 > 0) {
             // Add extra byte if there are bits remaining
             bytesLength++;
         }
@@ -44,13 +44,7 @@ void picopass_scene_device_info_on_enter(void* context) {
         for(uint8_t i = RFAL_PICOPASS_BLOCK_LEN - bytesLength; i < RFAL_PICOPASS_BLOCK_LEN; i++) {
             furi_string_cat_printf(credential_str, "%02X", pacs->credential[i]);
         }
-
-        if(pacs->record.valid) {
-            furi_string_cat_printf(
-                wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber);
-        } else {
-            furi_string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength);
-        }
+        furi_string_cat_printf(wiegand_str, "%d bits", pacs->bitLength);
 
         if(pacs->sio) {
             furi_string_cat_printf(credential_str, " +SIO");

+ 3 - 9
scenes/picopass_scene_read_card_success.c

@@ -64,7 +64,7 @@ void picopass_scene_read_card_success_on_enter(void* context) {
             "Menu",
             picopass_scene_read_card_success_widget_callback,
             picopass);
-    } else if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) {
+    } else if(pacs->bitLength == 0 || pacs->bitLength == 255) {
         // Neither of these are valid.  Indicates the block was all 0x00 or all 0xff
         furi_string_cat_printf(wiegand_str, "Invalid PACS");
 
@@ -78,18 +78,12 @@ void picopass_scene_read_card_success_on_enter(void* context) {
             picopass_scene_read_card_success_widget_callback,
             picopass);
     } else {
-        size_t bytesLength = 1 + pacs->record.bitLength / 8;
+        size_t bytesLength = 1 + pacs->bitLength / 8;
         furi_string_set(credential_str, "");
         for(uint8_t i = RFAL_PICOPASS_BLOCK_LEN - bytesLength; i < RFAL_PICOPASS_BLOCK_LEN; i++) {
             furi_string_cat_printf(credential_str, "%02X", pacs->credential[i]);
         }
-
-        if(pacs->record.valid) {
-            furi_string_cat_printf(
-                wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber);
-        } else {
-            furi_string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength);
-        }
+        furi_string_cat_printf(wiegand_str, "%d bits", pacs->bitLength);
 
         if(pacs->sio) {
             furi_string_cat_printf(credential_str, " +SIO");