Explorar o código

Merge seader from https://github.com/xMasterX/all-the-plugins

# Conflicts:
#	seader/application.fam
#	seader/scenes/seader_scene_config.h
Willy-JL hai 1 ano
pai
achega
2882a34400

+ 2 - 2
seader/application.fam

@@ -11,7 +11,7 @@ App(
         "storage",
         "nfc",
     ],
-    stack_size=7 * 1024,
+    stack_size=5 * 1024,
     order=20,
     sources=[
         "*.c",
@@ -20,7 +20,7 @@ App(
     ],
     fap_icon="icons/logo.png",
     fap_category="NFC",
-    fap_version="2.7",
+    fap_version="2.8",
     fap_author="bettse",
     #    fap_extbuild=(
     #        ExtFile(

+ 180 - 10
seader/sam_api.c

@@ -1,6 +1,7 @@
 
 #include "sam_api.h"
 #include <toolbox/path.h>
+#include <bit_lib/bit_lib.h>
 
 #define TAG "SAMAPI"
 
@@ -728,6 +729,161 @@ void seader_iso14443a_transmit(
     bit_buffer_free(rx_buffer);
 }
 
+/* Assumes this is called in the context of the NFC API callback */
+#define MF_CLASSIC_FWT_FC (60000)
+void seader_mfc_transmit(
+    Seader* seader,
+    MfClassicPoller* mfc_poller,
+    uint8_t* buffer,
+    size_t len,
+    uint16_t timeout,
+    uint8_t format[3]) {
+    UNUSED(timeout);
+
+    furi_assert(seader);
+    furi_assert(buffer);
+    furi_assert(mfc_poller);
+    SeaderWorker* seader_worker = seader->worker;
+    SeaderUartBridge* seader_uart = seader_worker->uart;
+
+    BitBuffer* tx_buffer = bit_buffer_alloc(len);
+    BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
+
+    do {
+        if(format[0] == 0x00 && format[1] == 0xC0 && format[2] == 0x00) {
+            bit_buffer_append_bytes(tx_buffer, buffer, len);
+            MfClassicError error =
+                mf_classic_poller_send_frame(mfc_poller, tx_buffer, rx_buffer, MF_CLASSIC_FWT_FC);
+            if(error != MfClassicErrorNone) {
+                FURI_LOG_W(TAG, "mf_classic_poller_send_frame error %d", error);
+                seader_worker->stage = SeaderPollerEventTypeFail;
+                break;
+            }
+        } else if(
+            (format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x40) ||
+            (format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x24) ||
+            (format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x44)) {
+            memset(display, 0, sizeof(display));
+            for(uint8_t i = 0; i < len; i++) {
+                snprintf(display + (i * 2), sizeof(display), "%02x", buffer[i]);
+            }
+            FURI_LOG_D(TAG, "NFC Send with parity %d: %s", len, display);
+
+            // Only handles message up to 8 data bytes
+            uint8_t tx_parity = 0;
+            uint8_t len_without_parity = len - 1;
+
+            // Don't forget to swap the bits of buffer[8]
+            for(size_t i = 0; i < len; i++) {
+                bit_lib_reverse_bits(buffer + i, 0, 8);
+            }
+
+            // Pull out parity bits
+            for(size_t i = 0; i < len_without_parity; i++) {
+                bool val = bit_lib_get_bit(buffer + i + 1, i);
+                bit_lib_set_bit(&tx_parity, i, val);
+            }
+
+            for(size_t i = 0; i < len_without_parity; i++) {
+                buffer[i] = (buffer[i] << i) | (buffer[i + 1] >> (8 - i));
+            }
+            bit_buffer_append_bytes(tx_buffer, buffer, len_without_parity);
+
+            for(size_t i = 0; i < len_without_parity; i++) {
+                bit_lib_reverse_bits(buffer + i, 0, 8);
+                bit_buffer_set_byte_with_parity(
+                    tx_buffer, i, buffer[i], bit_lib_get_bit(&tx_parity, i));
+            }
+
+            memset(display, 0, sizeof(display));
+            for(uint8_t i = 0; i < bit_buffer_get_size_bytes(tx_buffer); i++) {
+                snprintf(
+                    display + (i * 2), sizeof(display), "%02x", bit_buffer_get_byte(tx_buffer, i));
+            }
+            FURI_LOG_D(
+                TAG,
+                "NFC Send without parity %d: %s [%02x]",
+                bit_buffer_get_size_bytes(tx_buffer),
+                display,
+                tx_parity);
+
+            MfClassicError error = mf_classic_poller_send_custom_parity_frame(
+                mfc_poller, tx_buffer, rx_buffer, MF_CLASSIC_FWT_FC);
+            if(error != MfClassicErrorNone) {
+                FURI_LOG_W(TAG, "mf_classic_poller_send_encrypted_frame error %d", error);
+                seader_worker->stage = SeaderPollerEventTypeFail;
+                break;
+            }
+
+            size_t length = bit_buffer_get_size_bytes(rx_buffer);
+            const uint8_t* rx_parity = bit_buffer_get_parity(rx_buffer);
+
+            memset(display, 0, sizeof(display));
+            for(uint8_t i = 0; i < length; i++) {
+                snprintf(
+                    display + (i * 2), sizeof(display), "%02x", bit_buffer_get_byte(rx_buffer, i));
+            }
+            FURI_LOG_D(
+                TAG, "NFC Response without parity %d: %s [%02x]", length, display, rx_parity[0]);
+
+            uint8_t with_parity[SEADER_POLLER_MAX_BUFFER_SIZE];
+            memset(with_parity, 0, sizeof(with_parity));
+
+            for(size_t i = 0; i < length; i++) {
+                uint8_t b = bit_buffer_get_byte(rx_buffer, i);
+                bit_lib_reverse_bits(&b, 0, 8);
+                bit_buffer_set_byte(rx_buffer, i, b);
+            }
+
+            length = length + (length / 8) + 1;
+
+            uint8_t parts = 1 + length / 9;
+            for(size_t p = 0; p < parts; p++) {
+                uint8_t doffset = p * 9;
+                uint8_t soffset = p * 8;
+
+                for(size_t i = 0; i < 9; i++) {
+                    with_parity[i + doffset] = bit_buffer_get_byte(rx_buffer, i + soffset) >> i;
+                    if(i > 0) {
+                        with_parity[i + doffset] |= bit_buffer_get_byte(rx_buffer, i + soffset - 1)
+                                                    << (9 - i);
+                    }
+
+                    if(i > 0) {
+                        bool val = bit_lib_get_bit(rx_parity, i - 1);
+                        bit_lib_set_bit(with_parity + i, i - 1, val);
+                    }
+                }
+            }
+
+            for(size_t i = 0; i < length; i++) {
+                bit_lib_reverse_bits(with_parity + i, 0, 8);
+            }
+
+            bit_buffer_copy_bytes(rx_buffer, with_parity, length);
+
+            memset(display, 0, sizeof(display));
+            for(uint8_t i = 0; i < length; i++) {
+                snprintf(
+                    display + (i * 2), sizeof(display), "%02x", bit_buffer_get_byte(rx_buffer, i));
+            }
+            FURI_LOG_D(
+                TAG, "NFC Response with parity %d: %s [%02x]", length, display, rx_parity[0]);
+
+        } else {
+            FURI_LOG_W(TAG, "UNHANDLED FORMAT");
+        }
+
+        seader_send_nfc_rx(
+            seader_uart,
+            (uint8_t*)bit_buffer_get_data(rx_buffer),
+            bit_buffer_get_size_bytes(rx_buffer));
+
+    } while(false);
+    bit_buffer_free(tx_buffer);
+    bit_buffer_free(rx_buffer);
+}
+
 void seader_parse_nfc_command_transmit(
     Seader* seader,
     NFCSend_t* nfcSend,
@@ -757,13 +913,23 @@ void seader_parse_nfc_command_transmit(
         seader_iso15693_transmit(
             seader, spc->picopass_poller, nfcSend->data.buf, nfcSend->data.size);
     } else if(frameProtocol == FrameProtocol_nfc) {
-        seader_iso14443a_transmit(
-            seader,
-            spc->iso14443_4a_poller,
-            nfcSend->data.buf,
-            nfcSend->data.size,
-            (uint16_t)timeOut,
-            nfcSend->format->buf);
+        if(spc->iso14443_4a_poller) {
+            seader_iso14443a_transmit(
+                seader,
+                spc->iso14443_4a_poller,
+                nfcSend->data.buf,
+                nfcSend->data.size,
+                (uint16_t)timeOut,
+                nfcSend->format->buf);
+        } else if(spc->mfc_poller) {
+            seader_mfc_transmit(
+                seader,
+                spc->mfc_poller,
+                nfcSend->data.buf,
+                nfcSend->data.size,
+                (uint16_t)timeOut,
+                nfcSend->format->buf);
+        }
     } else {
         FURI_LOG_W(TAG, "unknown frame protocol %lx", frameProtocol);
     }
@@ -911,18 +1077,22 @@ NfcCommand seader_worker_card_detect(
     OCTET_STRING_t atqa_string = {.buf = atqa, .size = 2};
     uint8_t protocol_bytes[] = {0x00, 0x00};
 
-    if(sak == 0 && atqa == NULL) {
+    if(sak == 0 && atqa == NULL) { // picopass
         protocol_bytes[1] = FrameProtocol_iclass;
         OCTET_STRING_fromBuf(
             &cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
         memcpy(credential->diversifier, uid, uid_len);
         credential->diversifier_len = uid_len;
         credential->isDesfire = false;
-    } else {
+    } else if(atqa == 0) { // MFC
+        protocol_bytes[1] = FrameProtocol_nfc;
+        OCTET_STRING_fromBuf(
+            &cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
+        cardDetails->sak = &sak_string;
+    } else { // type 4
         protocol_bytes[1] = FrameProtocol_nfc;
         OCTET_STRING_fromBuf(
             &cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
-
         cardDetails->sak = &sak_string;
         cardDetails->atqa = &atqa_string;
         credential->isDesfire = seader_mf_df_check_card_type(atqa[0], atqa[1], sak);

+ 1 - 0
seader/scenes/seader_scene_config.h

@@ -16,3 +16,4 @@ ADD_SCENE(seader, credential_info, CredentialInfo)
 ADD_SCENE(seader, sam_info, SamInfo)
 ADD_SCENE(seader, virtual_credential, VirtualCredential)
 ADD_SCENE(seader, formats, Formats)
+ADD_SCENE(seader, read_mfc, ReadMfc)

+ 65 - 0
seader/scenes/seader_scene_read_mfc.c

@@ -0,0 +1,65 @@
+#include "../seader_i.h"
+#include <dolphin/dolphin.h>
+
+#define TAG "SceneReadNfc"
+
+void seader_scene_read_mfc_on_enter(void* context) {
+    Seader* seader = context;
+    dolphin_deed(DolphinDeedNfcRead);
+
+    // Setup view
+    Popup* popup = seader->popup;
+    popup_set_header(popup, "Detecting\nMFC\ncard", 68, 30, AlignLeft, AlignTop);
+    popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
+
+    // Start worker
+    view_dispatcher_switch_to_view(seader->view_dispatcher, SeaderViewPopup);
+
+    seader->poller = nfc_poller_alloc(seader->nfc, NfcProtocolMfClassic);
+
+    seader->worker->stage = SeaderPollerEventTypeCardDetect;
+    seader_credential_clear(seader->credential);
+    seader->credential->type = SeaderCredentialTypeMifareClassic;
+
+    FURI_LOG_W(TAG, "Start poller");
+    nfc_poller_start(seader->poller, seader_worker_poller_callback_mfc, seader);
+
+    seader_blink_start(seader);
+}
+
+bool seader_scene_read_mfc_on_event(void* context, SceneManagerEvent event) {
+    Seader* seader = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == SeaderCustomEventWorkerExit) {
+            seader->credential->type = SeaderCredentialTypeMifareClassic;
+            scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
+            consumed = true;
+        } else if(event.event == SeaderCustomEventPollerSuccess) {
+            seader->credential->type = SeaderCredentialTypeMifareClassic;
+            scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
+            consumed = true;
+        }
+    } else if(event.type == SceneManagerEventTypeBack) {
+        scene_manager_search_and_switch_to_previous_scene(
+            seader->scene_manager, SeaderSceneSamPresent);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void seader_scene_read_mfc_on_exit(void* context) {
+    Seader* seader = context;
+
+    if(seader->poller) {
+        nfc_poller_stop(seader->poller);
+        nfc_poller_free(seader->poller);
+    }
+
+    // Clear view
+    popup_reset(seader->popup);
+
+    seader_blink_stop(seader);
+}

+ 12 - 0
seader/scenes/seader_scene_sam_present.c

@@ -2,6 +2,7 @@
 enum SubmenuIndex {
     SubmenuIndexReadPicopass,
     SubmenuIndexRead14a,
+    SubmenuIndexReadMfc,
     SubmenuIndexSaved,
     SubmenuIndexSamInfo,
     SubmenuIndexFwVersion,
@@ -33,6 +34,12 @@ void seader_scene_sam_present_on_update(void* context) {
         SubmenuIndexRead14a,
         seader_scene_sam_present_submenu_callback,
         seader);
+    submenu_add_item(
+        submenu,
+        "Read MFC",
+        SubmenuIndexReadMfc,
+        seader_scene_sam_present_submenu_callback,
+        seader);
     submenu_add_item(
         submenu, "Saved", SubmenuIndexSaved, seader_scene_sam_present_submenu_callback, seader);
 
@@ -75,6 +82,11 @@ bool seader_scene_sam_present_on_event(void* context, SceneManagerEvent event) {
                 seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexRead14a);
             scene_manager_next_scene(seader->scene_manager, SeaderSceneRead14a);
             consumed = true;
+        } else if(event.event == SubmenuIndexReadMfc) {
+            scene_manager_set_scene_state(
+                seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexReadMfc);
+            scene_manager_next_scene(seader->scene_manager, SeaderSceneReadMfc);
+            consumed = true;
         } else if(event.event == SubmenuIndexSamInfo) {
             scene_manager_set_scene_state(
                 seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexSamInfo);

+ 1 - 1
seader/seader_bridge.h

@@ -9,7 +9,7 @@
 #include <furi.h>
 #include <furi_hal.h>
 
-#define SEADER_UART_RX_BUF_SIZE (256)
+#define SEADER_UART_RX_BUF_SIZE (128)
 
 typedef struct {
     uint8_t uart_ch;

+ 1 - 3
seader/seader_i.h

@@ -26,10 +26,7 @@
 #include <input/input.h>
 
 #include <lib/nfc/nfc.h>
-#include <lib/nfc/protocols/iso14443_3a/iso14443_3a.h>
-
 #include <nfc/nfc_poller.h>
-
 #include <nfc/nfc_device.h>
 #include <nfc/helpers/nfc_data_generator.h>
 
@@ -126,6 +123,7 @@ struct Seader {
 
 struct SeaderPollerContainer {
     Iso14443_4aPoller* iso14443_4a_poller;
+    MfClassicPoller* mfc_poller;
     PicopassPoller* picopass_poller;
 };
 

+ 51 - 0
seader/seader_worker.c

@@ -286,6 +286,57 @@ NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void
         } else if(seader_worker->stage == SeaderPollerEventTypeComplete) {
             ret = NfcCommandStop;
         }
+    } else if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeError) {
+        Iso14443_4aPollerEventData* data = iso14443_4a_event->data;
+        Iso14443_4aError error = data->error;
+        FURI_LOG_W(TAG, "Iso14443_4aError %i", error);
+        // I was hoping to catch MFC here, but it seems to be treated the same (None) as no card being present.
+        switch(error) {
+        case Iso14443_4aErrorNone:
+            break;
+        case Iso14443_4aErrorNotPresent:
+            break;
+        case Iso14443_4aErrorProtocol:
+            ret = NfcCommandStop;
+            break;
+        case Iso14443_4aErrorTimeout:
+            break;
+        case Iso14443_4aErrorSendExtra:
+            break;
+        }
+    }
+
+    return ret;
+}
+
+NfcCommand seader_worker_poller_callback_mfc(NfcGenericEvent event, void* context) {
+    furi_assert(event.protocol == NfcProtocolMfClassic);
+    NfcCommand ret = NfcCommandContinue;
+
+    Seader* seader = context;
+    SeaderWorker* seader_worker = seader->worker;
+
+    MfClassicPollerEvent* mfc_event = event.event_data;
+    SeaderPollerContainer spc = {.mfc_poller = event.instance};
+
+    if(mfc_event->type == MfClassicPollerEventTypeSuccess) {
+        if(seader_worker->stage == SeaderPollerEventTypeCardDetect) {
+            const MfClassicData* mfc_data = nfc_poller_get_data(seader->poller);
+            uint8_t sak = iso14443_3a_get_sak(mfc_data->iso14443_3a_data);
+            size_t uid_len = 0;
+            const uint8_t* uid = mf_classic_get_uid(mfc_data, &uid_len);
+            seader_worker_card_detect(seader, sak, NULL, uid, uid_len, NULL, 0);
+            furi_thread_set_current_priority(FuriThreadPriorityLowest);
+            seader_worker->stage = SeaderPollerEventTypeConversation;
+        } else if(seader_worker->stage == SeaderPollerEventTypeConversation) {
+            seader_worker_poller_conversation(seader, &spc);
+        } else if(seader_worker->stage == SeaderPollerEventTypeComplete) {
+            ret = NfcCommandStop;
+        } else if(seader_worker->stage == SeaderPollerEventTypeFail) {
+            ret = NfcCommandStop;
+        }
+    } else if(mfc_event->type == MfClassicPollerEventTypeFail) {
+        ret = NfcCommandStop;
     }
 
     return ret;

+ 2 - 1
seader/seader_worker.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h>
+#include <lib/nfc/protocols/mf_classic/mf_classic_poller.h>
 
 #include "sam_api.h"
 #include "seader_credential.h"
@@ -65,5 +66,5 @@ bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message);
 void seader_worker_send_version(Seader* seader);
 
 NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void* context);
-
+NfcCommand seader_worker_poller_callback_mfc(NfcGenericEvent event, void* context);
 NfcCommand seader_worker_poller_callback_picopass(PicopassPollerEvent event, void* context);