Kaynağa Gözat

Picopass: detect and show SE / SIO (#1701)

* detect and show SE / SIO
* fix fault
* remove bad read check

Co-authored-by: あく <alleteam@gmail.com>
Patrick Cunningham 3 yıl önce
ebeveyn
işleme
c7cd5721ed

+ 2 - 4
applications/plugins/picopass/picopass_device.c

@@ -309,10 +309,6 @@ ReturnCode picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) {
 ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs) {
     ReturnCode err;
 
-    // Thank you proxmark!
-    pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
-    pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
-
     pacs->biometrics = AA1[6].data[4];
     pacs->pin_length = AA1[6].data[6] & 0x0F;
     pacs->encryption = AA1[6].data[7];
@@ -347,6 +343,8 @@ ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pa
         FURI_LOG_D(TAG, "Unknown encryption");
     }
 
+    pacs->sio = (AA1[10].data[0] == 0x30); // rough check
+
     return ERR_NONE;
 }
 

+ 1 - 0
applications/plugins/picopass/picopass_device.h

@@ -47,6 +47,7 @@ typedef struct {
 typedef struct {
     bool legacy;
     bool se_enabled;
+    bool sio;
     bool biometrics;
     uint8_t pin_length;
     PicopassEncryption encryption;

+ 80 - 18
applications/plugins/picopass/picopass_worker.c

@@ -112,18 +112,12 @@ ReturnCode picopass_detect_card(int timeout) {
     return ERR_NONE;
 }
 
-ReturnCode picopass_read_card(PicopassBlock* AA1) {
+ReturnCode picopass_read_preauth(PicopassBlock* AA1) {
     rfalPicoPassIdentifyRes idRes;
     rfalPicoPassSelectRes selRes;
-    rfalPicoPassReadCheckRes rcRes;
-    rfalPicoPassCheckRes chkRes;
 
     ReturnCode err;
 
-    uint8_t div_key[8] = {0};
-    uint8_t mac[4] = {0};
-    uint8_t ccnr[12] = {0};
-
     err = rfalPicoPassPollerIdentify(&idRes);
     if(err != ERR_NONE) {
         FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
@@ -136,6 +130,62 @@ ReturnCode picopass_read_card(PicopassBlock* AA1) {
         return err;
     }
 
+    memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, selRes.CSN, sizeof(selRes.CSN));
+    FURI_LOG_D(
+        TAG,
+        "csn %02x%02x%02x%02x%02x%02x%02x%02x",
+        AA1[PICOPASS_CSN_BLOCK_INDEX].data[0],
+        AA1[PICOPASS_CSN_BLOCK_INDEX].data[1],
+        AA1[PICOPASS_CSN_BLOCK_INDEX].data[2],
+        AA1[PICOPASS_CSN_BLOCK_INDEX].data[3],
+        AA1[PICOPASS_CSN_BLOCK_INDEX].data[4],
+        AA1[PICOPASS_CSN_BLOCK_INDEX].data[5],
+        AA1[PICOPASS_CSN_BLOCK_INDEX].data[6],
+        AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]);
+
+    rfalPicoPassReadBlockRes cfg = {0};
+    err = rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg);
+    memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data));
+    FURI_LOG_D(
+        TAG,
+        "config %02x%02x%02x%02x%02x%02x%02x%02x",
+        AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0],
+        AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[1],
+        AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[2],
+        AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[3],
+        AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[4],
+        AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[5],
+        AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[6],
+        AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]);
+
+    rfalPicoPassReadBlockRes aia;
+    err = rfalPicoPassPollerReadBlock(PICOPASS_AIA_BLOCK_INDEX, &aia);
+    memcpy(AA1[PICOPASS_AIA_BLOCK_INDEX].data, aia.data, sizeof(aia.data));
+    FURI_LOG_D(
+        TAG,
+        "aia %02x%02x%02x%02x%02x%02x%02x%02x",
+        AA1[PICOPASS_AIA_BLOCK_INDEX].data[0],
+        AA1[PICOPASS_AIA_BLOCK_INDEX].data[1],
+        AA1[PICOPASS_AIA_BLOCK_INDEX].data[2],
+        AA1[PICOPASS_AIA_BLOCK_INDEX].data[3],
+        AA1[PICOPASS_AIA_BLOCK_INDEX].data[4],
+        AA1[PICOPASS_AIA_BLOCK_INDEX].data[5],
+        AA1[PICOPASS_AIA_BLOCK_INDEX].data[6],
+        AA1[PICOPASS_AIA_BLOCK_INDEX].data[7]);
+
+    return ERR_NONE;
+}
+
+ReturnCode picopass_read_card(PicopassBlock* AA1) {
+    rfalPicoPassReadCheckRes rcRes;
+    rfalPicoPassCheckRes chkRes;
+
+    ReturnCode err;
+
+    uint8_t div_key[8] = {0};
+    uint8_t mac[4] = {0};
+    uint8_t ccnr[12] = {0};
+
     err = rfalPicoPassPollerReadCheck(&rcRes);
     if(err != ERR_NONE) {
         FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
@@ -143,7 +193,7 @@ ReturnCode picopass_read_card(PicopassBlock* AA1) {
     }
     memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
 
-    loclass_diversifyKey(selRes.CSN, picopass_iclass_key, div_key);
+    loclass_diversifyKey(AA1[PICOPASS_CSN_BLOCK_INDEX].data, picopass_iclass_key, div_key);
     loclass_opt_doReaderMAC(ccnr, div_key, mac);
 
     err = rfalPicoPassPollerCheck(mac, &chkRes);
@@ -152,18 +202,11 @@ ReturnCode picopass_read_card(PicopassBlock* AA1) {
         return err;
     }
 
-    rfalPicoPassReadBlockRes csn;
-    err = rfalPicoPassPollerReadBlock(PICOPASS_CSN_BLOCK_INDEX, &csn);
-    memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, csn.data, sizeof(csn.data));
-
-    rfalPicoPassReadBlockRes cfg;
-    err = rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg);
-    memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data));
-
-    size_t app_limit = cfg.data[0] < PICOPASS_MAX_APP_LIMIT ? cfg.data[0] : PICOPASS_MAX_APP_LIMIT;
+    size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ?
+                           AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
+                           PICOPASS_MAX_APP_LIMIT;
 
     for(size_t i = 2; i < app_limit; i++) {
-        FURI_LOG_D(TAG, "rfalPicoPassPollerReadBlock block %d", i);
         rfalPicoPassReadBlockRes block;
         err = rfalPicoPassPollerReadBlock(i, &block);
         if(err != ERR_NONE) {
@@ -287,11 +330,30 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
     PicopassPacs* pacs = &dev_data->pacs;
     ReturnCode err;
 
+    // reset device data
+    for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
+        memset(AA1[i].data, 0, sizeof(AA1[i].data));
+    }
+    memset(pacs, 0, sizeof(PicopassPacs));
+
     PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
 
     while(picopass_worker->state == PicopassWorkerStateDetect) {
         if(picopass_detect_card(1000) == ERR_NONE) {
             // Process first found device
+            err = picopass_read_preauth(AA1);
+            if(err != ERR_NONE) {
+                FURI_LOG_E(TAG, "picopass_read_preauth error %d", err);
+                nextState = PicopassWorkerEventFail;
+            }
+
+            // Thank you proxmark!
+            pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
+            pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
+            if(pacs->se_enabled) {
+                FURI_LOG_D(TAG, "SE enabled");
+            }
+
             err = picopass_read_card(AA1);
             if(err != ERR_NONE) {
                 FURI_LOG_E(TAG, "picopass_read_card error %d", err);

+ 1 - 0
applications/plugins/picopass/picopass_worker.h

@@ -24,6 +24,7 @@ typedef enum {
     PicopassWorkerEventSuccess,
     PicopassWorkerEventFail,
     PicopassWorkerEventNoCardDetected,
+    PicopassWorkerEventSeEnabled,
 
     PicopassWorkerEventStartReading,
 } PicopassWorkerEvent;

+ 19 - 13
applications/plugins/picopass/scenes/picopass_scene_read_card_success.c

@@ -17,8 +17,10 @@ void picopass_scene_read_card_success_on_enter(void* context) {
     Picopass* picopass = context;
     string_t credential_str;
     string_t wiegand_str;
+    string_t sio_str;
     string_init(credential_str);
     string_init(wiegand_str);
+    string_init(sio_str);
 
     DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
 
@@ -32,6 +34,10 @@ void picopass_scene_read_card_success_on_enter(void* context) {
     if(pacs->record.bitLength == 0) {
         string_cat_printf(wiegand_str, "Read Failed");
 
+        if(pacs->se_enabled) {
+            string_cat_printf(credential_str, "SE enabled");
+        }
+
         widget_add_button_element(
             widget,
             GuiButtonTypeLeft,
@@ -39,8 +45,6 @@ void picopass_scene_read_card_success_on_enter(void* context) {
             picopass_scene_read_card_success_widget_callback,
             picopass);
 
-        widget_add_string_element(
-            widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
     } else {
         size_t bytesLength = 1 + pacs->record.bitLength / 8;
         string_set_str(credential_str, "");
@@ -55,6 +59,10 @@ void picopass_scene_read_card_success_on_enter(void* context) {
             string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength);
         }
 
+        if(pacs->sio) {
+            string_cat_printf(sio_str, "+SIO");
+        }
+
         widget_add_button_element(
             widget,
             GuiButtonTypeLeft,
@@ -68,20 +76,18 @@ void picopass_scene_read_card_success_on_enter(void* context) {
             "More",
             picopass_scene_read_card_success_widget_callback,
             picopass);
-
-        widget_add_string_element(
-            widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
-        widget_add_string_element(
-            widget,
-            64,
-            32,
-            AlignCenter,
-            AlignCenter,
-            FontSecondary,
-            string_get_cstr(credential_str));
     }
+
+    widget_add_string_element(
+        widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
+    widget_add_string_element(
+        widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(credential_str));
+    widget_add_string_element(
+        widget, 64, 42, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(sio_str));
+
     string_clear(credential_str);
     string_clear(wiegand_str);
+    string_clear(sio_str);
 
     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
 }