浏览代码

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

Willy-JL 1 年之前
父节点
当前提交
527888be02
共有 49 个文件被更改,包括 649 次插入3530 次删除
  1. 1 1
      nfc_magic/application.fam
  2. 二进制
      nfc_magic/assets/DolphinSuccess_91x55.png
  3. 二进制
      nfc_magic/assets/WarningDolphinFlip_45x42.png
  4. 29 28
      nfc_magic/lib/magic/nfc_magic_scanner.c
  5. 4 1
      nfc_magic/lib/magic/nfc_magic_scanner.h
  6. 0 178
      nfc_magic/lib/magic/protocols/gen2/crypto1.c
  7. 0 45
      nfc_magic/lib/magic/protocols/gen2/crypto1.h
  8. 0 594
      nfc_magic/lib/magic/protocols/gen2/gen2_poller.c
  9. 0 97
      nfc_magic/lib/magic/protocols/gen2/gen2_poller.h
  10. 0 629
      nfc_magic/lib/magic/protocols/gen2/gen2_poller_i.c
  11. 0 139
      nfc_magic/lib/magic/protocols/gen2/gen2_poller_i.h
  12. 97 0
      nfc_magic/lib/magic/protocols/gen4/gen4.c
  13. 101 0
      nfc_magic/lib/magic/protocols/gen4/gen4.h
  14. 156 61
      nfc_magic/lib/magic/protocols/gen4/gen4_poller.c
  15. 6 8
      nfc_magic/lib/magic/protocols/gen4/gen4_poller.h
  16. 59 95
      nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.c
  17. 26 56
      nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h
  18. 2 4
      nfc_magic/lib/magic/protocols/nfc_magic_protocols.c
  19. 0 2
      nfc_magic/lib/magic/protocols/nfc_magic_protocols.h
  20. 6 29
      nfc_magic/nfc_magic_app.c
  21. 3 54
      nfc_magic/nfc_magic_app_i.h
  22. 0 6
      nfc_magic/scenes/nfc_magic_scene_config.h
  23. 1 15
      nfc_magic/scenes/nfc_magic_scene_file_select.c
  24. 0 55
      nfc_magic/scenes/nfc_magic_scene_gen2_menu.c
  25. 0 130
      nfc_magic/scenes/nfc_magic_scene_gen2_write_check.c
  26. 8 3
      nfc_magic/scenes/nfc_magic_scene_gen4_get_info.c
  27. 29 8
      nfc_magic/scenes/nfc_magic_scene_gen4_menu.c
  28. 0 96
      nfc_magic/scenes/nfc_magic_scene_gen4_select_direct_write_block_0_mode.c
  29. 5 9
      nfc_magic/scenes/nfc_magic_scene_gen4_select_shd_mode.c
  30. 1 1
      nfc_magic/scenes/nfc_magic_scene_gen4_set_default_cfg.c
  31. 2 1
      nfc_magic/scenes/nfc_magic_scene_gen4_set_direct_write_block_0_mode.c
  32. 1 1
      nfc_magic/scenes/nfc_magic_scene_gen4_set_shd_mode.c
  33. 7 6
      nfc_magic/scenes/nfc_magic_scene_gen4_show_cfg.c
  34. 28 56
      nfc_magic/scenes/nfc_magic_scene_gen4_show_info.c
  35. 10 5
      nfc_magic/scenes/nfc_magic_scene_key_input.c
  36. 37 18
      nfc_magic/scenes/nfc_magic_scene_magic_info.c
  37. 0 311
      nfc_magic/scenes/nfc_magic_scene_mf_classic_dict_attack.c
  38. 0 65
      nfc_magic/scenes/nfc_magic_scene_mf_classic_menu.c
  39. 0 124
      nfc_magic/scenes/nfc_magic_scene_mf_classic_write_check.c
  40. 1 1
      nfc_magic/scenes/nfc_magic_scene_start.c
  41. 2 2
      nfc_magic/scenes/nfc_magic_scene_success.c
  42. 6 48
      nfc_magic/scenes/nfc_magic_scene_wipe.c
  43. 2 5
      nfc_magic/scenes/nfc_magic_scene_wipe_fail.c
  44. 5 50
      nfc_magic/scenes/nfc_magic_scene_write.c
  45. 14 6
      nfc_magic/scenes/nfc_magic_scene_write_fail.c
  46. 0 245
      nfc_magic/views/dict_attack.c
  47. 0 50
      nfc_magic/views/dict_attack.h
  48. 0 160
      nfc_magic/views/write_problems.c
  49. 0 32
      nfc_magic/views/write_problems.h

+ 1 - 1
nfc_magic/application.fam

@@ -1,6 +1,6 @@
 App(
     appid="nfc_magic",
-    name="Nfc Magic",
+    name="NFC Magic",
     apptype=FlipperAppType.EXTERNAL,
     targets=["f7"],
     entry_point="nfc_magic_app",

二进制
nfc_magic/assets/DolphinSuccess_91x55.png


二进制
nfc_magic/assets/WarningDolphinFlip_45x42.png


+ 29 - 28
nfc_magic/lib/magic/nfc_magic_scanner.c

@@ -1,7 +1,8 @@
 #include "nfc_magic_scanner.h"
 
+#include "core/check.h"
 #include "protocols/gen1a/gen1a_poller.h"
-#include "protocols/gen2/gen2_poller.h"
+#include "protocols/gen4/gen4.h"
 #include "protocols/gen4/gen4_poller.h"
 #include <nfc/nfc_poller.h>
 
@@ -18,7 +19,8 @@ struct NfcMagicScanner {
     NfcMagicScannerSessionState session_state;
     NfcMagicProtocol current_protocol;
 
-    uint32_t gen4_password;
+    Gen4Password gen4_password;
+    Gen4* gen4_data;
     bool magic_protocol_detected;
 
     NfcMagicScannerCallback callback;
@@ -43,6 +45,7 @@ NfcMagicScanner* nfc_magic_scanner_alloc(Nfc* nfc) {
 
     NfcMagicScanner* instance = malloc(sizeof(NfcMagicScanner));
     instance->nfc = nfc;
+    instance->gen4_data = gen4_alloc();
 
     return instance;
 }
@@ -50,10 +53,11 @@ NfcMagicScanner* nfc_magic_scanner_alloc(Nfc* nfc) {
 void nfc_magic_scanner_free(NfcMagicScanner* instance) {
     furi_assert(instance);
 
+    gen4_free(instance->gen4_data);
     free(instance);
 }
 
-void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, uint32_t password) {
+void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, Gen4Password password) {
     furi_assert(instance);
 
     instance->gen4_password = password;
@@ -66,33 +70,24 @@ static int32_t nfc_magic_scanner_worker(void* context) {
     furi_assert(instance->session_state == NfcMagicScannerSessionStateActive);
 
     while(instance->session_state == NfcMagicScannerSessionStateActive) {
-        do {
-            if(instance->current_protocol == NfcMagicProtocolGen1) {
-                instance->magic_protocol_detected = gen1a_poller_detect(instance->nfc);
-                if(instance->magic_protocol_detected) {
-                    break;
-                }
-            } else if(instance->current_protocol == NfcMagicProtocolGen4) {
-                Gen4PollerError error = gen4_poller_detect(instance->nfc, instance->gen4_password);
+        if(instance->current_protocol == NfcMagicProtocolGen1) {
+            instance->magic_protocol_detected = gen1a_poller_detect(instance->nfc);
+        } else if(instance->current_protocol == NfcMagicProtocolGen4) {
+            gen4_reset(instance->gen4_data);
+            Gen4 gen4_data;
+            Gen4PollerError error =
+                gen4_poller_detect(instance->nfc, instance->gen4_password, &gen4_data);
+            if(error == Gen4PollerErrorProtocol) {
+                NfcMagicScannerEvent event = {
+                    .type = NfcMagicScannerEventTypeDetectedNotMagic,
+                };
+                instance->callback(event, instance->context);
+                break;
+            } else {
                 instance->magic_protocol_detected = (error == Gen4PollerErrorNone);
-                if(instance->magic_protocol_detected) {
-                    break;
-                }
-            } else if(instance->current_protocol == NfcMagicProtocolGen2) {
-                Gen2PollerError error = gen2_poller_detect(instance->nfc);
-                instance->magic_protocol_detected = (error == Gen2PollerErrorNone);
-                if(instance->magic_protocol_detected) {
-                    break;
-                }
-            } else if(instance->current_protocol == NfcMagicProtocolClassic) {
-                NfcPoller* poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic);
-                instance->magic_protocol_detected = nfc_poller_detect(poller);
-                nfc_poller_free(poller);
-                if(instance->magic_protocol_detected) {
-                    break;
-                }
+                gen4_copy(instance->gen4_data, &gen4_data);
             }
-        } while(false);
+        }
 
         if(instance->magic_protocol_detected) {
             NfcMagicScannerEvent event = {
@@ -162,3 +157,9 @@ void nfc_magic_scanner_stop(NfcMagicScanner* instance) {
     instance->callback = NULL;
     instance->context = NULL;
 }
+
+Gen4* nfc_magic_scanner_get_gen4_data(NfcMagicScanner* instance) {
+    furi_assert(instance);
+
+    return instance->gen4_data;
+}

+ 4 - 1
nfc_magic/lib/magic/nfc_magic_scanner.h

@@ -1,5 +1,6 @@
 #pragma once
 
+#include "protocols/gen4/gen4.h"
 #include <nfc/nfc.h>
 #include "protocols/nfc_magic_protocols.h"
 
@@ -30,7 +31,7 @@ NfcMagicScanner* nfc_magic_scanner_alloc(Nfc* nfc);
 
 void nfc_magic_scanner_free(NfcMagicScanner* instance);
 
-void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, uint32_t password);
+void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, Gen4Password password);
 
 void nfc_magic_scanner_start(
     NfcMagicScanner* instance,
@@ -39,6 +40,8 @@ void nfc_magic_scanner_start(
 
 void nfc_magic_scanner_stop(NfcMagicScanner* instance);
 
+Gen4* nfc_magic_scanner_get_gen4_data(NfcMagicScanner* instance);
+
 #ifdef __cplusplus
 }
 #endif

+ 0 - 178
nfc_magic/lib/magic/protocols/gen2/crypto1.c

@@ -1,178 +0,0 @@
-#include "crypto1.h"
-
-#include <nfc/helpers/nfc_util.h>
-#include <bit_lib/bit_lib.h>
-#include <furi.h>
-
-// Algorithm from https://github.com/RfidResearchGroup/proxmark3.git
-
-#define SWAPENDIAN(x) \
-    ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16)
-#define LF_POLY_ODD (0x29CE5C)
-#define LF_POLY_EVEN (0x870804)
-
-#define BEBIT(x, n) FURI_BIT(x, (n) ^ 24)
-
-Crypto1* crypto1_alloc() {
-    Crypto1* instance = malloc(sizeof(Crypto1));
-
-    return instance;
-}
-
-void crypto1_free(Crypto1* instance) {
-    furi_assert(instance);
-
-    free(instance);
-}
-
-void crypto1_reset(Crypto1* crypto1) {
-    furi_assert(crypto1);
-    crypto1->even = 0;
-    crypto1->odd = 0;
-}
-
-void crypto1_init(Crypto1* crypto1, uint64_t key) {
-    furi_assert(crypto1);
-    crypto1->even = 0;
-    crypto1->odd = 0;
-    for(int8_t i = 47; i > 0; i -= 2) {
-        crypto1->odd = crypto1->odd << 1 | FURI_BIT(key, (i - 1) ^ 7);
-        crypto1->even = crypto1->even << 1 | FURI_BIT(key, i ^ 7);
-    }
-}
-
-static uint32_t crypto1_filter(uint32_t in) {
-    uint32_t out = 0;
-    out = 0xf22c0 >> (in & 0xf) & 16;
-    out |= 0x6c9c0 >> (in >> 4 & 0xf) & 8;
-    out |= 0x3c8b0 >> (in >> 8 & 0xf) & 4;
-    out |= 0x1e458 >> (in >> 12 & 0xf) & 2;
-    out |= 0x0d938 >> (in >> 16 & 0xf) & 1;
-    return FURI_BIT(0xEC57E80A, out);
-}
-
-uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) {
-    furi_assert(crypto1);
-    uint8_t out = crypto1_filter(crypto1->odd);
-    uint32_t feed = out & (!!is_encrypted);
-    feed ^= !!in;
-    feed ^= LF_POLY_ODD & crypto1->odd;
-    feed ^= LF_POLY_EVEN & crypto1->even;
-    crypto1->even = crypto1->even << 1 | (nfc_util_even_parity32(feed));
-
-    FURI_SWAP(crypto1->odd, crypto1->even);
-    return out;
-}
-
-uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) {
-    furi_assert(crypto1);
-    uint8_t out = 0;
-    for(uint8_t i = 0; i < 8; i++) {
-        out |= crypto1_bit(crypto1, FURI_BIT(in, i), is_encrypted) << i;
-    }
-    return out;
-}
-
-uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) {
-    furi_assert(crypto1);
-    uint32_t out = 0;
-    for(uint8_t i = 0; i < 32; i++) {
-        out |= (uint32_t)crypto1_bit(crypto1, BEBIT(in, i), is_encrypted) << (24 ^ i);
-    }
-    return out;
-}
-
-uint32_t prng_successor(uint32_t x, uint32_t n) {
-    SWAPENDIAN(x);
-    while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
-
-    return SWAPENDIAN(x);
-}
-
-void crypto1_decrypt(Crypto1* crypto, const BitBuffer* buff, BitBuffer* out) {
-    furi_assert(crypto);
-    furi_assert(buff);
-    furi_assert(out);
-
-    size_t bits = bit_buffer_get_size(buff);
-    bit_buffer_set_size(out, bits);
-    const uint8_t* encrypted_data = bit_buffer_get_data(buff);
-    if(bits < 8) {
-        uint8_t decrypted_byte = 0;
-        uint8_t encrypted_byte = encrypted_data[0];
-        decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 0)) << 0;
-        decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 1)) << 1;
-        decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 2)) << 2;
-        decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 3)) << 3;
-        bit_buffer_set_byte(out, 0, decrypted_byte);
-    } else {
-        for(size_t i = 0; i < bits / 8; i++) {
-            uint8_t decrypted_byte = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i];
-            bit_buffer_set_byte(out, i, decrypted_byte);
-        }
-    }
-}
-
-void crypto1_encrypt(Crypto1* crypto, uint8_t* keystream, const BitBuffer* buff, BitBuffer* out) {
-    furi_assert(crypto);
-    furi_assert(buff);
-    furi_assert(out);
-
-    size_t bits = bit_buffer_get_size(buff);
-    bit_buffer_set_size(out, bits);
-    const uint8_t* plain_data = bit_buffer_get_data(buff);
-    if(bits < 8) {
-        uint8_t encrypted_byte = 0;
-        for(size_t i = 0; i < bits; i++) {
-            encrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i;
-        }
-        bit_buffer_set_byte(out, 0, encrypted_byte);
-    } else {
-        for(size_t i = 0; i < bits / 8; i++) {
-            uint8_t encrypted_byte = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^
-                                     plain_data[i];
-            bool parity_bit =
-                ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01);
-            bit_buffer_set_byte_with_parity(out, i, encrypted_byte, parity_bit);
-        }
-    }
-}
-
-void crypto1_encrypt_reader_nonce(
-    Crypto1* crypto,
-    uint64_t key,
-    uint32_t cuid,
-    uint8_t* nt,
-    uint8_t* nr,
-    BitBuffer* out,
-    bool is_nested) {
-    furi_assert(crypto);
-    furi_assert(nt);
-    furi_assert(nr);
-    furi_assert(out);
-
-    bit_buffer_set_size_bytes(out, 8);
-    uint32_t nt_num = bit_lib_bytes_to_num_be(nt, sizeof(uint32_t));
-
-    crypto1_init(crypto, key);
-    if(is_nested) {
-        nt_num = crypto1_word(crypto, nt_num ^ cuid, 1) ^ nt_num;
-    } else {
-        crypto1_word(crypto, nt_num ^ cuid, 0);
-    }
-
-    for(size_t i = 0; i < 4; i++) {
-        uint8_t byte = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
-        bool parity_bit = ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01);
-        bit_buffer_set_byte_with_parity(out, i, byte, parity_bit);
-        nr[i] = byte;
-    }
-
-    nt_num = prng_successor(nt_num, 32);
-    for(size_t i = 4; i < 8; i++) {
-        nt_num = prng_successor(nt_num, 8);
-        uint8_t byte = crypto1_byte(crypto, 0, 0) ^ (uint8_t)(nt_num);
-        bool parity_bit = ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt_num)) & 0x01);
-        bit_buffer_set_byte_with_parity(out, i, byte, parity_bit);
-    }
-}

+ 0 - 45
nfc_magic/lib/magic/protocols/gen2/crypto1.h

@@ -1,45 +0,0 @@
-#pragma once
-
-#include <toolbox/bit_buffer.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
-    uint32_t odd;
-    uint32_t even;
-} Crypto1;
-
-Crypto1* crypto1_alloc();
-
-void crypto1_free(Crypto1* instance);
-
-void crypto1_reset(Crypto1* crypto1);
-
-void crypto1_init(Crypto1* crypto1, uint64_t key);
-
-uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted);
-
-uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted);
-
-uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted);
-
-void crypto1_decrypt(Crypto1* crypto, const BitBuffer* buff, BitBuffer* out);
-
-void crypto1_encrypt(Crypto1* crypto, uint8_t* keystream, const BitBuffer* buff, BitBuffer* out);
-
-void crypto1_encrypt_reader_nonce(
-    Crypto1* crypto,
-    uint64_t key,
-    uint32_t cuid,
-    uint8_t* nt,
-    uint8_t* nr,
-    BitBuffer* out,
-    bool is_nested);
-
-uint32_t prng_successor(uint32_t x, uint32_t n);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 594
nfc_magic/lib/magic/protocols/gen2/gen2_poller.c

@@ -1,594 +0,0 @@
-#include "gen2_poller_i.h"
-#include <nfc/helpers/nfc_data_generator.h>
-
-#include <furi/furi.h>
-
-#define GEN2_POLLER_THREAD_FLAG_DETECTED (1U << 0)
-
-#define TAG "GEN2"
-
-typedef NfcCommand (*Gen2PollerStateHandler)(Gen2Poller* instance);
-
-typedef struct {
-    NfcPoller* poller;
-    BitBuffer* tx_buffer;
-    BitBuffer* rx_buffer;
-    FuriThreadId thread_id;
-    bool detected;
-    Gen2PollerError error;
-} Gen2PollerDetectContext;
-
-// Array of known Gen2 ATS responses
-// 0978009102DABC1910F005 - flavour 2
-// 0978009102DABC1910F005 - flavour 4
-// 0D780071028849A13020150608563D - flavour 6
-// Other flavours can't be detected other than by just trying to write to block 0
-const uint8_t GEN2_ATS[3][16] = {
-    {0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0xF0, 0x05},
-    {0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0xF0, 0x05},
-    {0x0D, 0x78, 0x00, 0x71, 0x02, 0x88, 0x49, 0xA1, 0x30, 0x20, 0x15, 0x06, 0x08, 0x56, 0x3D}};
-
-static MfClassicBlock gen2_poller_default_block_0 = {
-    .data =
-        {0x00,
-         0x01,
-         0x02,
-         0x03,
-         0x00, // BCC - IMPORTANT
-         0x08, // SAK
-         0x04, // ATQA0
-         0x00, // ATQA1
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00},
-};
-
-static MfClassicBlock gen2_poller_default_empty_block = {
-    .data =
-        {0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00,
-         0x00},
-};
-
-static MfClassicBlock gen2_poller_default_sector_trailer_block = {
-    .data =
-        {0xFF,
-         0xFF,
-         0xFF,
-         0xFF,
-         0xFF,
-         0xFF,
-         0xFF,
-         0x07,
-         0x80,
-         0x69,
-         0xFF,
-         0xFF,
-         0xFF,
-         0xFF,
-         0xFF,
-         0xFF},
-};
-
-char* gen2_problem_strings[] = {
-    "UID may be non-\nrewritable. Check data after writing",
-    "No data in selected file",
-    "Some sectors are locked",
-    "Can't find keys to some sectors",
-    "The selected file is incomplete",
-};
-
-Gen2Poller* gen2_poller_alloc(Nfc* nfc) {
-    Gen2Poller* instance = malloc(sizeof(Gen2Poller));
-    instance->poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a);
-    instance->data = mf_classic_alloc();
-    instance->crypto = crypto1_alloc();
-    instance->tx_plain_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
-    instance->tx_encrypted_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
-    instance->rx_plain_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
-    instance->rx_encrypted_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
-    instance->card_state = Gen2CardStateLost;
-
-    instance->gen2_event.data = &instance->gen2_event_data;
-
-    instance->mode_ctx.write_ctx.mfc_data_source = malloc(sizeof(MfClassicData));
-    instance->mode_ctx.write_ctx.mfc_data_target = malloc(sizeof(MfClassicData));
-
-    instance->mode_ctx.write_ctx.need_halt_before_write = true;
-
-    return instance;
-}
-
-void gen2_poller_free(Gen2Poller* instance) {
-    furi_assert(instance);
-    furi_assert(instance->data);
-    furi_assert(instance->crypto);
-    furi_assert(instance->tx_plain_buffer);
-    furi_assert(instance->rx_plain_buffer);
-    furi_assert(instance->tx_encrypted_buffer);
-    furi_assert(instance->rx_encrypted_buffer);
-
-    nfc_poller_free(instance->poller);
-    mf_classic_free(instance->data);
-    crypto1_free(instance->crypto);
-    bit_buffer_free(instance->tx_plain_buffer);
-    bit_buffer_free(instance->rx_plain_buffer);
-    bit_buffer_free(instance->tx_encrypted_buffer);
-    bit_buffer_free(instance->rx_encrypted_buffer);
-
-    free(instance->mode_ctx.write_ctx.mfc_data_source);
-    free(instance->mode_ctx.write_ctx.mfc_data_target);
-
-    free(instance);
-}
-
-NfcCommand gen2_poller_detect_callback(NfcGenericEvent event, void* context) {
-    furi_assert(context);
-    furi_assert(event.protocol == NfcProtocolIso14443_3a);
-    furi_assert(event.event_data);
-    furi_assert(event.instance);
-
-    NfcCommand command = NfcCommandStop;
-    Gen2PollerDetectContext* detect_ctx = context;
-    Iso14443_3aPoller* iso3_poller = event.instance;
-    Iso14443_3aPollerEvent* iso3_event = event.event_data;
-    detect_ctx->error = Gen2PollerErrorTimeout;
-
-    bit_buffer_reset(detect_ctx->tx_buffer);
-    bit_buffer_append_byte(detect_ctx->tx_buffer, GEN2_CMD_READ_ATS);
-    bit_buffer_append_byte(detect_ctx->tx_buffer, GEN2_FSDI_256 << 4);
-
-    if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
-        do {
-            const Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standard_frame(
-                iso3_poller, detect_ctx->tx_buffer, detect_ctx->rx_buffer, GEN2_POLLER_MAX_FWT);
-
-            if(iso14443_3a_error != Iso14443_3aErrorNone &&
-               iso14443_3a_error != Iso14443_3aErrorWrongCrc) {
-                FURI_LOG_E(TAG, "ATS request failed");
-                detect_ctx->error = Gen2PollerErrorProtocol;
-                break;
-
-            } else {
-                FURI_LOG_D(TAG, "ATS request succeeded:");
-                // Check against known ATS responses
-                for(size_t i = 0; i < COUNT_OF(GEN2_ATS); i++) {
-                    if(memcmp(
-                           bit_buffer_get_data(detect_ctx->rx_buffer),
-                           GEN2_ATS[i],
-                           sizeof(GEN2_ATS[i])) == 0) {
-                        detect_ctx->error = Gen2PollerErrorNone;
-                        break;
-                    }
-                }
-            }
-        } while(false);
-    } else if(iso3_event->type == Iso14443_3aPollerEventTypeError) {
-        detect_ctx->error = Gen2PollerErrorTimeout;
-    }
-    furi_thread_flags_set(detect_ctx->thread_id, GEN2_POLLER_THREAD_FLAG_DETECTED);
-
-    return command;
-}
-
-Gen2PollerError gen2_poller_detect(Nfc* nfc) {
-    furi_assert(nfc);
-
-    Gen2PollerDetectContext detect_ctx = {
-        .poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a),
-        .tx_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE),
-        .rx_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE),
-        .thread_id = furi_thread_get_current_id(),
-        .detected = false,
-        .error = Gen2PollerErrorNone,
-    };
-
-    nfc_poller_start(detect_ctx.poller, gen2_poller_detect_callback, &detect_ctx);
-    uint32_t flags =
-        furi_thread_flags_wait(GEN2_POLLER_THREAD_FLAG_DETECTED, FuriFlagWaitAny, FuriWaitForever);
-    if(flags & GEN2_POLLER_THREAD_FLAG_DETECTED) {
-        furi_thread_flags_clear(GEN2_POLLER_THREAD_FLAG_DETECTED);
-    }
-    nfc_poller_stop(detect_ctx.poller);
-
-    bit_buffer_free(detect_ctx.tx_buffer);
-    bit_buffer_free(detect_ctx.rx_buffer);
-    nfc_poller_free(detect_ctx.poller);
-
-    return detect_ctx.error;
-}
-
-NfcCommand gen2_poller_idle_handler(Gen2Poller* instance) {
-    furi_assert(instance);
-
-    NfcCommand command = NfcCommandContinue;
-
-    instance->mode_ctx.write_ctx.current_block = 0;
-    instance->gen2_event.type = Gen2PollerEventTypeDetected;
-    command = instance->callback(instance->gen2_event, instance->context);
-    instance->state = Gen2PollerStateRequestMode;
-
-    return command;
-}
-
-NfcCommand gen2_poller_request_mode_handler(Gen2Poller* instance) {
-    furi_assert(instance);
-
-    NfcCommand command = NfcCommandContinue;
-
-    instance->gen2_event.type = Gen2PollerEventTypeRequestMode;
-    command = instance->callback(instance->gen2_event, instance->context);
-    instance->mode = instance->gen2_event_data.poller_mode.mode;
-    if(instance->gen2_event_data.poller_mode.mode == Gen2PollerModeWipe) {
-        instance->state = Gen2PollerStateWriteTargetDataRequest;
-    } else {
-        instance->state = Gen2PollerStateWriteSourceDataRequest;
-    }
-
-    return command;
-}
-
-NfcCommand gen2_poller_write_source_data_request_handler(Gen2Poller* instance) {
-    NfcCommand command = NfcCommandContinue;
-
-    instance->gen2_event.type = Gen2PollerEventTypeRequestDataToWrite;
-    command = instance->callback(instance->gen2_event, instance->context);
-    memcpy(
-        instance->mode_ctx.write_ctx.mfc_data_source,
-        instance->gen2_event_data.data_to_write.mfc_data,
-        sizeof(MfClassicData));
-    instance->state = Gen2PollerStateWriteTargetDataRequest;
-
-    return command;
-}
-
-NfcCommand gen2_poller_write_target_data_request_handler(Gen2Poller* instance) {
-    NfcCommand command = NfcCommandContinue;
-
-    instance->gen2_event.type = Gen2PollerEventTypeRequestTargetData;
-    command = instance->callback(instance->gen2_event, instance->context);
-    memcpy(
-        instance->mode_ctx.write_ctx.mfc_data_target,
-        instance->gen2_event_data.target_data.mfc_data,
-        sizeof(MfClassicData));
-    if(instance->mode == Gen2PollerModeWipe) {
-        instance->state = Gen2PollerStateWipe;
-    } else {
-        instance->state = Gen2PollerStateWrite;
-    }
-
-    return command;
-}
-
-Gen2PollerError gen2_poller_write_block_handler(
-    Gen2Poller* instance,
-    uint8_t block_num,
-    MfClassicBlock* block) {
-    furi_assert(instance);
-
-    Gen2PollerError error = Gen2PollerErrorNone;
-    Gen2PollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx;
-    MfClassicKey auth_key = write_ctx->auth_key;
-
-    do {
-        // Compare the target and source data
-        if(memcmp(block->data, write_ctx->mfc_data_target->block[block_num].data, 16) == 0) {
-            FURI_LOG_D(TAG, "Block %d is the same, skipping", block_num);
-            break;
-        }
-
-        // Reauth if necessary
-        if(write_ctx->need_halt_before_write) {
-            FURI_LOG_D(TAG, "Auth before writing block %d", write_ctx->current_block);
-            error = gen2_poller_auth(
-                instance, write_ctx->current_block, &auth_key, write_ctx->write_key, NULL);
-            if(error != Gen2PollerErrorNone) {
-                FURI_LOG_D(
-                    TAG, "Failed to auth to block %d for writing", write_ctx->current_block);
-                break;
-            }
-        }
-
-        // Write the block
-        error = gen2_poller_write_block(instance, write_ctx->current_block, block);
-        if(error != Gen2PollerErrorNone) {
-            FURI_LOG_D(TAG, "Failed to write block %d", write_ctx->current_block);
-            break;
-        }
-    } while(false);
-    FURI_LOG_D(TAG, "Block %d finished, halting", write_ctx->current_block);
-    gen2_poller_halt(instance);
-    return error;
-}
-
-NfcCommand gen2_poller_wipe_handler(Gen2Poller* instance) {
-    NfcCommand command = NfcCommandContinue;
-    Gen2PollerError error = Gen2PollerErrorNone;
-    Gen2PollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx;
-    uint8_t block_num = write_ctx->current_block;
-
-    do {
-        // Check whether the ACs for that block are known in target data
-        if(!mf_classic_is_block_read(
-               write_ctx->mfc_data_target,
-               mf_classic_get_sector_trailer_num_by_block(block_num))) {
-            FURI_LOG_E(TAG, "Sector trailer for block %d not present in target data", block_num);
-            break;
-        }
-
-        // Check whether ACs need to be reset and whether they can be reset
-        if(!gen2_poller_can_write_block(write_ctx->mfc_data_target, block_num)) {
-            if(!gen2_can_reset_access_conditions(write_ctx->mfc_data_target, block_num)) {
-                FURI_LOG_E(TAG, "Block %d cannot be written", block_num);
-                break;
-            } else {
-                FURI_LOG_D(TAG, "Resetting ACs for block %d", block_num);
-                // Generate a block with old keys and default ACs (0xFF, 0x07, 0x80)
-                MfClassicBlock block;
-                memset(&block, 0, sizeof(block));
-                memcpy(block.data, write_ctx->mfc_data_target->block[block_num].data, 16);
-                memcpy(block.data + 6, "\xFF\x07\x80", 3);
-
-                error = gen2_poller_write_block_handler(instance, block_num, &block);
-                if(error != Gen2PollerErrorNone) {
-                    FURI_LOG_E(TAG, "Failed to reset ACs for block %d", block_num);
-                    break;
-                } else {
-                    FURI_LOG_D(TAG, "ACs for block %d reset", block_num);
-                    memcpy(write_ctx->mfc_data_target->block[block_num].data, block.data, 16);
-                }
-            }
-        }
-
-        // Figure out which key to use for writing
-        write_ctx->write_key =
-            gen2_poller_get_key_type_to_write(write_ctx->mfc_data_target, block_num);
-
-        // Get the key to use for writing from the target data
-        MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(
-            write_ctx->mfc_data_target, mf_classic_get_sector_by_block(block_num));
-        if(write_ctx->write_key == MfClassicKeyTypeA) {
-            write_ctx->auth_key = sec_tr->key_a;
-        } else {
-            write_ctx->auth_key = sec_tr->key_b;
-        }
-
-        // Write the default block depending on the block type
-        if(block_num == 0) {
-            error =
-                gen2_poller_write_block_handler(instance, block_num, &gen2_poller_default_block_0);
-        } else if(mf_classic_is_sector_trailer(block_num)) {
-            error = gen2_poller_write_block_handler(
-                instance, block_num, &gen2_poller_default_sector_trailer_block);
-        } else {
-            error = gen2_poller_write_block_handler(
-                instance, block_num, &gen2_poller_default_empty_block);
-        }
-        if(error != Gen2PollerErrorNone) {
-            FURI_LOG_E(TAG, "Couldn't write block %d", block_num);
-        }
-    } while(false);
-
-    write_ctx->current_block++;
-
-    if(error != Gen2PollerErrorNone) {
-        FURI_LOG_D(TAG, "Error occurred: %d", error);
-    }
-
-    if(write_ctx->current_block ==
-       mf_classic_get_total_block_num(write_ctx->mfc_data_target->type)) {
-        instance->state = Gen2PollerStateSuccess;
-    }
-
-    return command;
-}
-
-NfcCommand gen2_poller_write_handler(Gen2Poller* instance) {
-    NfcCommand command = NfcCommandContinue;
-    Gen2PollerError error = Gen2PollerErrorNone;
-    Gen2PollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx;
-    uint8_t block_num = write_ctx->current_block;
-
-    do {
-        // Check whether the block is present in the source data
-        if(!mf_classic_is_block_read(write_ctx->mfc_data_source, block_num)) {
-            // FURI_LOG_E(TAG, "Block %d not present in source data", block_num);
-            break;
-        }
-
-        // Check whether the ACs for that block are known in target data
-        if(!mf_classic_is_block_read(
-               write_ctx->mfc_data_target,
-               mf_classic_get_sector_trailer_num_by_block(block_num))) {
-            FURI_LOG_E(TAG, "Sector trailer for block %d not present in target data", block_num);
-            break;
-        }
-
-        // Check whether ACs need to be reset and whether they can be reset
-        if(!gen2_poller_can_write_block(write_ctx->mfc_data_target, block_num)) {
-            if(!gen2_can_reset_access_conditions(write_ctx->mfc_data_target, block_num)) {
-                FURI_LOG_E(TAG, "Block %d cannot be written", block_num);
-                break;
-            } else {
-                FURI_LOG_D(TAG, "Resetting ACs for block %d", block_num);
-                // Generate a block with old keys and default ACs (0xFF, 0x07, 0x80)
-                MfClassicBlock block;
-                memset(&block, 0, sizeof(block));
-                memcpy(block.data, write_ctx->mfc_data_target->block[block_num].data, 16);
-                memcpy(block.data + 6, "\xFF\x07\x80", 3);
-
-                error = gen2_poller_write_block_handler(instance, block_num, &block);
-                if(error != Gen2PollerErrorNone) {
-                    FURI_LOG_E(TAG, "Failed to reset ACs for block %d", block_num);
-                    break;
-                } else {
-                    FURI_LOG_D(TAG, "ACs for block %d reset", block_num);
-                    memcpy(write_ctx->mfc_data_target->block[block_num].data, block.data, 16);
-                }
-            }
-        }
-
-        // Figure out which key to use for writing
-        write_ctx->write_key =
-            gen2_poller_get_key_type_to_write(write_ctx->mfc_data_target, block_num);
-
-        // Get the key to use for writing from the target data
-        MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(
-            write_ctx->mfc_data_target, mf_classic_get_sector_by_block(block_num));
-        if(write_ctx->write_key == MfClassicKeyTypeA) {
-            write_ctx->auth_key = sec_tr->key_a;
-        } else {
-            write_ctx->auth_key = sec_tr->key_b;
-        }
-
-        // Write the block
-        error = gen2_poller_write_block_handler(
-            instance, block_num, &write_ctx->mfc_data_source->block[block_num]);
-        if(error != Gen2PollerErrorNone) {
-            FURI_LOG_E(TAG, "Couldn't write block %d", block_num);
-        }
-    } while(false);
-    write_ctx->current_block++;
-
-    if(error != Gen2PollerErrorNone) {
-        FURI_LOG_D(TAG, "Error occurred: %d", error);
-    } else if(
-        write_ctx->current_block ==
-        mf_classic_get_total_block_num(write_ctx->mfc_data_source->type)) {
-        instance->state = Gen2PollerStateSuccess;
-    }
-
-    return command;
-}
-
-NfcCommand gen2_poller_success_handler(Gen2Poller* instance) {
-    furi_assert(instance);
-
-    NfcCommand command = NfcCommandContinue;
-
-    instance->gen2_event.type = Gen2PollerEventTypeSuccess;
-    command = instance->callback(instance->gen2_event, instance->context);
-    instance->state = Gen2PollerStateIdle;
-
-    return command;
-}
-
-NfcCommand gen2_poller_fail_handler(Gen2Poller* instance) {
-    furi_assert(instance);
-
-    NfcCommand command = NfcCommandContinue;
-
-    instance->gen2_event.type = Gen2PollerEventTypeFail;
-    command = instance->callback(instance->gen2_event, instance->context);
-    instance->state = Gen2PollerStateIdle;
-
-    return command;
-}
-
-static const Gen2PollerStateHandler gen2_poller_state_handlers[Gen2PollerStateNum] = {
-    [Gen2PollerStateIdle] = gen2_poller_idle_handler,
-    [Gen2PollerStateRequestMode] = gen2_poller_request_mode_handler,
-    [Gen2PollerStateWipe] = gen2_poller_wipe_handler,
-    [Gen2PollerStateWriteSourceDataRequest] = gen2_poller_write_source_data_request_handler,
-    [Gen2PollerStateWriteTargetDataRequest] = gen2_poller_write_target_data_request_handler,
-    [Gen2PollerStateWrite] = gen2_poller_write_handler,
-    [Gen2PollerStateSuccess] = gen2_poller_success_handler,
-    [Gen2PollerStateFail] = gen2_poller_fail_handler,
-};
-
-NfcCommand gen2_poller_callback(NfcGenericEvent event, void* context) {
-    furi_assert(context);
-    furi_assert(event.protocol == NfcProtocolIso14443_3a);
-    furi_assert(event.event_data);
-    furi_assert(event.instance);
-
-    NfcCommand command = NfcCommandContinue;
-    Gen2Poller* instance = context;
-    instance->iso3_poller = event.instance;
-    Iso14443_3aPollerEvent* iso3_event = event.event_data;
-
-    if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
-        command = gen2_poller_state_handlers[instance->state](instance);
-    }
-
-    return command;
-}
-
-void gen2_poller_start(Gen2Poller* instance, Gen2PollerCallback callback, void* context) {
-    furi_assert(instance);
-    furi_assert(callback);
-
-    instance->callback = callback;
-    instance->context = context;
-
-    nfc_poller_start(instance->poller, gen2_poller_callback, instance);
-    return;
-}
-
-void gen2_poller_stop(Gen2Poller* instance) {
-    furi_assert(instance);
-
-    FURI_LOG_D(TAG, "Stopping Gen2 poller");
-    nfc_poller_stop(instance->poller);
-    return;
-}
-
-Gen2PollerWriteProblems gen2_poller_check_target_problems(NfcDevice* target_dev) {
-    furi_assert(target_dev);
-
-    Gen2PollerWriteProblems problems = {0};
-    const MfClassicData* mfc_data = nfc_device_get_data(target_dev, NfcProtocolMfClassic);
-
-    if(mfc_data) {
-        uint16_t total_block_num = mf_classic_get_total_block_num(mfc_data->type);
-        for(uint16_t i = 0; i < total_block_num; i++) {
-            if(mf_classic_is_sector_trailer(i)) {
-                problems.all_problems |=
-                    gen2_poller_can_write_sector_trailer(mfc_data, i).all_problems;
-            } else {
-                problems.all_problems |=
-                    gen2_poller_can_write_data_block(mfc_data, i).all_problems;
-            }
-        }
-    } else {
-        problems.no_data = true;
-    }
-
-    return problems;
-}
-
-Gen2PollerWriteProblems gen2_poller_check_source_problems(NfcDevice* source_dev) {
-    furi_assert(source_dev);
-
-    Gen2PollerWriteProblems problems = {0};
-    const MfClassicData* mfc_data = nfc_device_get_data(source_dev, NfcProtocolMfClassic);
-
-    if(mfc_data) {
-        uint16_t total_block_num = mf_classic_get_total_block_num(mfc_data->type);
-        for(uint16_t i = 0; i < total_block_num; i++) {
-            if(!mf_classic_is_block_read(mfc_data, i)) {
-                problems.missing_source_data = true;
-            }
-        }
-    }
-
-    return problems;
-}

+ 0 - 97
nfc_magic/lib/magic/protocols/gen2/gen2_poller.h

@@ -1,97 +0,0 @@
-#pragma once
-
-#include <nfc/nfc.h>
-#include <nfc/protocols/nfc_generic_event.h>
-#include <nfc/protocols/mf_classic/mf_classic.h>
-#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
-#include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
-#include <nfc/nfc_device.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
-    Gen2PollerErrorNone,
-    Gen2PollerErrorNotPresent,
-    Gen2PollerErrorProtocol,
-    Gen2PollerErrorAuth,
-    Gen2PollerErrorTimeout,
-    Gen2PollerErrorAccess,
-} Gen2PollerError;
-
-// Possible write problems, sorted by priority top to bottom
-typedef union {
-    uint8_t all_problems;
-    struct {
-        bool uid_locked : 1; // UID may be non-rewritable. Check data after writing
-        bool no_data : 1; // Shouldn't happen, mfc_data missing in nfc device
-        bool locked_access_bits : 1; // Access bits on the target card don't allow writing in some cases
-        bool missing_target_keys : 1; // Keys to write some sectors are not available
-        bool missing_source_data : 1; // The source dump is incomplete
-    };
-} Gen2PollerWriteProblems;
-
-#define GEN2_POLLER_WRITE_PROBLEMS_LEN (5)
-
-extern char* gen2_problem_strings[];
-
-typedef enum {
-    Gen2PollerEventTypeDetected,
-    Gen2PollerEventTypeRequestMode,
-    Gen2PollerEventTypeRequestDataToWrite,
-    Gen2PollerEventTypeRequestTargetData,
-
-    Gen2PollerEventTypeSuccess,
-    Gen2PollerEventTypeFail,
-} Gen2PollerEventType;
-
-typedef enum {
-    Gen2PollerModeWipe,
-    Gen2PollerModeWrite,
-} Gen2PollerMode;
-
-typedef struct {
-    Gen2PollerMode mode;
-} Gen2PollerEventDataRequestMode;
-
-typedef struct {
-    const MfClassicData* mfc_data;
-} Gen2PollerEventDataRequestDataToWrite;
-
-typedef struct {
-    const MfClassicData* mfc_data;
-} Gen2PollerEventDataRequestTargetData;
-
-typedef union {
-    Gen2PollerEventDataRequestMode poller_mode;
-    Gen2PollerEventDataRequestDataToWrite data_to_write;
-    Gen2PollerEventDataRequestTargetData target_data;
-} Gen2PollerEventData;
-
-typedef struct {
-    Gen2PollerEventType type;
-    Gen2PollerEventData* data;
-} Gen2PollerEvent;
-
-typedef NfcCommand (*Gen2PollerCallback)(Gen2PollerEvent event, void* context);
-
-typedef struct Gen2Poller Gen2Poller;
-
-Gen2PollerError gen2_poller_detect(Nfc* nfc);
-
-Gen2Poller* gen2_poller_alloc(Nfc* nfc);
-
-void gen2_poller_free(Gen2Poller* instance);
-
-void gen2_poller_start(Gen2Poller* instance, Gen2PollerCallback callback, void* context);
-
-void gen2_poller_stop(Gen2Poller* instance);
-
-Gen2PollerWriteProblems gen2_poller_check_target_problems(NfcDevice* target_dev);
-
-Gen2PollerWriteProblems gen2_poller_check_source_problems(NfcDevice* source_dev);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 629
nfc_magic/lib/magic/protocols/gen2/gen2_poller_i.c

@@ -1,629 +0,0 @@
-#include "gen2_poller_i.h"
-#include <nfc/helpers/iso14443_crc.h>
-
-#include <bit_lib/bit_lib.h>
-#include "furi_hal_random.h"
-
-#include <furi/furi.h>
-
-#define TAG "GEN2_I"
-
-MfClassicError mf_classic_process_error(Iso14443_3aError error) {
-    MfClassicError ret = MfClassicErrorNone;
-
-    switch(error) {
-    case Iso14443_3aErrorNone:
-        ret = MfClassicErrorNone;
-        break;
-    case Iso14443_3aErrorNotPresent:
-        ret = MfClassicErrorNotPresent;
-        break;
-    case Iso14443_3aErrorColResFailed:
-    case Iso14443_3aErrorCommunication:
-    case Iso14443_3aErrorWrongCrc:
-        ret = MfClassicErrorProtocol;
-        break;
-    case Iso14443_3aErrorTimeout:
-        ret = MfClassicErrorTimeout;
-        break;
-    default:
-        ret = MfClassicErrorProtocol;
-        break;
-    }
-    return ret;
-}
-
-Gen2PollerError gen2_poller_process_iso3_error(Iso14443_3aError error) {
-    Gen2PollerError ret = Gen2PollerErrorNone;
-
-    switch(error) {
-    case Iso14443_3aErrorNone:
-        ret = Gen2PollerErrorNone;
-        break;
-    case Iso14443_3aErrorNotPresent:
-        ret = Gen2PollerErrorNotPresent;
-        break;
-    case Iso14443_3aErrorWrongCrc:
-        ret = Gen2PollerErrorProtocol;
-        break;
-    case Iso14443_3aErrorTimeout:
-        ret = Gen2PollerErrorTimeout;
-        break;
-    default:
-        ret = Gen2PollerErrorProtocol;
-        break;
-    }
-    return ret;
-}
-
-Gen2PollerError gen2_poller_process_mifare_classic_error(MfClassicError error) {
-    Gen2PollerError ret = Gen2PollerErrorNone;
-
-    switch(error) {
-    case MfClassicErrorNone:
-        ret = Gen2PollerErrorNone;
-        break;
-    case MfClassicErrorNotPresent:
-        ret = Gen2PollerErrorNotPresent;
-        break;
-    case MfClassicErrorProtocol:
-        ret = Gen2PollerErrorProtocol;
-        break;
-    case MfClassicErrorAuth:
-        ret = Gen2PollerErrorAuth;
-        break;
-    case MfClassicErrorTimeout:
-        ret = Gen2PollerErrorTimeout;
-        break;
-    default:
-        ret = Gen2PollerErrorProtocol;
-        break;
-    }
-
-    return ret;
-}
-
-static Gen2PollerError gen2_poller_get_nt_common(
-    Gen2Poller* instance,
-    uint8_t block_num,
-    MfClassicKeyType key_type,
-    MfClassicNt* nt,
-    bool is_nested) {
-    MfClassicError ret = MfClassicErrorNone;
-    Iso14443_3aError error = Iso14443_3aErrorNone;
-
-    do {
-        uint8_t auth_type = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_CMD_AUTH_KEY_B :
-                                                              MF_CLASSIC_CMD_AUTH_KEY_A;
-        uint8_t auth_cmd[2] = {auth_type, block_num};
-        bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd));
-
-        if(is_nested) {
-            iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer);
-            crypto1_encrypt(
-                instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer);
-            error = iso14443_3a_poller_txrx_custom_parity(
-                instance->iso3_poller,
-                instance->tx_encrypted_buffer,
-                instance->rx_plain_buffer, // NT gets decrypted by mf_classic_async_auth
-                GEN2_POLLER_MAX_FWT);
-            if(error != Iso14443_3aErrorNone) {
-                ret = mf_classic_process_error(error);
-                break;
-            }
-        } else {
-            FURI_LOG_D(TAG, "Plain auth cmd");
-            error = iso14443_3a_poller_send_standard_frame(
-                instance->iso3_poller,
-                instance->tx_plain_buffer,
-                instance->rx_plain_buffer,
-                GEN2_POLLER_MAX_FWT);
-            if(error != Iso14443_3aErrorWrongCrc) {
-                ret = mf_classic_process_error(error);
-                break;
-            }
-        }
-        if(bit_buffer_get_size_bytes(instance->rx_plain_buffer) != sizeof(MfClassicNt)) {
-            ret = MfClassicErrorProtocol;
-            break;
-        }
-
-        if(nt) {
-            bit_buffer_write_bytes(instance->rx_plain_buffer, nt->data, sizeof(MfClassicNt));
-        }
-    } while(false);
-
-    return gen2_poller_process_mifare_classic_error(ret);
-}
-
-Gen2PollerError gen2_poller_get_nt(
-    Gen2Poller* instance,
-    uint8_t block_num,
-    MfClassicKeyType key_type,
-    MfClassicNt* nt) {
-    return gen2_poller_get_nt_common(instance, block_num, key_type, nt, false);
-}
-
-Gen2PollerError gen2_poller_get_nt_nested(
-    Gen2Poller* instance,
-    uint8_t block_num,
-    MfClassicKeyType key_type,
-    MfClassicNt* nt) {
-    return gen2_poller_get_nt_common(instance, block_num, key_type, nt, true);
-}
-
-static Gen2PollerError gen2_poller_auth_common(
-    Gen2Poller* instance,
-    uint8_t block_num,
-    MfClassicKey* key,
-    MfClassicKeyType key_type,
-    MfClassicAuthContext* data,
-    bool is_nested) {
-    Gen2PollerError ret = Gen2PollerErrorNone;
-    Iso14443_3aError error = Iso14443_3aErrorNone;
-
-    do {
-        iso14443_3a_copy(instance->data->iso14443_3a_data, nfc_poller_get_data(instance->poller));
-
-        MfClassicNt nt = {};
-        if(is_nested) {
-            ret = gen2_poller_get_nt_nested(instance, block_num, key_type, &nt);
-        } else {
-            ret = gen2_poller_get_nt(instance, block_num, key_type, &nt);
-        }
-        if(ret != Gen2PollerErrorNone) break;
-        if(data) {
-            data->nt = nt;
-        }
-
-        uint32_t cuid = iso14443_3a_get_cuid(instance->data->iso14443_3a_data);
-        uint64_t key_num = bit_lib_bytes_to_num_be(key->data, sizeof(MfClassicKey));
-        MfClassicNr nr = {};
-        furi_hal_random_fill_buf(nr.data, sizeof(MfClassicNr));
-
-        crypto1_encrypt_reader_nonce(
-            instance->crypto,
-            key_num,
-            cuid,
-            nt.data,
-            nr.data,
-            instance->tx_encrypted_buffer,
-            is_nested);
-        error = iso14443_3a_poller_txrx_custom_parity(
-            instance->iso3_poller,
-            instance->tx_encrypted_buffer,
-            instance->rx_encrypted_buffer,
-            GEN2_POLLER_MAX_FWT);
-
-        if(error != Iso14443_3aErrorNone) {
-            ret = gen2_poller_process_iso3_error(error);
-            break;
-        }
-        if(bit_buffer_get_size_bytes(instance->rx_encrypted_buffer) != 4) {
-            ret = Gen2PollerErrorAuth;
-        }
-
-        crypto1_word(instance->crypto, 0, 0);
-        instance->auth_state = Gen2AuthStatePassed;
-
-        if(data) {
-            data->nr = nr;
-            const uint8_t* nr_ar = bit_buffer_get_data(instance->tx_encrypted_buffer);
-            memcpy(data->ar.data, &nr_ar[4], sizeof(MfClassicAr));
-            bit_buffer_write_bytes(
-                instance->rx_encrypted_buffer, data->at.data, sizeof(MfClassicAt));
-        }
-    } while(false);
-
-    if(ret != Gen2PollerErrorNone) {
-        iso14443_3a_poller_halt(instance->iso3_poller);
-    }
-
-    return ret;
-}
-
-Gen2PollerError gen2_poller_auth(
-    Gen2Poller* instance,
-    uint8_t block_num,
-    MfClassicKey* key,
-    MfClassicKeyType key_type,
-    MfClassicAuthContext* data) {
-    return gen2_poller_auth_common(instance, block_num, key, key_type, data, false);
-}
-
-Gen2PollerError gen2_poller_halt(Gen2Poller* instance) {
-    Gen2PollerError ret = Gen2PollerErrorNone;
-    Iso14443_3aError error = Iso14443_3aErrorNone;
-
-    do {
-        uint8_t halt_cmd[2] = {MF_CLASSIC_CMD_HALT_MSB, MF_CLASSIC_CMD_HALT_LSB};
-        bit_buffer_copy_bytes(instance->tx_plain_buffer, halt_cmd, sizeof(halt_cmd));
-        iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer);
-
-        if(instance->auth_state == Gen2AuthStatePassed) {
-            // Send an encrypted halt command
-            crypto1_encrypt(
-                instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer);
-            FURI_LOG_D(TAG, "Send enc halt");
-            error = iso14443_3a_poller_txrx_custom_parity(
-                instance->iso3_poller,
-                instance->tx_encrypted_buffer,
-                instance->rx_encrypted_buffer,
-                GEN2_POLLER_MAX_FWT);
-        }
-
-        if(error != Iso14443_3aErrorNone) {
-            FURI_LOG_D(TAG, "Enc halt error");
-            // Do not break because we still need to halt the iso3 poller
-        }
-
-        // Send a regular halt command to halt the iso3 poller
-        FURI_LOG_D(TAG, "Send reg halt");
-        error = iso14443_3a_poller_halt(instance->iso3_poller);
-
-        if(error != Iso14443_3aErrorTimeout) {
-            FURI_LOG_D(TAG, "Reg halt error");
-            // Do not break as well becaue the first halt command might have worked
-            // and the card didn't respond because it was already halted
-        }
-
-        crypto1_reset(instance->crypto);
-        instance->auth_state = Gen2AuthStateIdle;
-    } while(false);
-
-    return ret;
-}
-
-Gen2PollerError
-    gen2_poller_write_block(Gen2Poller* instance, uint8_t block_num, const MfClassicBlock* data) {
-    Gen2PollerError ret = Gen2PollerErrorNone;
-    Iso14443_3aError error = Iso14443_3aErrorNone;
-
-    do {
-        uint8_t write_block_cmd[2] = {MF_CLASSIC_CMD_WRITE_BLOCK, block_num};
-        bit_buffer_copy_bytes(instance->tx_plain_buffer, write_block_cmd, sizeof(write_block_cmd));
-        iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer);
-
-        crypto1_encrypt(
-            instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer);
-
-        error = iso14443_3a_poller_txrx_custom_parity(
-            instance->iso3_poller,
-            instance->tx_encrypted_buffer,
-            instance->rx_encrypted_buffer,
-            GEN2_POLLER_MAX_FWT);
-        if(error != Iso14443_3aErrorNone) {
-            ret = gen2_poller_process_iso3_error(error);
-            break;
-        }
-        if(bit_buffer_get_size(instance->rx_encrypted_buffer) != 4) {
-            ret = Gen2PollerErrorProtocol;
-            break;
-        }
-
-        crypto1_decrypt(
-            instance->crypto, instance->rx_encrypted_buffer, instance->rx_plain_buffer);
-
-        if(bit_buffer_get_byte(instance->rx_plain_buffer, 0) != MF_CLASSIC_CMD_ACK) {
-            FURI_LOG_D(TAG, "NACK received");
-            ret = Gen2PollerErrorProtocol;
-            break;
-        }
-
-        bit_buffer_copy_bytes(instance->tx_plain_buffer, data->data, sizeof(MfClassicBlock));
-        iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer);
-
-        crypto1_encrypt(
-            instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer);
-
-        error = iso14443_3a_poller_txrx_custom_parity(
-            instance->iso3_poller,
-            instance->tx_encrypted_buffer,
-            instance->rx_encrypted_buffer,
-            GEN2_POLLER_MAX_FWT);
-        if(error != Iso14443_3aErrorNone) {
-            ret = gen2_poller_process_iso3_error(error);
-            break;
-        }
-        if(bit_buffer_get_size(instance->rx_encrypted_buffer) != 4) {
-            ret = Gen2PollerErrorProtocol;
-            break;
-        }
-
-        crypto1_decrypt(
-            instance->crypto, instance->rx_encrypted_buffer, instance->rx_plain_buffer);
-
-        if(bit_buffer_get_byte(instance->rx_plain_buffer, 0) != MF_CLASSIC_CMD_ACK) {
-            FURI_LOG_D(TAG, "NACK received");
-            ret = Gen2PollerErrorProtocol;
-            break;
-        }
-    } while(false);
-
-    return ret;
-}
-
-bool gen2_poller_can_write_block(const MfClassicData* target_data, uint8_t block_num) {
-    furi_assert(target_data);
-
-    bool can_write = true;
-
-    if(block_num == 0 && target_data->iso14443_3a_data->uid_len == 7) {
-        // 7-byte UID gen2 cards are not supported yet, need further testing
-        can_write = false;
-    }
-
-    if(mf_classic_is_sector_trailer(block_num)) {
-        can_write = gen2_poller_can_write_sector_trailer(target_data, block_num).all_problems == 0;
-    } else {
-        can_write = gen2_poller_can_write_data_block(target_data, block_num).all_problems == 0;
-    }
-
-    return can_write;
-}
-
-Gen2PollerWriteProblems
-    gen2_poller_can_write_data_block(const MfClassicData* target_data, uint8_t block_num) {
-    // Check whether it's possible to write the block
-    furi_assert(target_data);
-
-    // Check rules:
-    // 1. Check if block is read
-    // 2. Check if we have any of the keys
-    // 3. For each key, check if we can write the block
-    // 3.1. If none of the keys can write the block, check whether access conditions can be reset to allow writing
-    // 3.2 If the above conditions are not met, return an error code
-
-    Gen2PollerWriteProblems can_write = {0};
-
-    bool has_key_a = mf_classic_is_key_found(
-        target_data, mf_classic_get_sector_by_block(block_num), MfClassicKeyTypeA);
-    bool has_key_b = mf_classic_is_key_found(
-        target_data, mf_classic_get_sector_by_block(block_num), MfClassicKeyTypeB);
-
-    if(!has_key_a && !has_key_b) {
-        can_write.missing_target_keys = true;
-    }
-    if(!gen2_is_allowed_access(
-           target_data, block_num, MfClassicKeyTypeA, MfClassicActionDataWrite) &&
-       !gen2_is_allowed_access(
-           target_data, block_num, MfClassicKeyTypeB, MfClassicActionDataWrite)) {
-        if(!gen2_can_reset_access_conditions(target_data, block_num)) {
-            can_write.locked_access_bits = true;
-        }
-    }
-
-    return can_write;
-}
-
-Gen2PollerWriteProblems
-    gen2_poller_can_write_sector_trailer(const MfClassicData* target_data, uint8_t block_num) {
-    // Check whether it's possible to write the sector trailer
-    furi_assert(target_data);
-
-    // Check rules:
-    // 1. Check if block is read
-    // 2. Check if we have any of the keys
-    // 3. For each key, check if we can write the block
-    // 3.1 Check that at least one of the keys can write Key A
-    // 3.1.1 If none of the keys can write Key A, check whether access conditions can be reset to allow writing
-    // 3.2 Check that at least one of the keys can write the Access Conditions
-    // 3.3 Check that at least one of the keys can write Key B
-    // 3.3.1 If none of the keys can write Key B, check whether access conditions can be reset to allow writing
-    // 3.4 If any of the above conditions are not met, return an error code
-
-    Gen2PollerWriteProblems can_write = {0};
-
-    bool has_key_a = mf_classic_is_key_found(
-        target_data, mf_classic_get_sector_by_block(block_num), MfClassicKeyTypeA);
-    bool has_key_b = mf_classic_is_key_found(
-        target_data, mf_classic_get_sector_by_block(block_num), MfClassicKeyTypeB);
-
-    if(!has_key_a && !has_key_b) {
-        can_write.missing_target_keys = true;
-    }
-    if(!gen2_is_allowed_access(
-           target_data, block_num, MfClassicKeyTypeA, MfClassicActionKeyAWrite) &&
-       !gen2_is_allowed_access(
-           target_data, block_num, MfClassicKeyTypeB, MfClassicActionKeyAWrite)) {
-        if(!gen2_can_reset_access_conditions(target_data, block_num)) {
-            can_write.locked_access_bits = true;
-        }
-    }
-    if(!gen2_is_allowed_access(target_data, block_num, MfClassicKeyTypeA, MfClassicActionACWrite) &&
-       !gen2_is_allowed_access(target_data, block_num, MfClassicKeyTypeB, MfClassicActionACWrite)) {
-        can_write.locked_access_bits = true;
-    }
-    if(!gen2_is_allowed_access(
-           target_data, block_num, MfClassicKeyTypeA, MfClassicActionKeyBWrite) &&
-       !gen2_is_allowed_access(
-           target_data, block_num, MfClassicKeyTypeB, MfClassicActionKeyBWrite)) {
-        if(!gen2_can_reset_access_conditions(target_data, block_num)) {
-            can_write.locked_access_bits = true;
-        }
-    }
-
-    return can_write;
-}
-
-bool gen2_can_reset_access_conditions(const MfClassicData* target_data, uint8_t block_num) {
-    // Check whether it's possible to reset the access conditions
-    furi_assert(target_data);
-
-    // Check rules:
-    // 1. Check if the sector trailer for this block is read
-    // 2. Check if we have any of the keys
-    // 3. For each key, check if we can write the access conditions
-    // 3.1. If none of the keys can write the access conditions, return false
-
-    bool can_reset = false;
-
-    bool has_key_a = mf_classic_is_key_found(
-        target_data, mf_classic_get_sector_by_block(block_num), MfClassicKeyTypeA);
-    bool has_key_b = mf_classic_is_key_found(
-        target_data, mf_classic_get_sector_by_block(block_num), MfClassicKeyTypeB);
-    uint8_t sector_tr_num = mf_classic_get_sector_trailer_num_by_block(block_num);
-
-    if(!mf_classic_is_block_read(target_data, sector_tr_num)) {
-        can_reset = false;
-        return can_reset;
-    }
-
-    if(!has_key_a && !has_key_b) {
-        can_reset = false;
-        return can_reset;
-    }
-    if(gen2_is_allowed_access(target_data, block_num, MfClassicKeyTypeA, MfClassicActionACWrite) ||
-       gen2_is_allowed_access(target_data, block_num, MfClassicKeyTypeB, MfClassicActionACWrite)) {
-        can_reset = true;
-    }
-
-    return can_reset;
-}
-
-MfClassicKeyType
-    gen2_poller_get_key_type_to_write(const MfClassicData* target_data, uint8_t block_num) {
-    // Get the key type to use for writing
-    // We assume that at least one of the keys can write the block
-    furi_assert(target_data);
-
-    MfClassicKeyType key_type = MfClassicKeyTypeA;
-
-    if(gen2_is_allowed_access(
-           target_data, block_num, MfClassicKeyTypeA, MfClassicActionDataWrite)) {
-        key_type = MfClassicKeyTypeA;
-    } else if(gen2_is_allowed_access(
-                  target_data, block_num, MfClassicKeyTypeB, MfClassicActionDataWrite)) {
-        key_type = MfClassicKeyTypeB;
-    }
-
-    return key_type;
-}
-
-static bool gen2_is_allowed_access_sector_trailer(
-    const MfClassicData* data,
-    uint8_t block_num,
-    MfClassicKeyType key_type,
-    MfClassicAction action) {
-    uint8_t sector_num = mf_classic_get_sector_by_block(block_num);
-    MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num);
-    uint8_t* access_bits_arr = sec_tr->access_bits.data;
-    uint8_t AC = ((access_bits_arr[1] >> 5) & 0x04) | ((access_bits_arr[2] >> 2) & 0x02) |
-                 ((access_bits_arr[2] >> 7) & 0x01);
-    FURI_LOG_T("NFC", "AC: %02X", AC);
-
-    switch(action) {
-    case MfClassicActionKeyARead: {
-        return false;
-    }
-    case MfClassicActionKeyAWrite:
-    case MfClassicActionKeyBWrite: {
-        return (
-            (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x01)) ||
-            (key_type == MfClassicKeyTypeB &&
-             (AC == 0x00 || AC == 0x04 || AC == 0x03 || AC == 0x01)));
-    }
-    case MfClassicActionKeyBRead: {
-        return (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x02 || AC == 0x01)) ||
-               (key_type == MfClassicKeyTypeB && (AC == 0x00 || AC == 0x02 || AC == 0x01));
-    }
-    case MfClassicActionACRead: {
-        return ((key_type == MfClassicKeyTypeA) || (key_type == MfClassicKeyTypeB));
-    }
-    case MfClassicActionACWrite: {
-        return (
-            (key_type == MfClassicKeyTypeA && (AC == 0x01)) ||
-            (key_type == MfClassicKeyTypeB && (AC == 0x01 || AC == 0x03 || AC == 0x05)));
-    }
-    default:
-        return false;
-    }
-    return true;
-}
-
-bool gen2_is_allowed_access_data_block(
-    MfClassicSectorTrailer* sec_tr,
-    uint8_t block_num,
-    MfClassicKeyType key_type,
-    MfClassicAction action) {
-    // Same as mf_classic_is_allowed_access_data_block but with sector 0 allowed
-    furi_assert(sec_tr);
-
-    uint8_t* access_bits_arr = sec_tr->access_bits.data;
-
-    uint8_t sector_block = 0;
-    if(block_num <= 128) {
-        sector_block = block_num & 0x03;
-    } else {
-        sector_block = (block_num & 0x0f) / 5;
-    }
-
-    uint8_t AC;
-    switch(sector_block) {
-    case 0x00: {
-        AC = ((access_bits_arr[1] >> 2) & 0x04) | ((access_bits_arr[2] << 1) & 0x02) |
-             ((access_bits_arr[2] >> 4) & 0x01);
-        break;
-    }
-    case 0x01: {
-        AC = ((access_bits_arr[1] >> 3) & 0x04) | ((access_bits_arr[2] >> 0) & 0x02) |
-             ((access_bits_arr[2] >> 5) & 0x01);
-        break;
-    }
-    case 0x02: {
-        AC = ((access_bits_arr[1] >> 4) & 0x04) | ((access_bits_arr[2] >> 1) & 0x02) |
-             ((access_bits_arr[2] >> 6) & 0x01);
-        break;
-    }
-    default:
-        return false;
-    }
-
-    switch(action) {
-    case MfClassicActionDataRead: {
-        return (
-            (key_type == MfClassicKeyTypeA && !(AC == 0x03 || AC == 0x05 || AC == 0x07)) ||
-            (key_type == MfClassicKeyTypeB && !(AC == 0x07)));
-    }
-    case MfClassicActionDataWrite: {
-        return (
-            (key_type == MfClassicKeyTypeA && (AC == 0x00)) ||
-            (key_type == MfClassicKeyTypeB &&
-             (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03)));
-    }
-    case MfClassicActionDataInc: {
-        return (
-            (key_type == MfClassicKeyTypeA && (AC == 0x00)) ||
-            (key_type == MfClassicKeyTypeB && (AC == 0x00 || AC == 0x06)));
-    }
-    case MfClassicActionDataDec: {
-        return (
-            (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x06 || AC == 0x01)) ||
-            (key_type == MfClassicKeyTypeB && (AC == 0x00 || AC == 0x06 || AC == 0x01)));
-    }
-    default:
-        return false;
-    }
-
-    return false;
-}
-
-bool gen2_is_allowed_access(
-    const MfClassicData* data,
-    uint8_t block_num,
-    MfClassicKeyType key_type,
-    MfClassicAction action) {
-    // Same as mf_classic_is_allowed_access but with sector 0 allowed
-    furi_assert(data);
-
-    bool access_allowed = false;
-    if(mf_classic_is_sector_trailer(block_num)) {
-        access_allowed = gen2_is_allowed_access_sector_trailer(data, block_num, key_type, action);
-    } else {
-        uint8_t sector_num = mf_classic_get_sector_by_block(block_num);
-        MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num);
-        access_allowed = gen2_is_allowed_access_data_block(sec_tr, block_num, key_type, action);
-    }
-
-    return access_allowed;
-}

+ 0 - 139
nfc_magic/lib/magic/protocols/gen2/gen2_poller_i.h

@@ -1,139 +0,0 @@
-#pragma once
-
-#include "gen2_poller.h"
-#include <nfc/protocols/nfc_generic_event.h>
-#include "crypto1.h" // TODO: Move to a better home
-#include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GEN2_CMD_READ_ATS (0xE0)
-#define GEN2_FSDI_256 (0x8U)
-
-#define GEN2_POLLER_BLOCK_SIZE (16)
-
-#define GEN2_POLLER_MAX_BUFFER_SIZE (64U)
-#define GEN2_POLLER_MAX_FWT (150000U)
-
-typedef enum {
-    Gen2PollerStateIdle,
-    Gen2PollerStateRequestMode,
-    Gen2PollerStateWipe,
-    Gen2PollerStateWriteSourceDataRequest,
-    Gen2PollerStateWriteTargetDataRequest,
-    Gen2PollerStateWrite,
-    Gen2PollerStateSuccess,
-    Gen2PollerStateFail,
-
-    Gen2PollerStateNum,
-} Gen2PollerState;
-
-typedef enum {
-    Gen2AuthStateIdle,
-    Gen2AuthStatePassed,
-} Gen2AuthState;
-
-typedef enum {
-    Gen2CardStateDetected,
-    Gen2CardStateLost,
-} Gen2CardState;
-
-typedef struct {
-    MfClassicData* mfc_data_source;
-    MfClassicData* mfc_data_target;
-    MfClassicKey auth_key;
-    MfClassicKeyType read_key;
-    MfClassicKeyType write_key;
-    uint16_t current_block;
-    bool need_halt_before_write;
-} Gen2PollerWriteContext;
-
-typedef union {
-    Gen2PollerWriteContext write_ctx;
-} Gen2PollerModeContext;
-
-struct Gen2Poller {
-    Nfc* nfc;
-    Gen2PollerState state;
-
-    NfcPoller* poller;
-    Iso14443_3aPoller* iso3_poller;
-
-    Gen2AuthState auth_state;
-    Gen2CardState card_state;
-
-    Gen2PollerModeContext mode_ctx;
-    Gen2PollerMode mode;
-
-    Crypto1* crypto;
-    BitBuffer* tx_plain_buffer;
-    BitBuffer* tx_encrypted_buffer;
-    BitBuffer* rx_plain_buffer;
-    BitBuffer* rx_encrypted_buffer;
-    MfClassicData* data;
-
-    Gen2PollerEvent gen2_event;
-    Gen2PollerEventData gen2_event_data;
-
-    Gen2PollerCallback callback;
-    void* context;
-};
-
-typedef struct {
-    uint8_t block;
-    MfClassicKeyType key_type;
-    MfClassicNt nt;
-} Gen2CollectNtContext;
-
-typedef struct {
-    uint8_t block_num;
-    MfClassicKey key;
-    MfClassicKeyType key_type;
-    MfClassicBlock block;
-} Gen2ReadBlockContext;
-
-typedef struct {
-    uint8_t block_num;
-    MfClassicKey key;
-    MfClassicKeyType key_type;
-    MfClassicBlock block;
-} Gen2WriteBlockContext;
-
-Gen2PollerError gen2_poller_write(Gen2Poller* instance);
-
-Gen2PollerError gen2_poller_auth(
-    Gen2Poller* instance,
-    uint8_t block_num,
-    MfClassicKey* key,
-    MfClassicKeyType key_type,
-    MfClassicAuthContext* data);
-
-Gen2PollerError gen2_poller_halt(Gen2Poller* instance);
-
-Gen2PollerError
-    gen2_poller_write_block(Gen2Poller* instance, uint8_t block_num, const MfClassicBlock* data);
-
-MfClassicKeyType
-    gen2_poller_get_key_type_to_write(const MfClassicData* mfc_data, uint8_t block_num);
-
-bool gen2_poller_can_write_block(const MfClassicData* mfc_data, uint8_t block_num);
-
-bool gen2_can_reset_access_conditions(const MfClassicData* mfc_data, uint8_t block_num);
-
-Gen2PollerWriteProblems
-    gen2_poller_can_write_data_block(const MfClassicData* mfc_data, uint8_t block_num);
-
-Gen2PollerWriteProblems
-    gen2_poller_can_write_sector_trailer(const MfClassicData* mfc_data, uint8_t block_num);
-
-bool gen2_is_allowed_access(
-    const MfClassicData* data,
-    uint8_t block_num,
-    MfClassicKeyType key_type,
-    MfClassicAction action);
-
-#ifdef __cplusplus
-}
-#endif

+ 97 - 0
nfc_magic/lib/magic/protocols/gen4/gen4.c

@@ -0,0 +1,97 @@
+#include "gen4.h"
+#include "core/check.h"
+
+Gen4* gen4_alloc() {
+    Gen4* instance = (Gen4*)malloc(sizeof(Gen4));
+    return instance;
+}
+
+void gen4_free(Gen4* instance) {
+    furi_check(instance != NULL);
+    free(instance);
+}
+
+void gen4_reset(Gen4* instance) {
+    furi_check(instance != NULL);
+    memset(&instance->config, 0, sizeof(Gen4Config));
+    memset(&instance->revision, 0, sizeof(Gen4Revision));
+}
+
+void gen4_copy(Gen4* dest, const Gen4* source) {
+    furi_check(dest != NULL);
+    furi_check(source != NULL);
+    memcpy(dest, source, sizeof(Gen4));
+}
+
+char* gen4_get_shadow_mode_name(Gen4ShadowMode mode) {
+    switch(mode) {
+    case Gen4ShadowModePreWrite:
+        return "Pre-Write";
+    case Gen4ShadowModeRestore:
+        return "Restore";
+    case Gen4ShadowModeDisabled:
+        return "Disabled";
+    case Gen4ShadowModeHighSpeedDisabled:
+        return "Disabled (High-speed)";
+    case Gen4ShadowModeSplit:
+        return "Split";
+    default:
+        return "Unknown";
+    }
+}
+
+char* gen4_get_direct_write_mode_name(Gen4DirectWriteBlock0Mode mode) {
+    switch(mode) {
+    case Gen4DirectWriteBlock0ModeEnabled:
+        return "Enabled";
+    case Gen4DirectWriteBlock0ModeDisabled:
+        return "Disabled";
+    case Gen4DirectWriteBlock0ModeDefault:
+        return "Default";
+    default:
+        return "Unknown";
+    }
+}
+
+char* gen4_get_uid_len_num(Gen4UIDLength code) {
+    switch(code) {
+    case Gen4UIDLengthSingle:
+        return "4";
+    case Gen4UIDLengthDouble:
+        return "7";
+    case Gen4UIDLengthTriple:
+        return "10";
+    default:
+        return "Unknown";
+    }
+}
+
+char* gen4_get_configuration_name(const Gen4Config* config) {
+    switch(config->data_parsed.protocol) {
+    case Gen4ProtocolMfClassic: {
+        switch(config->data_parsed.total_blocks) {
+        case 255:
+            return "MIFARE Classic 4K";
+        case 63:
+            return "MIFARE Classic 1K";
+        case 19:
+            return "MIFARE Classic Mini (0.3K)";
+        default:
+            return "Unknown";
+        }
+    } break;
+    case Gen4ProtocolMfUltralight: {
+        switch(config->data_parsed.total_blocks) {
+        case 63:
+            return "MIFARE Ultralight";
+        case 127:
+            return "NTAG 2XX";
+        default:
+            return "Unknown";
+        }
+    } break;
+    default:
+        return "Unknown";
+        break;
+    };
+}

+ 101 - 0
nfc_magic/lib/magic/protocols/gen4/gen4.h

@@ -0,0 +1,101 @@
+#pragma once
+
+#include <stdint.h>
+
+#define GEN4_CONFIG_SIZE (32)
+#define GEN4_REVISION_SIZE (5)
+
+#define GEN4_PASSWORD_LEN (4)
+#define GEN4_ATS_MAX_LEN (16)
+#define GEN4_ATQA_LEN (2)
+#define GEN4_CRC_LEN (2)
+
+typedef enum {
+    Gen4ProtocolMfClassic = 0x00,
+    Gen4ProtocolMfUltralight = 0x01,
+} Gen4Protocol;
+
+typedef union {
+    uint32_t value;
+    uint8_t bytes[GEN4_PASSWORD_LEN];
+} Gen4Password;
+
+typedef enum {
+    Gen4UIDLengthSingle = 0x00,
+    Gen4UIDLengthDouble = 0x01,
+    Gen4UIDLengthTriple = 0x02
+} Gen4UIDLength;
+
+typedef enum {
+    Gen4UltralightModeUL_EV1 = 0x00,
+    Gen4UltralightModeNTAG = 0x01,
+    Gen4UltralightModeUL_C = 0x02,
+    Gen4UltralightModeUL = 0x03
+} Gen4UltralightMode;
+
+typedef enum {
+    // for writing original (shadow) data
+    Gen4ShadowModePreWrite = 0x00,
+    // written data can be read once before restored to original
+    Gen4ShadowModeRestore = 0x01,
+    // shadow mode disabled
+    Gen4ShadowModeDisabled = 0x02,
+    // apparently for UL?
+    Gen4ShadowModeHighSpeedDisabled = 0x03,
+    // work with new UMC. With old UMC is untested
+    Gen4ShadowModeSplit = 0x04,
+} Gen4ShadowMode;
+
+typedef enum {
+    // gen2 card behavour
+    Gen4DirectWriteBlock0ModeEnabled = 0x00,
+    // common card behavour
+    Gen4DirectWriteBlock0ModeDisabled = 0x01,
+    // default mode. same behavour as Gen4DirectWriteBlock0ModeActivate
+    Gen4DirectWriteBlock0ModeDefault = 0x02,
+} Gen4DirectWriteBlock0Mode;
+
+typedef union {
+    uint8_t data_raw[GEN4_CONFIG_SIZE];
+#pragma pack(push, 1)
+    struct {
+        Gen4Protocol protocol;
+        Gen4UIDLength uid_len_code;
+        Gen4Password password;
+        Gen4ShadowMode gtu_mode;
+        uint8_t ats_len;
+        uint8_t ats[GEN4_ATS_MAX_LEN]; // mb another class?
+        uint8_t atqa[GEN4_ATQA_LEN];
+        uint8_t sak;
+        Gen4UltralightMode mfu_mode;
+        uint8_t total_blocks;
+        Gen4DirectWriteBlock0Mode direct_write_mode;
+        uint8_t crc[GEN4_CRC_LEN];
+    } data_parsed;
+#pragma pack(pop)
+} Gen4Config;
+
+typedef struct {
+    uint8_t data[GEN4_REVISION_SIZE];
+} Gen4Revision;
+
+typedef struct {
+    Gen4Config config;
+    Gen4Revision revision;
+} Gen4;
+
+Gen4* gen4_alloc();
+
+void gen4_free(Gen4* instance);
+
+void gen4_reset(Gen4* instance);
+
+void gen4_copy(Gen4* dest, const Gen4* source);
+
+char* gen4_get_shadow_mode_name(Gen4ShadowMode mode);
+
+char* gen4_get_direct_write_mode_name(Gen4DirectWriteBlock0Mode mode);
+
+char* gen4_get_uid_len_num(Gen4UIDLength code);
+
+char* gen4_get_configuration_name(const Gen4Config* config);

+ 156 - 61
nfc_magic/lib/magic/protocols/gen4/gen4_poller.c

@@ -1,27 +1,33 @@
+#include "bit_buffer.h"
 #include "gen4_poller_i.h"
+#include "protocols/gen4/gen4.h"
 #include "protocols/gen4/gen4_poller.h"
 #include <nfc/protocols/iso14443_3a/iso14443_3a.h>
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
 #include <nfc/nfc_poller.h>
 #include <bit_lib.h>
+#include <string.h>
 
 #define GEN4_POLLER_THREAD_FLAG_DETECTED (1U << 0)
+#define GEN4_POLLER_DEFAULT_CONFIG_SIZE (28)
 
 typedef NfcCommand (*Gen4PollerStateHandler)(Gen4Poller* instance);
 
 typedef struct {
     NfcPoller* poller;
-    uint32_t password;
+    Gen4Password password;
+    Gen4 gen4_data;
     BitBuffer* tx_buffer;
     BitBuffer* rx_buffer;
     FuriThreadId thread_id;
     Gen4PollerError error;
 } Gen4PollerDetectContext;
 
-static const uint8_t gen4_poller_default_config[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-                                                     0x00, 0x09, 0x78, 0x00, 0x91, 0x02, 0xDA,
-                                                     0xBC, 0x19, 0x10, 0x10, 0x11, 0x12, 0x13,
-                                                     0x14, 0x15, 0x16, 0x04, 0x00, 0x08, 0x00};
+static const Gen4Config gen4_poller_default_config = {
+    .data_raw = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x78,
+                 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0x10, 0x11, 0x12,
+                 0x13, 0x14, 0x15, 0x16, 0x04, 0x00, 0x08, 0x00}};
+
 static const uint8_t gen4_poller_default_block_0[GEN4_POLLER_BLOCK_SIZE] =
     {0x00, 0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
@@ -53,6 +59,8 @@ Gen4Poller* gen4_poller_alloc(Nfc* nfc) {
     instance->tx_buffer = bit_buffer_alloc(GEN4_POLLER_MAX_BUFFER_SIZE);
     instance->rx_buffer = bit_buffer_alloc(GEN4_POLLER_MAX_BUFFER_SIZE);
 
+    instance->gen4_data = gen4_alloc();
+
     return instance;
 }
 
@@ -64,10 +72,12 @@ void gen4_poller_free(Gen4Poller* instance) {
     bit_buffer_free(instance->tx_buffer);
     bit_buffer_free(instance->rx_buffer);
 
+    gen4_free(instance->gen4_data);
+
     free(instance);
 }
 
-void gen4_poller_set_password(Gen4Poller* instance, uint32_t password) {
+void gen4_poller_set_password(Gen4Poller* instance, Gen4Password password) {
     furi_assert(instance);
 
     instance->password = password;
@@ -87,10 +97,12 @@ NfcCommand gen4_poller_detect_callback(NfcGenericEvent event, void* context) {
 
     if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
         do {
+            // check config
             bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_PREFIX);
-            uint8_t pwd_arr[4] = {};
-            bit_lib_num_to_bytes_be(gen4_poller_detect_ctx->password, COUNT_OF(pwd_arr), pwd_arr);
-            bit_buffer_append_bytes(gen4_poller_detect_ctx->tx_buffer, pwd_arr, COUNT_OF(pwd_arr));
+            bit_buffer_append_bytes(
+                gen4_poller_detect_ctx->tx_buffer,
+                gen4_poller_detect_ctx->password.bytes,
+                GEN4_PASSWORD_LEN);
             bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_GET_CFG);
 
             Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
@@ -104,11 +116,48 @@ NfcCommand gen4_poller_detect_callback(NfcGenericEvent event, void* context) {
                 break;
             }
             size_t rx_bytes = bit_buffer_get_size_bytes(gen4_poller_detect_ctx->rx_buffer);
-            if((rx_bytes != 30) && (rx_bytes != 32)) {
+            if(rx_bytes != GEN4_CONFIG_SIZE) {
+                gen4_poller_detect_ctx->error = Gen4PollerErrorProtocol;
+                break;
+            }
+
+            memcpy(
+                gen4_poller_detect_ctx->gen4_data.config.data_raw,
+                bit_buffer_get_data(gen4_poller_detect_ctx->rx_buffer),
+                GEN4_CONFIG_SIZE);
+
+            // check revision
+            bit_buffer_reset(gen4_poller_detect_ctx->tx_buffer);
+            bit_buffer_reset(gen4_poller_detect_ctx->rx_buffer);
+
+            bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_PREFIX);
+            bit_buffer_append_bytes(
+                gen4_poller_detect_ctx->tx_buffer,
+                gen4_poller_detect_ctx->password.bytes,
+                GEN4_PASSWORD_LEN);
+            bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_GET_REVISION);
+
+            error = iso14443_3a_poller_send_standard_frame(
+                iso3_poller,
+                gen4_poller_detect_ctx->tx_buffer,
+                gen4_poller_detect_ctx->rx_buffer,
+                GEN4_POLLER_MAX_FWT);
+
+            if(error != Iso14443_3aErrorNone) {
+                gen4_poller_detect_ctx->error = Gen4PollerErrorProtocol;
+                break;
+            }
+            rx_bytes = bit_buffer_get_size_bytes(gen4_poller_detect_ctx->rx_buffer);
+            if(rx_bytes != GEN4_REVISION_SIZE) {
                 gen4_poller_detect_ctx->error = Gen4PollerErrorProtocol;
                 break;
             }
 
+            memcpy(
+                gen4_poller_detect_ctx->gen4_data.revision.data,
+                bit_buffer_get_data(gen4_poller_detect_ctx->rx_buffer),
+                GEN4_REVISION_SIZE);
+
             gen4_poller_detect_ctx->error = Gen4PollerErrorNone;
         } while(false);
     } else if(iso3_event->type == Iso14443_3aPollerEventTypeError) {
@@ -119,7 +168,7 @@ NfcCommand gen4_poller_detect_callback(NfcGenericEvent event, void* context) {
     return command;
 }
 
-Gen4PollerError gen4_poller_detect(Nfc* nfc, uint32_t password) {
+Gen4PollerError gen4_poller_detect(Nfc* nfc, Gen4Password password, Gen4* gen4_data) {
     furi_assert(nfc);
 
     Gen4PollerDetectContext gen4_poller_detect_ctx = {};
@@ -143,6 +192,9 @@ Gen4PollerError gen4_poller_detect(Nfc* nfc, uint32_t password) {
     bit_buffer_free(gen4_poller_detect_ctx.tx_buffer);
     bit_buffer_free(gen4_poller_detect_ctx.rx_buffer);
 
+    if(gen4_poller_detect_ctx.error == Gen4PollerErrorNone)
+        gen4_copy(gen4_data, &gen4_poller_detect_ctx.gen4_data);
+
     return gen4_poller_detect_ctx.error;
 }
 
@@ -150,7 +202,8 @@ NfcCommand gen4_poller_idle_handler(Gen4Poller* instance) {
     NfcCommand command = NfcCommandContinue;
 
     instance->current_block = 0;
-    memset(instance->config, 0, sizeof(instance->config));
+    //TODO: FOR WHAT?
+    //memset(instance->config, 0, sizeof(instance->config));
     instance->gen4_event.type = Gen4PollerEventTypeCardDetected;
     command = instance->callback(instance->gen4_event, instance->context);
     instance->state = Gen4PollerStateRequestMode;
@@ -193,15 +246,15 @@ NfcCommand gen4_poller_wipe_handler(Gen4Poller* instance) {
             error = gen4_poller_set_config(
                 instance,
                 instance->password,
-                gen4_poller_default_config,
-                sizeof(gen4_poller_default_config),
+                &gen4_poller_default_config,
+                GEN4_POLLER_DEFAULT_CONFIG_SIZE,
                 false);
             if(error != Gen4PollerErrorNone) {
                 FURI_LOG_D(TAG, "Failed to set default config: %d", error);
                 instance->state = Gen4PollerStateFail;
                 break;
             }
-            instance->password = 0;
+            instance->password.value = 0;
             error = gen4_poller_write_block(
                 instance, instance->password, instance->current_block, gen4_poller_default_block_0);
             if(error != Gen4PollerErrorNone) {
@@ -256,29 +309,29 @@ static NfcCommand gen4_poller_write_mf_classic(Gen4Poller* instance) {
         const MfClassicData* mfc_data = instance->data;
         const Iso14443_3aData* iso3_data = mfc_data->iso14443_3a_data;
         if(instance->current_block == 0) {
-            instance->config[0] = 0x00;
+            instance->config.data_parsed.protocol = Gen4ProtocolMfClassic;
             instance->total_blocks = mf_classic_get_total_block_num(mfc_data->type);
 
             if(iso3_data->uid_len == 4) {
-                instance->config[1] = Gen4PollerUIDLengthSingle;
+                instance->config.data_parsed.uid_len_code = Gen4UIDLengthSingle;
             } else if(iso3_data->uid_len == 7) {
-                instance->config[1] = Gen4PollerUIDLengthDouble;
+                instance->config.data_parsed.uid_len_code = Gen4UIDLengthDouble;
             } else {
                 FURI_LOG_E(TAG, "Unsupported UID len: %d", iso3_data->uid_len);
                 instance->state = Gen4PollerStateFail;
                 break;
             }
 
-            instance->config[6] = Gen4PollerShadowModeDisabled;
-            instance->config[24] = iso3_data->atqa[0];
-            instance->config[25] = iso3_data->atqa[1];
-            instance->config[26] = iso3_data->sak;
-            instance->config[27] = 0x00;
-            instance->config[28] = instance->total_blocks - 1;
-            instance->config[29] = Gen4PollerDirectWriteBlock0ModeDisabled;
+            instance->config.data_parsed.gtu_mode = Gen4ShadowModeDisabled;
+            instance->config.data_parsed.atqa[0] = iso3_data->atqa[0];
+            instance->config.data_parsed.atqa[1] = iso3_data->atqa[1];
+            instance->config.data_parsed.sak = iso3_data->sak;
+            instance->config.data_parsed.mfu_mode = Gen4UltralightModeUL_EV1;
+            instance->config.data_parsed.total_blocks = instance->total_blocks - 1;
+            instance->config.data_parsed.direct_write_mode = Gen4DirectWriteBlock0ModeDisabled;
 
             Gen4PollerError error = gen4_poller_set_config(
-                instance, instance->password, instance->config, sizeof(instance->config), false);
+                instance, instance->password, &instance->config, GEN4_CONFIG_SIZE, false);
             if(error != Gen4PollerErrorNone) {
                 FURI_LOG_D(TAG, "Failed to write config: %d", error);
                 instance->state = Gen4PollerStateFail;
@@ -315,7 +368,7 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) {
         const Iso14443_3aData* iso3_data = mfu_data->iso14443_3a_data;
         if(instance->current_block == 0) {
             instance->total_blocks = 64;
-            instance->config[0] = 0x01;
+            instance->config.data_parsed.protocol = Gen4ProtocolMfUltralight;
             switch(mfu_data->type) {
             case MfUltralightTypeNTAG203:
             case MfUltralightTypeNTAG213:
@@ -325,7 +378,7 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) {
             case MfUltralightTypeNTAGI2C2K:
             case MfUltralightTypeNTAGI2CPlus1K:
             case MfUltralightTypeNTAGI2CPlus2K:
-                instance->config[27] = Gen4PollerUltralightModeNTAG;
+                instance->config.data_parsed.mfu_mode = Gen4UltralightModeNTAG;
                 instance->total_blocks = 64 * 2;
                 break;
 
@@ -334,30 +387,30 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) {
                 // UL-C?
                 // UL?
             default:
-                instance->config[27] = Gen4PollerUltralightModeUL_EV1;
+                instance->config.data_parsed.mfu_mode = Gen4UltralightModeUL_EV1;
                 break;
             }
 
             if(iso3_data->uid_len == 4) {
-                instance->config[1] = Gen4PollerUIDLengthSingle;
+                instance->config.data_parsed.uid_len_code = Gen4UIDLengthSingle;
             } else if(iso3_data->uid_len == 7) {
-                instance->config[1] = Gen4PollerUIDLengthDouble;
+                instance->config.data_parsed.uid_len_code = Gen4UIDLengthDouble;
             } else {
                 FURI_LOG_E(TAG, "Unsupported UID len: %d", iso3_data->uid_len);
                 instance->state = Gen4PollerStateFail;
                 break;
             }
 
-            instance->config[6] = Gen4PollerShadowModeHighSpeedDisabled;
-            instance->config[24] = iso3_data->atqa[0];
-            instance->config[25] = iso3_data->atqa[1];
-            instance->config[26] = iso3_data->sak;
-            instance->config[27] = 0x00;
-            instance->config[28] = instance->total_blocks - 1;
-            instance->config[29] = Gen4PollerDirectWriteBlock0ModeDisabled;
+            instance->config.data_parsed.gtu_mode = Gen4ShadowModeHighSpeedDisabled;
+            instance->config.data_parsed.atqa[0] = iso3_data->atqa[0];
+            instance->config.data_parsed.atqa[1] = iso3_data->atqa[1];
+            instance->config.data_parsed.sak = iso3_data->sak;
+            //instance->config.data_parsed.mfu_mode = Gen4UltralightModeUL_EV1;
+            instance->config.data_parsed.total_blocks = instance->total_blocks - 1;
+            instance->config.data_parsed.direct_write_mode = Gen4DirectWriteBlock0ModeDisabled;
 
             Gen4PollerError error = gen4_poller_set_config(
-                instance, instance->password, instance->config, sizeof(instance->config), false);
+                instance, instance->password, &instance->config, GEN4_CONFIG_SIZE, false);
             if(error != Gen4PollerErrorNone) {
                 FURI_LOG_D(TAG, "Failed to write config: %d", error);
                 instance->state = Gen4PollerStateFail;
@@ -420,6 +473,47 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) {
                 break;
             }
 
+            // Password
+            MfUltralightConfigPages* config_pages = malloc(sizeof(MfUltralightConfigPages));
+            mf_ultralight_get_config_page(mfu_data, &config_pages);
+
+            block[0] = config_pages->password.data[0];
+            block[1] = config_pages->password.data[1];
+            block[2] = config_pages->password.data[2];
+            block[3] = config_pages->password.data[3];
+            error = gen4_poller_write_block(instance, instance->password, 0xE5, block);
+            if(error != Gen4PollerErrorNone) {
+                FURI_LOG_E(TAG, "Failed to write Password to sector E5");
+                instance->state = Gen4PollerStateFail;
+                break;
+            }
+            error = gen4_poller_write_block(instance, instance->password, 0xF0, block);
+            if(error != Gen4PollerErrorNone) {
+                FURI_LOG_E(TAG, "Failed to write Password to sector F0");
+                instance->state = Gen4PollerStateFail;
+                break;
+            }
+
+            // PACK
+            block[0] = config_pages->pack.data[0];
+            block[1] = config_pages->pack.data[1];
+            block[2] = 0x00;
+            block[3] = 0x00;
+            error = gen4_poller_write_block(instance, instance->password, 0xE6, block);
+            if(error != Gen4PollerErrorNone) {
+                FURI_LOG_E(TAG, "Failed to write PACK to sector E6");
+                instance->state = Gen4PollerStateFail;
+                break;
+            }
+            error = gen4_poller_write_block(instance, instance->password, 0xF1, block);
+            if(error != Gen4PollerErrorNone) {
+                FURI_LOG_E(TAG, "Failed to write PACK to sector F1");
+                instance->state = Gen4PollerStateFail;
+                break;
+            }
+
+            free(config_pages);
+
             instance->state = Gen4PollerStateSuccess;
         }
     } while(false);
@@ -430,11 +524,14 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) {
 NfcCommand gen4_poller_write_handler(Gen4Poller* instance) {
     NfcCommand command = NfcCommandContinue;
 
-    memcpy(instance->config, gen4_poller_default_config, sizeof(gen4_poller_default_config));
-    uint8_t password_arr[4] = {};
-    bit_lib_num_to_bytes_be(instance->password, sizeof(password_arr), password_arr);
-    memcpy(&instance->config[2], password_arr, sizeof(password_arr));
-    memset(&instance->config[7], 0, 17);
+    memcpy(
+        instance->config.data_raw,
+        gen4_poller_default_config.data_raw,
+        GEN4_POLLER_DEFAULT_CONFIG_SIZE);
+
+    memcpy(
+        instance->config.data_parsed.password.bytes, instance->password.bytes, GEN4_PASSWORD_LEN);
+    memset(&instance->config.data_raw[7], 0, 17);
     if(instance->protocol == NfcProtocolMfClassic) {
         command = gen4_poller_write_mf_classic(instance);
     } else if(instance->protocol == NfcProtocolMfUltralight) {
@@ -454,7 +551,7 @@ NfcCommand gen4_poller_change_password_handler(Gen4Poller* instance) {
         command = instance->callback(instance->gen4_event, instance->context);
         if(command != NfcCommandContinue) break;
 
-        uint32_t new_password = instance->gen4_event_data.request_password.password;
+        Gen4Password new_password = instance->gen4_event_data.request_password.password;
         Gen4PollerError error =
             gen4_poller_change_password(instance, instance->password, new_password);
         if(error != Gen4PollerErrorNone) {
@@ -477,8 +574,8 @@ NfcCommand gen4_poller_set_default_cfg_handler(Gen4Poller* instance) {
         Gen4PollerError error = gen4_poller_set_config(
             instance,
             instance->password,
-            gen4_poller_default_config,
-            sizeof(gen4_poller_default_config),
+            &gen4_poller_default_config,
+            GEN4_POLLER_DEFAULT_CONFIG_SIZE,
             false);
         if(error != Gen4PollerErrorNone) {
             FURI_LOG_E(TAG, "Failed to set default config: %d", error);
@@ -496,16 +593,16 @@ NfcCommand gen4_poller_get_current_cfg_handler(Gen4Poller* instance) {
     NfcCommand command = NfcCommandContinue;
 
     do {
-        uint8_t config[32] = {};
+        Gen4Config config;
 
-        Gen4PollerError error = gen4_poller_get_config(instance, instance->password, config);
+        Gen4PollerError error = gen4_poller_get_config(instance, instance->password, &config);
         if(error != Gen4PollerErrorNone) {
             FURI_LOG_E(TAG, "Failed to get current config: %d", error);
             instance->state = Gen4PollerStateFail;
             break;
         }
         // Copy config data to event data buffer
-        memcpy(instance->gen4_event_data.config_data, config, sizeof(config));
+        memcpy(instance->gen4_data->config.data_raw, config.data_raw, sizeof(config));
 
         instance->state = Gen4PollerStateSuccess;
     } while(false);
@@ -517,15 +614,15 @@ NfcCommand gen4_poller_get_revision_handler(Gen4Poller* instance) {
     NfcCommand command = NfcCommandContinue;
 
     do {
-        uint8_t revision[5] = {0};
-        Gen4PollerError error = gen4_poller_get_revision(instance, instance->password, revision);
+        Gen4Revision revision;
+        Gen4PollerError error = gen4_poller_get_revision(instance, instance->password, &revision);
         if(error != Gen4PollerErrorNone) {
             FURI_LOG_E(TAG, "Failed to get revision: %d", error);
             instance->state = Gen4PollerStateFail;
             break;
         }
         // Copy revision data to event data buffer
-        memcpy(instance->gen4_event_data.revision_data, revision, sizeof(revision));
+        memcpy(instance->gen4_data->revision.data, revision.data, sizeof(revision));
 
         instance->state = Gen4PollerStateSuccess;
     } while(false);
@@ -537,27 +634,25 @@ NfcCommand gen4_poller_get_info_handler(Gen4Poller* instance) {
     NfcCommand command = NfcCommandContinue;
 
     do {
-        uint8_t revision[5] = {0};
-        uint8_t config[32] = {0};
+        Gen4 gen4_data;
 
-        Gen4PollerError error = gen4_poller_get_revision(instance, instance->password, revision);
+        Gen4PollerError error =
+            gen4_poller_get_revision(instance, instance->password, &gen4_data.revision);
         if(error != Gen4PollerErrorNone) {
             FURI_LOG_E(TAG, "Failed to get revision: %d", error);
             instance->state = Gen4PollerStateFail;
             break;
         }
 
-        error = gen4_poller_get_config(instance, instance->password, config);
+        error = gen4_poller_get_config(instance, instance->password, &gen4_data.config);
         if(error != Gen4PollerErrorNone) {
             FURI_LOG_E(TAG, "Failed to get current config: %d", error);
             instance->state = Gen4PollerStateFail;
             break;
         }
 
-        // Copy config data to event data buffer
-        memcpy(instance->gen4_event_data.config_data, config, sizeof(config));
-        // Copy revision data to event data buffer
-        memcpy(instance->gen4_event_data.revision_data, revision, sizeof(revision));
+        // Copy config&&revision data to event data buffer
+        gen4_copy(instance->gen4_data, &gen4_data);
 
         instance->state = Gen4PollerStateSuccess;
     } while(false);

+ 6 - 8
nfc_magic/lib/magic/protocols/gen4/gen4_poller.h

@@ -1,5 +1,6 @@
 #pragma once
 
+#include "protocols/gen4/gen4.h"
 #include <nfc/nfc.h>
 #include <nfc/protocols/nfc_protocol.h>
 #include <nfc/protocols/mf_classic/mf_classic.h>
@@ -9,8 +10,10 @@
 extern "C" {
 #endif
 
+// TODO: cleanup, check gen4_poller_i.c defines
 #define GEN4_CMD_PREFIX (0xCF)
 #define GEN4_CMD_GET_CFG (0xC6)
+#define GEN4_CMD_GET_REVISION (0xCC)
 #define GEN4_CMD_WRITE (0xCD)
 #define GEN4_CMD_READ (0xCE)
 #define GEN4_CMD_SET_CFG (0xF0)
@@ -55,18 +58,13 @@ typedef struct {
 } Gen4PollerEventDataRequestDataToWrite;
 
 typedef struct {
-    uint32_t password;
+    Gen4Password password;
 } Gen4PollerEventDataRequestNewPassword;
 
 typedef union {
     Gen4PollerEventDataRequestMode request_mode;
     Gen4PollerEventDataRequestDataToWrite request_data;
     Gen4PollerEventDataRequestNewPassword request_password;
-
-    struct {
-        uint8_t config_data[32];
-        uint8_t revision_data[5];
-    };
 } Gen4PollerEventData;
 
 typedef struct {
@@ -78,13 +76,13 @@ typedef NfcCommand (*Gen4PollerCallback)(Gen4PollerEvent event, void* context);
 
 typedef struct Gen4Poller Gen4Poller;
 
-Gen4PollerError gen4_poller_detect(Nfc* nfc, uint32_t password);
+Gen4PollerError gen4_poller_detect(Nfc* nfc, Gen4Password password, Gen4* gen4_data);
 
 Gen4Poller* gen4_poller_alloc(Nfc* nfc);
 
 void gen4_poller_free(Gen4Poller* instance);
 
-void gen4_poller_set_password(Gen4Poller* instance, uint32_t password);
+void gen4_poller_set_password(Gen4Poller* instance, Gen4Password password);
 
 void gen4_poller_start(Gen4Poller* instance, Gen4PollerCallback callback, void* context);
 

+ 59 - 95
nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.c

@@ -1,6 +1,7 @@
 #include "gen4_poller_i.h"
 
 #include "bit_buffer.h"
+#include "protocols/gen4/gen4.h"
 #include "protocols/gen4/gen4_poller.h"
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
 
@@ -16,40 +17,28 @@
 #define GEN4_CMD_FUSE_CFG (0xF1)
 #define GEN4_CMD_SET_PWD (0xFE)
 
-#define GEM4_RESPONSE_SUCCESS (0x02)
+#define GEN4_RESPONSE_SUCCESS (0x02)
 
-#define CONFIG_SIZE_MAX (32)
-#define CONFIG_SIZE_MIN (30)
-#define REVISION_SIZE (5)
-
-static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error)
-{
+static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
     Gen4PollerError ret = Gen4PollerErrorNone;
 
-    if (error == Iso14443_3aErrorNone)
-    {
+    if(error == Iso14443_3aErrorNone) {
         ret = Gen4PollerErrorNone;
-    }
-    else
-    {
+    } else {
         ret = Gen4PollerErrorTimeout;
     }
 
     return ret;
 }
 
-Gen4PollerError gen4_poller_set_shadow_mode(
-    Gen4Poller* instance,
-    uint32_t password,
-    Gen4PollerShadowMode mode) {
+Gen4PollerError
+    gen4_poller_set_shadow_mode(Gen4Poller* instance, Gen4Password password, Gen4ShadowMode mode) {
     Gen4PollerError ret = Gen4PollerErrorNone;
     bit_buffer_reset(instance->tx_buffer);
 
     do {
-        uint8_t password_arr[4] = {};
-        bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr);
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
-        bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
+        bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN);
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_SHD_MODE);
         bit_buffer_append_byte(instance->tx_buffer, mode);
 
@@ -65,7 +54,7 @@ Gen4PollerError gen4_poller_set_shadow_mode(
 
         FURI_LOG_D(TAG, "Card response: 0x%02X, Shadow mode set: 0x%02X", response, mode);
 
-        if(response != GEM4_RESPONSE_SUCCESS) {
+        if(response != GEN4_RESPONSE_SUCCESS) {
             ret = Gen4PollerErrorProtocol;
             break;
         }
@@ -77,16 +66,14 @@ Gen4PollerError gen4_poller_set_shadow_mode(
 
 Gen4PollerError gen4_poller_set_direct_write_block_0_mode(
     Gen4Poller* instance,
-    uint32_t password,
-    Gen4PollerDirectWriteBlock0Mode mode) {
+    Gen4Password password,
+    Gen4DirectWriteBlock0Mode mode) {
     Gen4PollerError ret = Gen4PollerErrorNone;
     bit_buffer_reset(instance->tx_buffer);
 
     do {
-        uint8_t password_arr[4] = {};
-        bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr);
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
-        bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
+        bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN);
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_DW_BLOCK_0);
         bit_buffer_append_byte(instance->tx_buffer, mode);
 
@@ -102,7 +89,7 @@ Gen4PollerError gen4_poller_set_direct_write_block_0_mode(
         FURI_LOG_D(
             TAG, "Card response: 0x%02X, Direct write to block 0 mode set: 0x%02X", response, mode);
 
-        if(response != GEM4_RESPONSE_SUCCESS) {
+        if(response != GEN4_RESPONSE_SUCCESS) {
             ret = Gen4PollerErrorProtocol;
             break;
         }
@@ -113,99 +100,86 @@ Gen4PollerError gen4_poller_set_direct_write_block_0_mode(
 }
 
 Gen4PollerError
-gen4_poller_get_config(Gen4Poller *instance, uint32_t password, uint8_t *config_result)
-{
+    gen4_poller_get_config(Gen4Poller* instance, Gen4Password password, Gen4Config* config_result) {
     Gen4PollerError ret = Gen4PollerErrorNone;
     bit_buffer_reset(instance->tx_buffer);
 
-    do
-    {
-        uint8_t password_arr[4] = {};
-        bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr);
+    do {
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
-        bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
+        bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN);
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_GET_CFG);
 
         Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
             instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
 
-        if (error != Iso14443_3aErrorNone)
-        {
+        if(error != Iso14443_3aErrorNone) {
             ret = gen4_poller_process_error(error);
             break;
         }
 
         size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
 
-        if((rx_bytes != CONFIG_SIZE_MAX) && (rx_bytes != CONFIG_SIZE_MIN)) {
+        if((rx_bytes != GEN4_CONFIG_SIZE)) {
             ret = Gen4PollerErrorProtocol;
             break;
         }
-        bit_buffer_write_bytes(instance->rx_buffer, config_result, CONFIG_SIZE_MAX);
+        bit_buffer_write_bytes(instance->rx_buffer, config_result->data_raw, GEN4_CONFIG_SIZE);
     } while(false);
 
     return ret;
 }
 
-Gen4PollerError
-gen4_poller_get_revision(Gen4Poller *instance, uint32_t password, uint8_t *revision_result)
-{
+Gen4PollerError gen4_poller_get_revision(
+    Gen4Poller* instance,
+    Gen4Password password,
+    Gen4Revision* revision_result) {
     Gen4PollerError ret = Gen4PollerErrorNone;
     bit_buffer_reset(instance->tx_buffer);
 
-    do
-    {
-        uint8_t password_arr[4] = {};
-        bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr);
+    do {
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
-        bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
+        bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN);
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_GET_REVISION);
 
         Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
             instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
 
-        if (error != Iso14443_3aErrorNone)
-        {
+        if(error != Iso14443_3aErrorNone) {
             ret = gen4_poller_process_error(error);
             break;
         }
 
         size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
-        if(rx_bytes != REVISION_SIZE) {
+        if(rx_bytes != GEN4_REVISION_SIZE) {
             ret = Gen4PollerErrorProtocol;
             break;
         }
-        bit_buffer_write_bytes(instance->rx_buffer, revision_result, REVISION_SIZE);
-    } while (false);
+        bit_buffer_write_bytes(instance->rx_buffer, revision_result->data, GEN4_REVISION_SIZE);
+    } while(false);
 
     return ret;
 }
 
 Gen4PollerError gen4_poller_set_config(
-    Gen4Poller *instance,
-    uint32_t password,
-    const uint8_t *config,
+    Gen4Poller* instance,
+    Gen4Password password,
+    const Gen4Config* config,
     size_t config_size,
-    bool fuse)
-{
+    bool fuse) {
     Gen4PollerError ret = Gen4PollerErrorNone;
     bit_buffer_reset(instance->tx_buffer);
 
-    do
-    {
-        uint8_t password_arr[4] = {};
-        bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr);
+    do {
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
-        bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
+        bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN);
         uint8_t fuse_config = fuse ? GEN4_CMD_FUSE_CFG : GEN4_CMD_SET_CFG;
         bit_buffer_append_byte(instance->tx_buffer, fuse_config);
-        bit_buffer_append_bytes(instance->tx_buffer, config, config_size);
+        bit_buffer_append_bytes(instance->tx_buffer, config->data_raw, config_size);
 
         Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
             instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
 
-        if (error != Iso14443_3aErrorNone)
-        {
+        if(error != Iso14443_3aErrorNone) {
             ret = gen4_poller_process_error(error);
             break;
         }
@@ -214,30 +188,26 @@ Gen4PollerError gen4_poller_set_config(
 
         FURI_LOG_D(TAG, "Card response to set default config command: 0x%02X", response);
 
-        if(response != GEM4_RESPONSE_SUCCESS) {
+        if(response != GEN4_RESPONSE_SUCCESS) {
             ret = Gen4PollerErrorProtocol;
             break;
         }
-    } while (false);
+    } while(false);
 
     return ret;
 }
 
 Gen4PollerError gen4_poller_write_block(
-    Gen4Poller *instance,
-    uint32_t password,
+    Gen4Poller* instance,
+    Gen4Password password,
     uint8_t block_num,
-    const uint8_t *data)
-{
+    const uint8_t* data) {
     Gen4PollerError ret = Gen4PollerErrorNone;
     bit_buffer_reset(instance->tx_buffer);
 
-    do
-    {
-        uint8_t password_arr[4] = {};
-        bit_lib_num_to_bytes_be(password, COUNT_OF(password_arr), password_arr);
+    do {
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
-        bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
+        bit_buffer_append_bytes(instance->tx_buffer, password.bytes, GEN4_PASSWORD_LEN);
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_WRITE);
         bit_buffer_append_byte(instance->tx_buffer, block_num);
         bit_buffer_append_bytes(instance->tx_buffer, data, GEN4_POLLER_BLOCK_SIZE);
@@ -245,45 +215,39 @@ Gen4PollerError gen4_poller_write_block(
         Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
             instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
 
-        if (error != Iso14443_3aErrorNone)
-        {
+        if(error != Iso14443_3aErrorNone) {
             ret = gen4_poller_process_error(error);
             break;
         }
 
         size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
-        if (rx_bytes != 2)
-        {
+        if(rx_bytes != 2) {
             ret = Gen4PollerErrorProtocol;
             break;
         }
-    } while (false);
+    } while(false);
 
     return ret;
 }
 
-Gen4PollerError
-gen4_poller_change_password(Gen4Poller *instance, uint32_t pwd_current, uint32_t pwd_new)
-{
+Gen4PollerError gen4_poller_change_password(
+    Gen4Poller* instance,
+    Gen4Password pwd_current,
+    Gen4Password pwd_new) {
     Gen4PollerError ret = Gen4PollerErrorNone;
     bit_buffer_reset(instance->tx_buffer);
 
-    do
-    {
-        uint8_t password_arr[4] = {};
-        bit_lib_num_to_bytes_be(pwd_current, COUNT_OF(password_arr), password_arr);
+    do {
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
-        bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
+        bit_buffer_append_bytes(instance->tx_buffer, pwd_current.bytes, GEN4_PASSWORD_LEN);
 
         bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_PWD);
-        bit_lib_num_to_bytes_be(pwd_new, COUNT_OF(password_arr), password_arr);
-        bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
+        bit_buffer_append_bytes(instance->tx_buffer, pwd_new.bytes, GEN4_PASSWORD_LEN);
 
         Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
             instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
 
-        if (error != Iso14443_3aErrorNone)
-        {
+        if(error != Iso14443_3aErrorNone) {
             ret = gen4_poller_process_error(error);
             break;
         }
@@ -293,15 +257,15 @@ gen4_poller_change_password(Gen4Poller *instance, uint32_t pwd_current, uint32_t
         FURI_LOG_D(
             TAG,
             "Trying to change password from 0x%08lX to 0x%08lX. Card response: 0x%02X",
-            pwd_current,
-            pwd_new,
+            pwd_current.value,
+            pwd_new.value,
             response);
 
-        if(response != GEM4_RESPONSE_SUCCESS) {
+        if(response != GEN4_RESPONSE_SUCCESS) {
             ret = Gen4PollerErrorProtocol;
             break;
         }
-    } while (false);
+    } while(false);
 
     return ret;
 }

+ 26 - 56
nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h

@@ -1,9 +1,10 @@
 #pragma once
 
+#include "gen4.h"
 #include "gen4_poller.h"
 #include <nfc/nfc_poller.h>
 #include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
-#include <bit_lib.h>
+#include <bit_lib/bit_lib.h>
 
 #define TAG "Gen4Poller"
 
@@ -17,43 +18,6 @@ extern "C" {
 #define GEN4_POLLER_BLOCK_SIZE (16)
 #define GEN4_POLLER_BLOCKS_TOTAL (256)
 
-#define GEN4_POLLER_CONFIG_SIZE_MAX (30)
-
-typedef enum {
-    Gen4PollerUIDLengthSingle = 0x00,
-    Gen4PollerUIDLengthDouble = 0x01,
-    Gen4PollerUIDLengthTriple = 0x02
-} Gen4PollerUIDLength;
-
-typedef enum {
-    Gen4PollerUltralightModeUL_EV1 = 0x00,
-    Gen4PollerUltralightModeNTAG = 0x01,
-    Gen4PollerUltralightModeUL_C = 0x02,
-    Gen4PollerUltralightModeUL = 0x03
-} Gen4PollerUltralightMode;
-
-typedef enum {
-    // for writing original (shadow) data
-    Gen4PollerShadowModePreWrite = 0x00,
-    // written data can be read once before restored to original
-    Gen4PollerShadowModeRestore = 0x01,
-    // shadow mode disabled
-    Gen4PollerShadowModeDisabled = 0x02,
-    // apparently for UL?
-    Gen4PollerShadowModeHighSpeedDisabled = 0x03,
-    // work with new UMC. With old UMC is untested
-    Gen4PollerShadowModeSplit = 0x04,
-} Gen4PollerShadowMode;
-
-typedef enum {
-    // gen2 card behavour
-    Gen4PollerDirectWriteBlock0ModeEnabled = 0x00,
-    // common card behavour
-    Gen4PollerDirectWriteBlock0ModeDisabled = 0x01,
-    // default mode. same behavour as Gen4PollerDirectWriteBlock0ModeActivate
-    Gen4PollerDirectWriteBlock0ModeDefault = 0x02,
-} Gen4PollerDirectWriteBlock0Mode;
-
 typedef enum {
     Gen4PollerStateIdle,
     Gen4PollerStateRequestMode,
@@ -77,7 +41,15 @@ struct Gen4Poller {
     NfcPoller* poller;
     Iso14443_3aPoller* iso3_poller;
     Gen4PollerState state;
-    uint32_t password;
+
+    Gen4* gen4_data;
+
+    Gen4Password password;
+
+    Gen4Password new_password;
+    Gen4Config config;
+    Gen4ShadowMode shadow_mode;
+    Gen4DirectWriteBlock0Mode direct_write_block_0_mode;
 
     BitBuffer* tx_buffer;
     BitBuffer* rx_buffer;
@@ -87,12 +59,6 @@ struct Gen4Poller {
 
     NfcProtocol protocol;
     const NfcDeviceData* data;
-    uint32_t new_password;
-
-    uint8_t config[GEN4_POLLER_CONFIG_SIZE_MAX];
-
-    Gen4PollerShadowMode shadow_mode;
-    Gen4PollerDirectWriteBlock0Mode direct_write_block_0_mode;
 
     Gen4PollerEvent gen4_event;
     Gen4PollerEventData gen4_event_data;
@@ -103,33 +69,37 @@ struct Gen4Poller {
 
 Gen4PollerError gen4_poller_set_config(
     Gen4Poller* instance,
-    uint32_t password,
-    const uint8_t* config,
+    Gen4Password password,
+    const Gen4Config* config,
     size_t config_size,
     bool fuse);
 
 Gen4PollerError gen4_poller_write_block(
     Gen4Poller* instance,
-    uint32_t password,
+    Gen4Password password,
     uint8_t block_num,
     const uint8_t* data);
 
-Gen4PollerError
-    gen4_poller_change_password(Gen4Poller* instance, uint32_t pwd_current, uint32_t pwd_new);
+Gen4PollerError gen4_poller_change_password(
+    Gen4Poller* instance,
+    Gen4Password pwd_current,
+    Gen4Password pwd_new);
 
-Gen4PollerError
-    gen4_poller_get_revision(Gen4Poller* instance, uint32_t password, uint8_t* revision_result);
+Gen4PollerError gen4_poller_get_revision(
+    Gen4Poller* instance,
+    Gen4Password password,
+    Gen4Revision* revision_result);
 
 Gen4PollerError
-    gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result);
+    gen4_poller_get_config(Gen4Poller* instance, Gen4Password password, Gen4Config* config_result);
 
 Gen4PollerError
-    gen4_poller_set_shadow_mode(Gen4Poller* instance, uint32_t password, Gen4PollerShadowMode mode);
+    gen4_poller_set_shadow_mode(Gen4Poller* instance, Gen4Password password, Gen4ShadowMode mode);
 
 Gen4PollerError gen4_poller_set_direct_write_block_0_mode(
     Gen4Poller* instance,
-    uint32_t password,
-    Gen4PollerDirectWriteBlock0Mode mode);
+    Gen4Password password,
+    Gen4DirectWriteBlock0Mode mode);
 
 #ifdef __cplusplus
 }

+ 2 - 4
nfc_magic/lib/magic/protocols/nfc_magic_protocols.c

@@ -3,10 +3,8 @@
 #include <furi/furi.h>
 
 static const char* nfc_magic_protocol_names[NfcMagicProtocolNum] = {
-    [NfcMagicProtocolGen1] = "Gen1A/B",
-    [NfcMagicProtocolGen2] = "Gen2",
-    [NfcMagicProtocolClassic] = "MIFARE Classic",
-    [NfcMagicProtocolGen4] = "Gen4 GTU",
+    [NfcMagicProtocolGen1] = "Classic Gen 1A/B",
+    [NfcMagicProtocolGen4] = "Gen 4 GTU",
 };
 
 const char* nfc_magic_protocols_get_name(NfcMagicProtocol protocol) {

+ 0 - 2
nfc_magic/lib/magic/protocols/nfc_magic_protocols.h

@@ -6,9 +6,7 @@ extern "C" {
 
 typedef enum {
     NfcMagicProtocolGen1,
-    NfcMagicProtocolGen2,
     NfcMagicProtocolGen4,
-    NfcMagicProtocolClassic, // Last to give priority to the others
 
     NfcMagicProtocolNum,
     NfcMagicProtocolInvalid,

+ 6 - 29
nfc_magic/nfc_magic_app.c

@@ -1,4 +1,5 @@
 #include "nfc_magic_app_i.h"
+#include "protocols/gen4/gen4.h"
 
 bool nfc_magic_app_custom_event_callback(void* context, uint32_t event) {
     furi_assert(context);
@@ -48,16 +49,13 @@ NfcMagicApp* nfc_magic_app_alloc() {
     view_dispatcher_set_tick_event_callback(
         instance->view_dispatcher, nfc_magic_app_tick_event_callback, 100);
 
-    // NFC source device (file)
+    // Nfc device
     instance->source_dev = nfc_device_alloc();
     nfc_device_set_loading_callback(
         instance->source_dev, nfc_magic_app_show_loading_popup, instance);
     instance->file_path = furi_string_alloc_set(NFC_APP_FOLDER);
     instance->file_name = furi_string_alloc();
 
-    // NFC target device (tag)
-    instance->target_dev = nfc_device_alloc();
-
     // Open GUI record
     instance->gui = furi_record_open(RECORD_GUI);
     view_dispatcher_attach_to_gui(
@@ -106,19 +104,7 @@ NfcMagicApp* nfc_magic_app_alloc() {
     view_dispatcher_add_view(
         instance->view_dispatcher, NfcMagicAppViewWidget, widget_get_view(instance->widget));
 
-    // Dict attack
-    instance->dict_attack = dict_attack_alloc();
-    view_dispatcher_add_view(
-        instance->view_dispatcher,
-        NfcMagicAppViewDictAttack,
-        dict_attack_get_view(instance->dict_attack));
-
-    // Write problems
-    instance->write_problems = write_problems_alloc();
-    view_dispatcher_add_view(
-        instance->view_dispatcher,
-        NfcMagicAppViewWriteProblems,
-        write_problems_get_view(instance->write_problems));
+    instance->gen4_data = gen4_alloc();
 
     instance->nfc = nfc_alloc();
     instance->scanner = nfc_magic_scanner_alloc(instance->nfc);
@@ -129,14 +115,11 @@ NfcMagicApp* nfc_magic_app_alloc() {
 void nfc_magic_app_free(NfcMagicApp* instance) {
     furi_assert(instance);
 
-    // Nfc source device
+    // Nfc device
     nfc_device_free(instance->source_dev);
     furi_string_free(instance->file_name);
     furi_string_free(instance->file_path);
 
-    // Nfc target device
-    nfc_device_free(instance->target_dev);
-
     // Submenu
     view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewMenu);
     submenu_free(instance->submenu);
@@ -161,14 +144,6 @@ void nfc_magic_app_free(NfcMagicApp* instance) {
     view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewWidget);
     widget_free(instance->widget);
 
-    // Dict attack
-    view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewDictAttack);
-    dict_attack_free(instance->dict_attack);
-
-    // Write problems
-    view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewWriteProblems);
-    write_problems_free(instance->write_problems);
-
     // View Dispatcher
     view_dispatcher_free(instance->view_dispatcher);
 
@@ -191,6 +166,8 @@ void nfc_magic_app_free(NfcMagicApp* instance) {
     furi_record_close(RECORD_STORAGE);
     instance->storage = NULL;
 
+    gen4_free(instance->gen4_data);
+
     nfc_magic_scanner_free(instance->scanner);
     nfc_free(instance->nfc);
 

+ 3 - 54
nfc_magic/nfc_magic_app_i.h

@@ -15,8 +15,6 @@
 #include <gui/modules/text_input.h>
 #include <gui/modules/byte_input.h>
 #include <gui/modules/widget.h>
-#include <views/dict_attack.h>
-#include <views/write_problems.h>
 
 #include <input/input.h>
 
@@ -28,28 +26,18 @@
 
 #include "nfc_magic_icons.h"
 
-#include <assets_icons.h>
-
 #include <nfc/nfc.h>
 #include <nfc/nfc_device.h>
-#include <nfc/nfc_poller.h>
-#include <toolbox/keys_dict.h>
 
 #include "lib/magic/nfc_magic_scanner.h"
 #include "lib/magic/protocols/nfc_magic_protocols.h"
 #include "lib/magic/protocols/gen1a/gen1a_poller.h"
-#include "lib/magic/protocols/gen2/gen2_poller.h"
 #include "lib/magic/protocols/gen4/gen4_poller.h"
 
-#include "lib/nfc/protocols/mf_classic/mf_classic_poller.h"
-
 #define NFC_APP_FOLDER ANY_PATH("nfc")
 #define NFC_APP_EXTENSION ".nfc"
 #define NFC_APP_SHADOW_EXTENSION ".shd"
 
-#define NFC_APP_MF_CLASSIC_DICT_USER_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict_user.nfc")
-#define NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict.nfc")
-
 #define NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE (4)
 
 enum NfcMagicAppCustomEvent {
@@ -60,33 +48,8 @@ enum NfcMagicAppCustomEvent {
     NfcMagicAppCustomEventWorkerExit,
     NfcMagicAppCustomEventByteInputDone,
     NfcMagicAppCustomEventTextInputDone,
-    NfcMagicAppCustomEventCardDetected,
-    NfcMagicAppCustomEventCardLost,
-    NfcMagicAppCustomEventDictAttackDataUpdate,
-    NfcMagicAppCustomEventDictAttackComplete,
-    NfcMagicAppCustomEventDictAttackSkip,
 };
 
-typedef struct {
-    KeysDict* dict;
-    uint8_t sectors_total;
-    uint8_t sectors_read;
-    uint8_t current_sector;
-    uint8_t keys_found;
-    size_t dict_keys_total;
-    size_t dict_keys_current;
-    bool is_key_attack;
-    uint8_t key_attack_current_sector;
-    bool is_card_present;
-} NfcMagicAppMfClassicDictAttackContext;
-
-typedef struct {
-    uint8_t problem_index;
-    uint8_t problem_index_abs;
-    uint8_t problems_total;
-    Gen2PollerWriteProblems problems;
-} NfcMagicAppWriteProblemsContext;
-
 struct NfcMagicApp {
     ViewDispatcher* view_dispatcher;
     Gui* gui;
@@ -96,31 +59,19 @@ struct NfcMagicApp {
 
     SceneManager* scene_manager;
     NfcDevice* source_dev;
-    NfcDevice* target_dev;
     FuriString* file_name;
     FuriString* file_path;
 
     Nfc* nfc;
     NfcMagicProtocol protocol;
     NfcMagicScanner* scanner;
-    NfcPoller* poller;
     Gen1aPoller* gen1a_poller;
-
-    Gen2Poller* gen2_poller;
-    bool gen2_poller_is_wipe_mode;
-
     Gen4Poller* gen4_poller;
 
-    NfcMagicAppMfClassicDictAttackContext nfc_dict_context;
-    DictAttack* dict_attack;
-    NfcMagicAppWriteProblemsContext write_problems_context;
-    WriteProblems* write_problems;
-
-    uint32_t gen4_password;
-    uint32_t gen4_password_new;
+    Gen4* gen4_data;
 
-    uint8_t gen4_config[32];
-    uint8_t gen4_revision[5];
+    Gen4Password gen4_password;
+    Gen4Password gen4_password_new;
 
     FuriString* text_box_store;
     uint8_t byte_input_store[NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE];
@@ -141,8 +92,6 @@ typedef enum {
     NfcMagicAppViewTextInput,
     NfcMagicAppViewByteInput,
     NfcMagicAppViewWidget,
-    NfcMagicAppViewDictAttack,
-    NfcMagicAppViewWriteProblems,
 } NfcMagicAppView;
 
 void nfc_magic_app_blink_start(NfcMagicApp* nfc_magic);

+ 0 - 6
nfc_magic/scenes/nfc_magic_scene_config.h

@@ -11,7 +11,6 @@ ADD_SCENE(nfc_magic, gen4_show_cfg, Gen4ShowCfg)
 ADD_SCENE(nfc_magic, gen4_show_info, Gen4ShowInfo)
 ADD_SCENE(nfc_magic, gen4_select_shd_mode, Gen4SelectShdMode)
 ADD_SCENE(nfc_magic, gen4_set_shd_mode, Gen4SetShdMode)
-ADD_SCENE(nfc_magic, gen4_select_direct_write_block_0_mode, Gen4SelectDirectWriteBlock0Mode)
 ADD_SCENE(nfc_magic, gen4_set_direct_write_block_0_mode, Gen4SetDirectWriteBlock0Mode)
 ADD_SCENE(nfc_magic, gen4_fail, Gen4Fail)
 ADD_SCENE(nfc_magic, wipe, Wipe)
@@ -25,8 +24,3 @@ ADD_SCENE(nfc_magic, change_key, ChangeKey)
 ADD_SCENE(nfc_magic, change_key_fail, ChangeKeyFail)
 ADD_SCENE(nfc_magic, wrong_card, WrongCard)
 ADD_SCENE(nfc_magic, not_magic, NotMagic)
-ADD_SCENE(nfc_magic, gen2_menu, Gen2Menu)
-ADD_SCENE(nfc_magic, mf_classic_menu, MfClassicMenu)
-ADD_SCENE(nfc_magic, mf_classic_dict_attack, MfClassicDictAttack)
-ADD_SCENE(nfc_magic, gen2_write_check, Gen2WriteCheck)
-ADD_SCENE(nfc_magic, mf_classic_write_check, MfClassicWriteCheck)

+ 1 - 15
nfc_magic/scenes/nfc_magic_scene_file_select.c

@@ -30,14 +30,6 @@ static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagicApp* instance)
                            (mfu_type != MfUltralightTypeNTAGI2CPlus2K);
             }
         }
-    } else if(instance->protocol == NfcMagicProtocolGen2) {
-        if(protocol == NfcProtocolMfClassic) {
-            suitable = true;
-        }
-    } else if(instance->protocol == NfcMagicProtocolClassic) {
-        if(protocol == NfcProtocolMfClassic) {
-            suitable = true;
-        }
     }
 
     return suitable;
@@ -48,13 +40,7 @@ void nfc_magic_scene_file_select_on_enter(void* context) {
 
     if(nfc_magic_load_from_file_select(instance)) {
         if(nfc_magic_scene_file_select_is_file_suitable(instance)) {
-            if(instance->protocol == NfcMagicProtocolClassic ||
-               instance->protocol == NfcMagicProtocolGen2) {
-                scene_manager_next_scene(
-                    instance->scene_manager, NfcMagicSceneMfClassicDictAttack);
-            } else {
-                scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWriteConfirm);
-            }
+            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWriteConfirm);
         } else {
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWrongCard);
         }

+ 0 - 55
nfc_magic/scenes/nfc_magic_scene_gen2_menu.c

@@ -1,55 +0,0 @@
-#include "../nfc_magic_app_i.h"
-
-enum SubmenuIndex {
-    SubmenuIndexWrite,
-    SubmenuIndexWipe,
-};
-
-void nfc_magic_scene_gen2_menu_submenu_callback(void* context, uint32_t index) {
-    NfcMagicApp* instance = context;
-
-    view_dispatcher_send_custom_event(instance->view_dispatcher, index);
-}
-
-void nfc_magic_scene_gen2_menu_on_enter(void* context) {
-    NfcMagicApp* instance = context;
-
-    Submenu* submenu = instance->submenu;
-    submenu_add_item(
-        submenu, "Write", SubmenuIndexWrite, nfc_magic_scene_gen2_menu_submenu_callback, instance);
-    submenu_add_item(
-        submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_gen2_menu_submenu_callback, instance);
-
-    submenu_set_selected_item(
-        submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen2Menu));
-    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
-}
-
-bool nfc_magic_scene_gen2_menu_on_event(void* context, SceneManagerEvent event) {
-    NfcMagicApp* instance = context;
-    bool consumed = false;
-
-    if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubmenuIndexWrite) {
-            instance->gen2_poller_is_wipe_mode = false;
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneFileSelect);
-            consumed = true;
-        } else if(event.event == SubmenuIndexWipe) {
-            instance->gen2_poller_is_wipe_mode = true;
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneMfClassicDictAttack);
-            consumed = true;
-        }
-        scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen2Menu, event.event);
-    } else if(event.type == SceneManagerEventTypeBack) {
-        consumed = scene_manager_search_and_switch_to_previous_scene(
-            instance->scene_manager, NfcMagicSceneStart);
-    }
-
-    return consumed;
-}
-
-void nfc_magic_scene_gen2_menu_on_exit(void* context) {
-    NfcMagicApp* instance = context;
-
-    submenu_reset(instance->submenu);
-}

+ 0 - 130
nfc_magic/scenes/nfc_magic_scene_gen2_write_check.c

@@ -1,130 +0,0 @@
-#include "../nfc_magic_app_i.h"
-
-void nfc_magic_scene_gen2_write_check_view_callback(WriteProblemsEvent event, void* context) {
-    NfcMagicApp* instance = context;
-    NfcMagicAppWriteProblemsContext* problems_context = &instance->write_problems_context;
-
-    if(event == WriteProblemsEventCenterPressed) {
-        if(problems_context->problem_index == problems_context->problems_total - 1) {
-            // Continue to the next scene
-            if(instance->gen2_poller_is_wipe_mode) {
-                scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe);
-            } else {
-                scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWrite);
-            }
-        } else {
-            // Move to the next problem
-            problems_context->problem_index++;
-            problems_context->problem_index_abs++;
-            write_problems_set_problem_index(
-                instance->write_problems, problems_context->problem_index);
-
-            for(uint8_t i = problems_context->problem_index_abs;
-                i < GEN2_POLLER_WRITE_PROBLEMS_LEN;
-                i++) {
-                if(problems_context->problems.all_problems & (1 << i)) {
-                    write_problems_set_content(instance->write_problems, gen2_problem_strings[i]);
-                    problems_context->problem_index_abs = i;
-                    break;
-                }
-            }
-        }
-    } else if(event == WriteProblemsEventLeftPressed) {
-        if(problems_context->problem_index == 0) {
-            // Exit to the previous scene
-            scene_manager_search_and_switch_to_previous_scene(
-                instance->scene_manager, NfcMagicSceneMfClassicMenu);
-        } else {
-            // Move to the previous problem
-            problems_context->problem_index--;
-            problems_context->problem_index_abs--;
-            write_problems_set_problem_index(
-                instance->write_problems, problems_context->problem_index);
-
-            for(uint8_t i = problems_context->problem_index_abs;
-                i < GEN2_POLLER_WRITE_PROBLEMS_LEN;
-                i--) {
-                if(problems_context->problems.all_problems & (1 << i)) {
-                    write_problems_set_content(instance->write_problems, gen2_problem_strings[i]);
-                    problems_context->problem_index_abs = i;
-                    break;
-                }
-            }
-        }
-    }
-}
-
-void nfc_magic_scene_gen2_write_check_on_enter(void* context) {
-    NfcMagicApp* instance = context;
-
-    Gen2PollerWriteProblems problems = gen2_poller_check_target_problems(instance->target_dev);
-    if(!instance->gen2_poller_is_wipe_mode) {
-        problems.all_problems |=
-            gen2_poller_check_source_problems(instance->source_dev).all_problems;
-    }
-
-    WriteProblems* write_problems = instance->write_problems;
-    uint8_t problems_count = 0;
-    uint8_t current_problem = 0;
-    furi_assert(!problems.no_data, "No MFC data in nfc device");
-
-    if(problems.all_problems == 0) {
-        if(instance->gen2_poller_is_wipe_mode) {
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe);
-            return;
-        } else {
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWrite);
-            return;
-        }
-    }
-
-    // Count the total number of problems
-    for(uint8_t i = 0; i < GEN2_POLLER_WRITE_PROBLEMS_LEN; i++) {
-        if(problems.all_problems & (1 << i)) {
-            problems_count++;
-        }
-    }
-
-    // Init the view
-    write_problems_set_callback(
-        write_problems, nfc_magic_scene_gen2_write_check_view_callback, instance);
-    write_problems_set_problems_total(write_problems, problems_count);
-    write_problems_set_problem_index(write_problems, current_problem);
-
-    // Set the initial content to the first problem
-    for(uint8_t i = 0; i < GEN2_POLLER_WRITE_PROBLEMS_LEN; i++) {
-        if(problems.all_problems & (1 << i)) {
-            write_problems_set_content(write_problems, gen2_problem_strings[i]);
-            current_problem = i;
-            break;
-        }
-    }
-
-    // Save the context
-    instance->write_problems_context.problem_index = current_problem;
-    instance->write_problems_context.problems_total = problems_count;
-    instance->write_problems_context.problems = problems;
-
-    // Setup and start worker
-    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWriteProblems);
-}
-
-bool nfc_magic_scene_gen2_write_check_on_event(void* context, SceneManagerEvent event) {
-    NfcMagicApp* instance = context;
-    UNUSED(event);
-    UNUSED(context);
-    UNUSED(instance);
-    bool consumed = false;
-
-    return consumed;
-}
-
-void nfc_magic_scene_gen2_write_check_on_exit(void* context) {
-    NfcMagicApp* instance = context;
-
-    instance->write_problems_context.problem_index = 0;
-    instance->write_problems_context.problems_total = 0;
-    instance->write_problems_context.problems.all_problems = 0;
-
-    write_problems_reset(instance->write_problems);
-}

+ 8 - 3
nfc_magic/scenes/nfc_magic_scene_gen4_get_info.c

@@ -1,4 +1,7 @@
 #include "../nfc_magic_app_i.h"
+//TODO: INCAPSULATE?
+#include "gui/scene_manager.h"
+#include "protocols/gen4/gen4_poller_i.h"
 
 enum {
     NfcMagicSceneGen4GetInfoStateCardSearch,
@@ -18,9 +21,8 @@ NfcCommand nfc_mafic_scene_gen4_get_info_poller_callback(Gen4PollerEvent event,
         event.data->request_mode.mode = Gen4PollerModeGetInfo;
     } else if(event.type == Gen4PollerEventTypeSuccess) {
         // Copy data from event to main instance
-        memcpy(
-            instance->gen4_revision, event.data->revision_data, sizeof(event.data->revision_data));
-        memcpy(instance->gen4_config, event.data->config_data, sizeof(event.data->config_data));
+        // TODO: From event data? or from poller?
+        gen4_copy(instance->gen4_data, instance->gen4_poller->gen4_data);
 
         view_dispatcher_send_custom_event(
             instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
@@ -89,6 +91,9 @@ bool nfc_magic_scene_gen4_get_info_on_event(void* context, SceneManagerEvent eve
             nfc_magic_scene_gen4_get_info_setup_view(instance);
             consumed = true;
         } else if(event.event == NfcMagicCustomEventWorkerSuccess) {
+            // for notification message
+            scene_manager_set_scene_state(
+                instance->scene_manager, NfcMagicSceneGen4ShowInfo, true);
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4ShowInfo);
             consumed = true;
         } else if(event.event == NfcMagicCustomEventWorkerFail) {

+ 29 - 8
nfc_magic/scenes/nfc_magic_scene_gen4_menu.c

@@ -1,4 +1,6 @@
 #include "../nfc_magic_app_i.h"
+#include "gui/scene_manager.h"
+#include "protocols/gen4/gen4.h"
 
 enum SubmenuIndex {
     SubmenuIndexWrite,
@@ -33,12 +35,31 @@ void nfc_magic_scene_gen4_menu_on_enter(void* context) {
         SubmenuIndexSetShadowMode,
         nfc_magic_scene_gen4_menu_submenu_callback,
         instance);
-    submenu_add_item(
-        submenu,
-        "Set Gen2 Mode",
-        SubmenuIndexSetDirectWriteBlock0Mode,
-        nfc_magic_scene_gen4_menu_submenu_callback,
-        instance);
+    if(instance->gen4_data->config.data_parsed.direct_write_mode ==
+       Gen4DirectWriteBlock0ModeEnabled) {
+        submenu_add_item(
+            submenu,
+            "Disable Direct Write Mode",
+            SubmenuIndexSetDirectWriteBlock0Mode,
+            nfc_magic_scene_gen4_menu_submenu_callback,
+            instance);
+        scene_manager_set_scene_state(
+            instance->scene_manager,
+            NfcMagicSceneGen4SetDirectWriteBlock0Mode,
+            Gen4DirectWriteBlock0ModeDisabled);
+    } else {
+        submenu_add_item(
+            submenu,
+            "Enable Direct Write Mode",
+            SubmenuIndexSetDirectWriteBlock0Mode,
+            nfc_magic_scene_gen4_menu_submenu_callback,
+            instance);
+        scene_manager_set_scene_state(
+            instance->scene_manager,
+            NfcMagicSceneGen4SetDirectWriteBlock0Mode,
+            Gen4DirectWriteBlock0ModeEnabled);
+    }
+
     submenu_add_item(
         submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_gen4_menu_submenu_callback, instance);
     submenu_add_item(
@@ -71,13 +92,13 @@ bool nfc_magic_scene_gen4_menu_on_event(void* context, SceneManagerEvent event)
             consumed = true;
         } else if(event.event == SubmenuIndexSetDirectWriteBlock0Mode) {
             scene_manager_next_scene(
-                instance->scene_manager, NfcMagicSceneGen4SelectDirectWriteBlock0Mode);
+                instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode);
             consumed = true;
         }
 
         scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu, event.event);
     } else if(event.type == SceneManagerEventTypeBack) {
-        if(instance->gen4_password != 0) {
+        if(instance->gen4_password.value != 0) {
             consumed = scene_manager_search_and_switch_to_previous_scene(
                 instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
         } else {

+ 0 - 96
nfc_magic/scenes/nfc_magic_scene_gen4_select_direct_write_block_0_mode.c

@@ -1,96 +0,0 @@
-#include "../nfc_magic_app_i.h"
-#include "furi_hal_rtc.h"
-#include "protocols/gen4/gen4_poller_i.h"
-
-enum SubmenuIndex {
-    SubmenuIndexEnable,
-    SubmenuIndexDisable,
-    SubmenuIndexDefault,
-};
-
-void nfc_magic_scene_gen4_select_direct_write_block_0_mode_submenu_callback(
-    void* context,
-    uint32_t index) {
-    NfcMagicApp* instance = context;
-
-    view_dispatcher_send_custom_event(instance->view_dispatcher, index);
-}
-
-void nfc_magic_scene_gen4_select_direct_write_block_0_mode_on_enter(void* context) {
-    NfcMagicApp* instance = context;
-
-    Submenu* submenu = instance->submenu;
-    submenu_add_item(
-        submenu,
-        "Enable",
-        SubmenuIndexEnable,
-        nfc_magic_scene_gen4_select_direct_write_block_0_mode_submenu_callback,
-        instance);
-    submenu_add_item(
-        submenu,
-        "Disable",
-        SubmenuIndexDisable,
-        nfc_magic_scene_gen4_select_direct_write_block_0_mode_submenu_callback,
-        instance);
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        submenu_add_item(
-            submenu,
-            "Default",
-            SubmenuIndexDefault,
-            nfc_magic_scene_gen4_select_direct_write_block_0_mode_submenu_callback,
-            instance);
-    }
-    submenu_set_selected_item(
-        submenu,
-        scene_manager_get_scene_state(
-            instance->scene_manager, NfcMagicSceneGen4SelectDirectWriteBlock0Mode));
-    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
-}
-
-bool nfc_magic_scene_gen4_select_direct_write_block_0_mode_on_event(
-    void* context,
-    SceneManagerEvent event) {
-    NfcMagicApp* instance = context;
-    bool consumed = false;
-
-    if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubmenuIndexEnable) {
-            scene_manager_set_scene_state(
-                instance->scene_manager,
-                NfcMagicSceneGen4SetDirectWriteBlock0Mode,
-                Gen4PollerDirectWriteBlock0ModeEnabled);
-            scene_manager_next_scene(
-                instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode);
-            consumed = true;
-        } else if(event.event == SubmenuIndexDisable) {
-            scene_manager_set_scene_state(
-                instance->scene_manager,
-                NfcMagicSceneGen4SetDirectWriteBlock0Mode,
-                Gen4PollerDirectWriteBlock0ModeDisabled);
-            scene_manager_next_scene(
-                instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode);
-            consumed = true;
-        } else if(event.event == SubmenuIndexDefault) {
-            scene_manager_set_scene_state(
-                instance->scene_manager,
-                NfcMagicSceneGen4SetDirectWriteBlock0Mode,
-                Gen4PollerDirectWriteBlock0ModeDefault);
-            scene_manager_next_scene(
-                instance->scene_manager, NfcMagicSceneGen4SetDirectWriteBlock0Mode);
-            consumed = true;
-        }
-        scene_manager_set_scene_state(
-            instance->scene_manager, NfcMagicSceneGen4SelectDirectWriteBlock0Mode, event.event);
-    } else if(event.type == SceneManagerEventTypeBack) {
-        consumed = scene_manager_search_and_switch_to_previous_scene(
-            instance->scene_manager, NfcMagicSceneGen4ActionsMenu);
-    }
-
-    return consumed;
-}
-
-void nfc_magic_scene_gen4_select_direct_write_block_0_mode_on_exit(void* context) {
-    NfcMagicApp* instance = context;
-
-    submenu_reset(instance->submenu);
-}

+ 5 - 9
nfc_magic/scenes/nfc_magic_scene_gen4_select_shd_mode.c

@@ -63,33 +63,29 @@ bool nfc_magic_scene_gen4_select_shd_mode_on_event(void* context, SceneManagerEv
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubmenuIndexPreWriteMode) {
             scene_manager_set_scene_state(
-                instance->scene_manager,
-                NfcMagicSceneGen4SetShdMode,
-                Gen4PollerShadowModePreWrite);
+                instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4ShadowModePreWrite);
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
             consumed = true;
         } else if(event.event == SubmenuIndexRestoreMode) {
             scene_manager_set_scene_state(
-                instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4PollerShadowModeRestore);
+                instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4ShadowModeRestore);
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
             consumed = true;
         } else if(event.event == SubmenuIndexDisable) {
             scene_manager_set_scene_state(
-                instance->scene_manager,
-                NfcMagicSceneGen4SetShdMode,
-                Gen4PollerShadowModeDisabled);
+                instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4ShadowModeDisabled);
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
             consumed = true;
         } else if(event.event == SubmenuIndexDisableHighSpeed) {
             scene_manager_set_scene_state(
                 instance->scene_manager,
                 NfcMagicSceneGen4SetShdMode,
-                Gen4PollerShadowModeHighSpeedDisabled);
+                Gen4ShadowModeHighSpeedDisabled);
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
             consumed = true;
         } else if(event.event == SubmenuIndexSplitMode) {
             scene_manager_set_scene_state(
-                instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4PollerShadowModeSplit);
+                instance->scene_manager, NfcMagicSceneGen4SetShdMode, Gen4ShadowModeSplit);
             scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4SetShdMode);
             consumed = true;
         }

+ 1 - 1
nfc_magic/scenes/nfc_magic_scene_gen4_set_default_cfg.c

@@ -42,7 +42,7 @@ static void nfc_magic_scene_gen4_set_default_cfg_setup_view(NfcMagicApp* instanc
             instance->popup, "Apply the\ncard\nto the back", 128, 32, AlignRight, AlignCenter);
     } else {
         popup_set_icon(popup, 12, 23, &I_Loading_24);
-        popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
+        popup_set_header(popup, "Configuring\nDon't move...", 52, 32, AlignLeft, AlignCenter);
     }
 
     view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);

+ 2 - 1
nfc_magic/scenes/nfc_magic_scene_gen4_set_direct_write_block_0_mode.c

@@ -1,5 +1,6 @@
 #include "../nfc_magic_app_i.h"
 #include "../lib/magic/protocols/gen4/gen4_poller_i.h"
+#include "gui/scene_manager.h"
 
 enum {
     NfcMagicSceneGen4SetDirectWriteBlock0ModeStateCardSearch,
@@ -43,7 +44,7 @@ static void nfc_magic_scene_gen4_set_direct_write_block_0_mode_setup_view(NfcMag
             instance->popup, "Apply the\ncard\nto the back", 128, 32, AlignRight, AlignCenter);
     } else {
         popup_set_icon(popup, 12, 23, &I_Loading_24);
-        popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
+        popup_set_header(popup, "Configuring\nDon't move...", 52, 32, AlignLeft, AlignCenter);
     }
 
     view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);

+ 1 - 1
nfc_magic/scenes/nfc_magic_scene_gen4_set_shd_mode.c

@@ -42,7 +42,7 @@ static void nfc_magic_scene_gen4_set_shd_mode_setup_view(NfcMagicApp* instance)
             instance->popup, "Apply the\ncard\nto the back", 128, 32, AlignRight, AlignCenter);
     } else {
         popup_set_icon(popup, 12, 23, &I_Loading_24);
-        popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
+        popup_set_header(popup, "Configuring\nDon't move...", 52, 32, AlignLeft, AlignCenter);
     }
 
     view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);

+ 7 - 6
nfc_magic/scenes/nfc_magic_scene_gen4_show_cfg.c

@@ -1,6 +1,6 @@
 #include "../nfc_magic_app_i.h"
-
-#define CONFIG_SIZE (32)
+#include "protocols/gen4/gen4.h"
+#include "protocols/gen4/gen4_poller_i.h"
 
 void nfc_magic_scene_gen4_show_cfg_widget_callback(
     GuiButtonType result,
@@ -19,10 +19,11 @@ void nfc_magic_scene_gen4_show_cfg_on_enter(void* context) {
 
     FuriString* output = furi_string_alloc();
 
-    for(size_t i = 0; i < CONFIG_SIZE; i += 2) {
+    Gen4Config* config = &instance->gen4_data->config;
+
+    for(size_t i = 0; i < GEN4_CONFIG_SIZE; i += 2) {
         if(i && !(i % 8)) furi_string_cat_printf(output, "\n");
-        furi_string_cat_printf(
-            output, "%02X%02X ", instance->gen4_config[i], instance->gen4_config[i + 1]);
+        furi_string_cat_printf(output, "%02X%02X ", config->data_raw[i], config->data_raw[i + 1]);
     }
 
     widget_add_string_element(widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Gen4 Config");
@@ -39,7 +40,7 @@ bool nfc_magic_scene_gen4_show_cfg_on_event(void* context, SceneManagerEvent eve
 
     if(event.type == SceneManagerEventTypeBack) {
         consumed = scene_manager_search_and_switch_to_previous_scene(
-            instance->scene_manager, NfcMagicSceneGen4GetInfo);
+            instance->scene_manager, NfcMagicSceneGen4ShowInfo);
     }
     return consumed;
 }

+ 28 - 56
nfc_magic/scenes/nfc_magic_scene_gen4_show_info.c

@@ -1,51 +1,10 @@
 #include "../nfc_magic_app_i.h"
+#include "core/string.h"
 #include "gui/modules/widget_elements/widget_element.h"
 #include "gui/scene_manager.h"
-#include "protocols/gen4/gen4_poller_i.h"
-#include <bit_lib.h>
-
-#define CONFIG_SIZE (32)
-
-static char* gen4_get_shadow_mode_name(Gen4PollerShadowMode mode) {
-    switch(mode) {
-    case Gen4PollerShadowModePreWrite:
-        return "Pre-Write";
-    case Gen4PollerShadowModeRestore:
-        return "Restore";
-    case Gen4PollerShadowModeDisabled:
-        return "Disabled";
-    case Gen4PollerShadowModeHighSpeedDisabled:
-        return "Disabled (High-speed)";
-    case Gen4PollerShadowModeSplit:
-        return "Split";
-    default:
-        return "Unknown";
-    }
-}
-
-static char* gen4_get_direct_write_mode_name(Gen4PollerDirectWriteBlock0Mode mode) {
-    switch(mode) {
-    case Gen4PollerDirectWriteBlock0ModeEnabled:
-        return "Enabled";
-    case Gen4PollerDirectWriteBlock0ModeDisabled:
-        return "Disabled";
-    case Gen4PollerDirectWriteBlock0ModeDefault:
-        return "Default";
-    default:
-        return "Unknown";
-    }
-}
 
-static char* gen4_get_uid_len(uint8_t byte) {
-    switch(byte) {
-    case 0:
-        return "4";
-    case 1:
-        return "7";
-    default:
-        return "Unknown";
-    }
-}
+#include <bit_lib.h>
+#include <stdbool.h>
 
 void nfc_magic_scene_gen4_show_info_widget_callback(
     GuiButtonType result,
@@ -62,21 +21,30 @@ void nfc_magic_scene_gen4_show_info_on_enter(void* context) {
     NfcMagicApp* instance = context;
     Widget* widget = instance->widget;
 
-    notification_message(instance->notifications, &sequence_success);
+    if(scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4ShowInfo))
+        notification_message(instance->notifications, &sequence_success);
+    scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4ShowInfo, false);
+
+    Gen4* gen4 = instance->gen4_data;
 
-    Gen4PollerDirectWriteBlock0Mode dw_mode = instance->gen4_config[29];
-    Gen4PollerShadowMode s_mode = instance->gen4_config[6];
-    uint8_t ats_len = instance->gen4_config[7];
+    Gen4DirectWriteBlock0Mode dw_mode = gen4->config.data_parsed.direct_write_mode;
+    Gen4ShadowMode s_mode = gen4->config.data_parsed.gtu_mode;
+    uint8_t ats_len = gen4->config.data_parsed.ats_len;
 
     FuriString* output = furi_string_alloc();
 
     // Revision
     furi_string_cat_printf(
-        output, "Revision: %02X %02X\n", instance->gen4_revision[3], instance->gen4_revision[4]);
+        output, "Revision: %02X %02X\n", gen4->revision.data[3], gen4->revision.data[4]);
 
     // Password
     furi_string_cat_printf(
-        output, "Password: %08llX\n", bit_lib_bytes_to_num_be(instance->gen4_config + 2, 4));
+        output,
+        "Password: %02X %02X %02X %02X\n",
+        gen4->config.data_parsed.password.bytes[0],
+        gen4->config.data_parsed.password.bytes[1],
+        gen4->config.data_parsed.password.bytes[2],
+        gen4->config.data_parsed.password.bytes[3]);
 
     // Shadow mode
     furi_string_cat_printf(output, "Shadow Mode: %s\n", gen4_get_shadow_mode_name(s_mode));
@@ -89,14 +57,18 @@ void nfc_magic_scene_gen4_show_info_on_enter(void* context) {
     furi_string_cat_printf(output, ":::::::::::::[Configured As]::::::::::::::\n");
     /////////////////////////////////////////////////////////////////////////////////////////////////////
 
+    // Configuration type:
+    furi_string_cat_printf(output, "%s\n", gen4_get_configuration_name(&gen4->config));
+
     // UID len
-    furi_string_cat_printf(output, "UID Length: %s\n", gen4_get_uid_len(instance->gen4_config[1]));
+    furi_string_cat_printf(
+        output, "UID Length: %s\n", gen4_get_uid_len_num(gen4->config.data_parsed.uid_len_code));
 
     // ATS
     furi_string_cat_printf(output, "ATS:");
     if(ats_len)
         for(uint8_t i = 0; i < ats_len; i++)
-            furi_string_cat_printf(output, " %02X", instance->gen4_config[8 + i]);
+            furi_string_cat_printf(output, " %02X", gen4->config.data_parsed.ats[i]);
     else
         furi_string_cat_printf(output, " No");
     furi_string_cat_printf(output, "\n");
@@ -105,17 +77,17 @@ void nfc_magic_scene_gen4_show_info_on_enter(void* context) {
     furi_string_cat_printf(
         output,
         "ATQA: %02X %02X\n",
-        instance->gen4_config[25],
-        instance->gen4_config[24]); // invert for big endian
+        gen4->config.data_parsed.atqa[0],
+        gen4->config.data_parsed.atqa[1]);
 
     // SAK
-    furi_string_cat_printf(output, "SAK: %02X\n", instance->gen4_config[26]);
+    furi_string_cat_printf(output, "SAK: %02X\n", gen4->config.data_parsed.sak);
 
     // Blocks
     furi_string_cat_printf(
         output,
         "Total blocks: %u",
-        instance->gen4_config[28] + 1); // config stores the number of the last block
+        gen4->config.data_parsed.total_blocks + 1); // config stores the number of the last block
 
     widget_add_string_element(widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Gen4 Info");
 

+ 10 - 5
nfc_magic/scenes/nfc_magic_scene_key_input.c

@@ -1,6 +1,8 @@
 #include "../nfc_magic_app_i.h"
 
-#include <bit_lib/bit_lib.h>
+#include "protocols/gen4/gen4.h"
+#include <bit_lib.h>
+#include <string.h>
 
 void nfc_magic_scene_key_input_byte_input_callback(void* context) {
     NfcMagicApp* instance = context;
@@ -31,13 +33,16 @@ bool nfc_magic_scene_key_input_on_event(void* context, SceneManagerEvent event)
 
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcMagicAppCustomEventByteInputDone) {
+            // TODO: NEED TEST
             if(scene_manager_has_previous_scene(instance->scene_manager, NfcMagicSceneGen4Menu)) {
-                instance->gen4_password_new = bit_lib_bytes_to_num_be(
-                    instance->byte_input_store, NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE);
+                memcpy(
+                    instance->gen4_password_new.bytes,
+                    instance->byte_input_store,
+                    GEN4_PASSWORD_LEN);
                 scene_manager_next_scene(instance->scene_manager, NfcMagicSceneChangeKey);
             } else {
-                instance->gen4_password = bit_lib_bytes_to_num_be(
-                    instance->byte_input_store, NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE);
+                memcpy(
+                    instance->gen4_password.bytes, instance->byte_input_store, GEN4_PASSWORD_LEN);
                 scene_manager_next_scene(instance->scene_manager, NfcMagicSceneCheck);
             }
             consumed = true;

+ 37 - 18
nfc_magic/scenes/nfc_magic_scene_magic_info.c

@@ -1,4 +1,9 @@
 #include "../nfc_magic_app_i.h"
+#include "core/string.h"
+#include "gui/canvas.h"
+#include "gui/modules/widget.h"
+#include "lib/magic/nfc_magic_scanner.h"
+#include "protocols/gen4/gen4.h"
 
 void nfc_magic_scene_magic_info_widget_callback(
     GuiButtonType result,
@@ -17,20 +22,40 @@ void nfc_magic_scene_magic_info_on_enter(void* context) {
 
     notification_message(instance->notifications, &sequence_success);
 
-    FuriString* message = furi_string_alloc();
+    //widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48);
+    widget_add_string_element(
+        widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Magic card detected");
+    widget_add_string_element(
+        widget,
+        3,
+        17,
+        AlignLeft,
+        AlignTop,
+        FontSecondary,
+        nfc_magic_protocols_get_name(instance->protocol));
+    if(instance->protocol == NfcMagicProtocolGen4) {
+        gen4_copy(instance->gen4_data, nfc_magic_scanner_get_gen4_data(instance->scanner));
+
+        FuriString* message = furi_string_alloc();
+
+        furi_string_printf(
+            message,
+            "Revision: %02X %02X\n",
+            instance->gen4_data->revision.data[3],
+            instance->gen4_data->revision.data[4]);
 
-    if(instance->protocol == NfcMagicProtocolClassic) {
-        widget_add_string_element(
-            widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "It Might Be a Magic Card");
-        furi_string_printf(message, "You can make sure the card is\nmagic by writing to it\n");
-    } else {
         widget_add_string_element(
-            widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Magic card detected!");
+            widget, 55, 17, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(message));
+
+        furi_string_printf(
+            message,
+            "Configured As:\n%s",
+            gen4_get_configuration_name(&instance->gen4_data->config));
+
+        widget_add_string_multiline_element(
+            widget, 3, 27, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(message));
+        furi_string_free(message);
     }
-    furi_string_cat_printf(
-        message, "Magic Type: %s", nfc_magic_protocols_get_name(instance->protocol));
-    widget_add_text_box_element(
-        widget, 0, 10, 128, 54, AlignLeft, AlignTop, furi_string_get_cstr(message), false);
     widget_add_button_element(
         widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_magic_info_widget_callback, instance);
     widget_add_button_element(
@@ -50,15 +75,9 @@ bool nfc_magic_scene_magic_info_on_event(void* context, SceneManagerEvent event)
             if(instance->protocol == NfcMagicProtocolGen1) {
                 scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen1Menu);
                 consumed = true;
-            } else if(instance->protocol == NfcMagicProtocolGen4) {
+            } else {
                 scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Menu);
                 consumed = true;
-            } else if(instance->protocol == NfcMagicProtocolGen2) {
-                scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen2Menu);
-                consumed = true;
-            } else if(instance->protocol == NfcMagicProtocolClassic) {
-                scene_manager_next_scene(instance->scene_manager, NfcMagicSceneMfClassicMenu);
-                consumed = true;
             }
         }
     } else if(event.type == SceneManagerEventTypeBack) {

+ 0 - 311
nfc_magic/scenes/nfc_magic_scene_mf_classic_dict_attack.c

@@ -1,311 +0,0 @@
-#include "../nfc_magic_app_i.h"
-
-#include <dolphin/dolphin.h>
-#include <lib/nfc/protocols/mf_classic/mf_classic_poller.h>
-
-#include "views/dict_attack.h"
-
-#define TAG "NfcMagicMfClassicDictAttack"
-
-typedef enum {
-    DictAttackStateUserDictInProgress,
-    DictAttackStateSystemDictInProgress,
-} DictAttackState;
-
-NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context) {
-    furi_assert(context);
-    furi_assert(event.event_data);
-    furi_assert(event.instance);
-    furi_assert(event.protocol == NfcProtocolMfClassic);
-
-    NfcCommand command = NfcCommandContinue;
-    MfClassicPollerEvent* mfc_event = event.event_data;
-
-    NfcMagicApp* instance = context;
-    if(mfc_event->type == MfClassicPollerEventTypeCardDetected) {
-        instance->nfc_dict_context.is_card_present = true;
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventCardDetected);
-    } else if(mfc_event->type == MfClassicPollerEventTypeCardLost) {
-        instance->nfc_dict_context.is_card_present = false;
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventCardLost);
-    } else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) {
-        const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller);
-        nfc_device_set_data(instance->target_dev, NfcProtocolMfClassic, mfc_data);
-        FURI_LOG_D(TAG, "MFC type: %d", mfc_data->type);
-        mfc_event->data->poller_mode.mode = MfClassicPollerModeDictAttack;
-        mfc_event->data->poller_mode.data = mfc_data;
-        instance->nfc_dict_context.sectors_total =
-            mf_classic_get_total_sectors_num(mfc_data->type);
-        FURI_LOG_D(TAG, "Total sectors: %d", mf_classic_get_total_sectors_num(mfc_data->type));
-        mf_classic_get_read_sectors_and_keys(
-            mfc_data,
-            &instance->nfc_dict_context.sectors_read,
-            &instance->nfc_dict_context.keys_found);
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventDictAttackDataUpdate);
-    } else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) {
-        MfClassicKey key = {};
-        if(keys_dict_get_next_key(
-               instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) {
-            mfc_event->data->key_request_data.key = key;
-            mfc_event->data->key_request_data.key_provided = true;
-            instance->nfc_dict_context.dict_keys_current++;
-            if(instance->nfc_dict_context.dict_keys_current % 10 == 0) {
-                view_dispatcher_send_custom_event(
-                    instance->view_dispatcher, NfcMagicAppCustomEventDictAttackDataUpdate);
-            }
-        } else {
-            mfc_event->data->key_request_data.key_provided = false;
-        }
-    } else if(mfc_event->type == MfClassicPollerEventTypeDataUpdate) {
-        MfClassicPollerEventDataUpdate* data_update = &mfc_event->data->data_update;
-        instance->nfc_dict_context.sectors_read = data_update->sectors_read;
-        instance->nfc_dict_context.keys_found = data_update->keys_found;
-        instance->nfc_dict_context.current_sector = data_update->current_sector;
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventDictAttackDataUpdate);
-    } else if(mfc_event->type == MfClassicPollerEventTypeNextSector) {
-        keys_dict_rewind(instance->nfc_dict_context.dict);
-        instance->nfc_dict_context.dict_keys_current = 0;
-        instance->nfc_dict_context.current_sector =
-            mfc_event->data->next_sector_data.current_sector;
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventDictAttackDataUpdate);
-    } else if(mfc_event->type == MfClassicPollerEventTypeFoundKeyA) {
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventDictAttackDataUpdate);
-    } else if(mfc_event->type == MfClassicPollerEventTypeFoundKeyB) {
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventDictAttackDataUpdate);
-    } else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStart) {
-        instance->nfc_dict_context.key_attack_current_sector =
-            mfc_event->data->key_attack_data.current_sector;
-        instance->nfc_dict_context.is_key_attack = true;
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventDictAttackDataUpdate);
-    } else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStop) {
-        keys_dict_rewind(instance->nfc_dict_context.dict);
-        instance->nfc_dict_context.is_key_attack = false;
-        instance->nfc_dict_context.dict_keys_current = 0;
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventDictAttackDataUpdate);
-    } else if(mfc_event->type == MfClassicPollerEventTypeSuccess) {
-        const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller);
-        nfc_device_set_data(instance->target_dev, NfcProtocolMfClassic, mfc_data);
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventDictAttackComplete);
-        command = NfcCommandStop;
-    }
-
-    return command;
-}
-
-void nfc_dict_attack_dict_attack_result_callback(DictAttackEvent event, void* context) {
-    furi_assert(context);
-    NfcMagicApp* instance = context;
-
-    if(event == DictAttackEventSkipPressed) {
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicAppCustomEventDictAttackSkip);
-    }
-}
-
-static void nfc_magic_scene_mf_classic_dict_attack_update_view(NfcMagicApp* instance) {
-    NfcMagicAppMfClassicDictAttackContext* mfc_dict = &instance->nfc_dict_context;
-
-    if(mfc_dict->is_key_attack) {
-        dict_attack_set_key_attack(instance->dict_attack, mfc_dict->key_attack_current_sector);
-    } else {
-        dict_attack_reset_key_attack(instance->dict_attack);
-        dict_attack_set_sectors_total(instance->dict_attack, mfc_dict->sectors_total);
-        dict_attack_set_sectors_read(instance->dict_attack, mfc_dict->sectors_read);
-        dict_attack_set_keys_found(instance->dict_attack, mfc_dict->keys_found);
-        dict_attack_set_current_dict_key(instance->dict_attack, mfc_dict->dict_keys_current);
-        dict_attack_set_current_sector(instance->dict_attack, mfc_dict->current_sector);
-    }
-}
-
-static void nfc_magic_scene_mf_classic_dict_attack_prepare_view(NfcMagicApp* instance) {
-    uint32_t state =
-        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneMfClassicDictAttack);
-    if(state == DictAttackStateUserDictInProgress) {
-        do {
-            if(!keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) {
-                state = DictAttackStateSystemDictInProgress;
-                break;
-            }
-
-            instance->nfc_dict_context.dict = keys_dict_alloc(
-                NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
-            if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
-                keys_dict_free(instance->nfc_dict_context.dict);
-                state = DictAttackStateSystemDictInProgress;
-                break;
-            }
-
-            dict_attack_set_header(instance->dict_attack, "MF Classic User Dictionary");
-        } while(false);
-    }
-    if(state == DictAttackStateSystemDictInProgress) {
-        instance->nfc_dict_context.dict = keys_dict_alloc(
-            NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey));
-        dict_attack_set_header(instance->dict_attack, "MF Classic System Dictionary");
-    }
-
-    instance->nfc_dict_context.dict_keys_total =
-        keys_dict_get_total_keys(instance->nfc_dict_context.dict);
-    dict_attack_set_total_dict_keys(
-        instance->dict_attack, instance->nfc_dict_context.dict_keys_total);
-    instance->nfc_dict_context.dict_keys_current = 0;
-
-    dict_attack_set_callback(
-        instance->dict_attack, nfc_dict_attack_dict_attack_result_callback, instance);
-    nfc_magic_scene_mf_classic_dict_attack_update_view(instance);
-
-    scene_manager_set_scene_state(
-        instance->scene_manager, NfcMagicSceneMfClassicDictAttack, state);
-}
-
-void nfc_magic_scene_mf_classic_dict_attack_on_enter(void* context) {
-    NfcMagicApp* instance = context;
-
-    scene_manager_set_scene_state(
-        instance->scene_manager,
-        NfcMagicSceneMfClassicDictAttack,
-        DictAttackStateUserDictInProgress);
-    nfc_magic_scene_mf_classic_dict_attack_prepare_view(instance);
-    dict_attack_set_card_state(instance->dict_attack, true);
-    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewDictAttack);
-    nfc_magic_app_blink_start(instance);
-    notification_message(instance->notifications, &sequence_display_backlight_enforce_on);
-
-    instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic);
-    nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance);
-}
-
-static void nfc_magic_scene_mf_classic_dict_attack_notify_read(NfcMagicApp* instance) {
-    const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller);
-    bool is_card_fully_read = mf_classic_is_card_read(mfc_data);
-    if(is_card_fully_read) {
-        notification_message(instance->notifications, &sequence_success);
-    } else {
-        notification_message(instance->notifications, &sequence_semi_success);
-    }
-}
-
-bool nfc_magic_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) {
-    NfcMagicApp* instance = context;
-    bool consumed = false;
-
-    uint32_t state =
-        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneMfClassicDictAttack);
-    if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == NfcMagicAppCustomEventDictAttackComplete) {
-            if(state == DictAttackStateUserDictInProgress) {
-                nfc_poller_stop(instance->poller);
-                nfc_poller_free(instance->poller);
-                keys_dict_free(instance->nfc_dict_context.dict);
-                scene_manager_set_scene_state(
-                    instance->scene_manager,
-                    NfcMagicSceneMfClassicDictAttack,
-                    DictAttackStateSystemDictInProgress);
-                nfc_magic_scene_mf_classic_dict_attack_prepare_view(instance);
-                instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic);
-                nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance);
-                consumed = true;
-            } else {
-                nfc_magic_scene_mf_classic_dict_attack_notify_read(instance);
-                if(instance->protocol == NfcMagicProtocolGen2) {
-                    scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen2WriteCheck);
-                } else {
-                    scene_manager_next_scene(
-                        instance->scene_manager, NfcMagicSceneMfClassicWriteCheck);
-                }
-                dolphin_deed(DolphinDeedNfcReadSuccess);
-                consumed = true;
-            }
-        } else if(event.event == NfcMagicAppCustomEventCardDetected) {
-            dict_attack_set_card_state(instance->dict_attack, true);
-            consumed = true;
-        } else if(event.event == NfcMagicAppCustomEventCardLost) {
-            dict_attack_set_card_state(instance->dict_attack, false);
-            consumed = true;
-        } else if(event.event == NfcMagicAppCustomEventDictAttackDataUpdate) {
-            nfc_magic_scene_mf_classic_dict_attack_update_view(instance);
-        } else if(event.event == NfcMagicAppCustomEventDictAttackSkip) {
-            const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller);
-            nfc_device_set_data(instance->target_dev, NfcProtocolMfClassic, mfc_data);
-            if(state == DictAttackStateUserDictInProgress) {
-                if(instance->nfc_dict_context.is_card_present) {
-                    nfc_poller_stop(instance->poller);
-                    nfc_poller_free(instance->poller);
-                    keys_dict_free(instance->nfc_dict_context.dict);
-                    scene_manager_set_scene_state(
-                        instance->scene_manager,
-                        NfcMagicSceneMfClassicDictAttack,
-                        DictAttackStateSystemDictInProgress);
-                    nfc_magic_scene_mf_classic_dict_attack_prepare_view(instance);
-                    instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic);
-                    nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance);
-                } else {
-                    nfc_magic_scene_mf_classic_dict_attack_notify_read(instance);
-                    if(instance->protocol == NfcMagicProtocolGen2) {
-                        scene_manager_next_scene(
-                            instance->scene_manager, NfcMagicSceneGen2WriteCheck);
-                    } else {
-                        scene_manager_next_scene(
-                            instance->scene_manager, NfcMagicSceneMfClassicWriteCheck);
-                    }
-                    dolphin_deed(DolphinDeedNfcReadSuccess);
-                }
-                consumed = true;
-            } else if(state == DictAttackStateSystemDictInProgress) {
-                nfc_magic_scene_mf_classic_dict_attack_notify_read(instance);
-                if(instance->protocol == NfcMagicProtocolGen2) {
-                    scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen2WriteCheck);
-                } else {
-                    scene_manager_next_scene(
-                        instance->scene_manager, NfcMagicSceneMfClassicWriteCheck);
-                }
-                dolphin_deed(DolphinDeedNfcReadSuccess);
-                consumed = true;
-            }
-        }
-    } else if(event.type == SceneManagerEventTypeBack) {
-        scene_manager_previous_scene(instance->scene_manager);
-        consumed = true;
-    }
-    return consumed;
-}
-
-void nfc_magic_scene_mf_classic_dict_attack_on_exit(void* context) {
-    NfcMagicApp* instance = context;
-    const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller);
-    nfc_device_set_data(instance->target_dev, NfcProtocolMfClassic, mfc_data);
-
-    nfc_poller_stop(instance->poller);
-    nfc_poller_free(instance->poller);
-
-    dict_attack_reset(instance->dict_attack);
-    scene_manager_set_scene_state(
-        instance->scene_manager,
-        NfcMagicSceneMfClassicDictAttack,
-        DictAttackStateUserDictInProgress);
-
-    keys_dict_free(instance->nfc_dict_context.dict);
-
-    instance->nfc_dict_context.current_sector = 0;
-    instance->nfc_dict_context.sectors_total = 0;
-    instance->nfc_dict_context.sectors_read = 0;
-    instance->nfc_dict_context.keys_found = 0;
-    instance->nfc_dict_context.dict_keys_total = 0;
-    instance->nfc_dict_context.dict_keys_current = 0;
-    instance->nfc_dict_context.is_key_attack = false;
-    instance->nfc_dict_context.key_attack_current_sector = 0;
-    instance->nfc_dict_context.is_card_present = false;
-
-    nfc_magic_app_blink_stop(instance);
-    notification_message(instance->notifications, &sequence_display_backlight_enforce_auto);
-}

+ 0 - 65
nfc_magic/scenes/nfc_magic_scene_mf_classic_menu.c

@@ -1,65 +0,0 @@
-#include "../nfc_magic_app_i.h"
-
-enum SubmenuIndex {
-    SubmenuIndexWrite,
-    SubmenuIndexWipe,
-};
-
-void nfc_magic_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) {
-    NfcMagicApp* instance = context;
-
-    view_dispatcher_send_custom_event(instance->view_dispatcher, index);
-}
-
-void nfc_magic_scene_mf_classic_menu_on_enter(void* context) {
-    NfcMagicApp* instance = context;
-
-    Submenu* submenu = instance->submenu;
-    submenu_add_item(
-        submenu,
-        "Write",
-        SubmenuIndexWrite,
-        nfc_magic_scene_mf_classic_menu_submenu_callback,
-        instance);
-    submenu_add_item(
-        submenu,
-        "Wipe",
-        SubmenuIndexWipe,
-        nfc_magic_scene_mf_classic_menu_submenu_callback,
-        instance);
-
-    submenu_set_selected_item(
-        submenu,
-        scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneMfClassicMenu));
-    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
-}
-
-bool nfc_magic_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) {
-    NfcMagicApp* instance = context;
-    bool consumed = false;
-
-    if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubmenuIndexWrite) {
-            instance->gen2_poller_is_wipe_mode = false;
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneFileSelect);
-            consumed = true;
-        } else if(event.event == SubmenuIndexWipe) {
-            instance->gen2_poller_is_wipe_mode = true;
-            scene_manager_next_scene(instance->scene_manager, NfcMagicSceneMfClassicDictAttack);
-            consumed = true;
-        }
-        scene_manager_set_scene_state(
-            instance->scene_manager, NfcMagicSceneMfClassicMenu, event.event);
-    } else if(event.type == SceneManagerEventTypeBack) {
-        consumed = scene_manager_search_and_switch_to_previous_scene(
-            instance->scene_manager, NfcMagicSceneStart);
-    }
-
-    return consumed;
-}
-
-void nfc_magic_scene_mf_classic_menu_on_exit(void* context) {
-    NfcMagicApp* instance = context;
-
-    submenu_reset(instance->submenu);
-}

+ 0 - 124
nfc_magic/scenes/nfc_magic_scene_mf_classic_write_check.c

@@ -1,124 +0,0 @@
-#include "../nfc_magic_app_i.h"
-
-void nfc_magic_scene_mf_classic_write_check_view_callback(WriteProblemsEvent event, void* context) {
-    NfcMagicApp* instance = context;
-    NfcMagicAppWriteProblemsContext* problems_context = &instance->write_problems_context;
-
-    if(event == WriteProblemsEventCenterPressed) {
-        if(problems_context->problem_index == problems_context->problems_total - 1) {
-            // Continue to the next scene
-            if(instance->gen2_poller_is_wipe_mode) {
-                scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe);
-            } else {
-                scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWrite);
-            }
-        } else {
-            // Move to the next problem
-            problems_context->problem_index++;
-            problems_context->problem_index_abs++;
-            write_problems_set_problem_index(
-                instance->write_problems, problems_context->problem_index);
-
-            for(uint8_t i = problems_context->problem_index_abs;
-                i < GEN2_POLLER_WRITE_PROBLEMS_LEN;
-                i++) {
-                if(problems_context->problems.all_problems & (1 << i)) {
-                    write_problems_set_content(instance->write_problems, gen2_problem_strings[i]);
-                    problems_context->problem_index_abs = i;
-                    break;
-                }
-            }
-        }
-    } else if(event == WriteProblemsEventLeftPressed) {
-        if(problems_context->problem_index == 0) {
-            // Exit to the previous scene
-            scene_manager_search_and_switch_to_previous_scene(
-                instance->scene_manager, NfcMagicSceneMfClassicMenu);
-        } else {
-            // Move to the previous problem
-            problems_context->problem_index--;
-            problems_context->problem_index_abs--;
-            write_problems_set_problem_index(
-                instance->write_problems, problems_context->problem_index);
-
-            for(uint8_t i = problems_context->problem_index_abs;
-                i < GEN2_POLLER_WRITE_PROBLEMS_LEN;
-                i--) {
-                if(problems_context->problems.all_problems & (1 << i)) {
-                    write_problems_set_content(instance->write_problems, gen2_problem_strings[i]);
-                    problems_context->problem_index_abs = i;
-                    break;
-                }
-            }
-        }
-    }
-}
-
-void nfc_magic_scene_mf_classic_write_check_on_enter(void* context) {
-    NfcMagicApp* instance = context;
-
-    Gen2PollerWriteProblems problems = gen2_poller_check_target_problems(instance->target_dev);
-    if(!instance->gen2_poller_is_wipe_mode) {
-        problems.all_problems |=
-            gen2_poller_check_source_problems(instance->source_dev).all_problems;
-    }
-    FURI_LOG_D("GEN2", "Problems: %d", problems.all_problems);
-
-    WriteProblems* write_problems = instance->write_problems;
-    uint8_t problems_count = 0;
-    uint8_t current_problem = 0;
-    furi_assert(!problems.no_data, "No MFC data in nfc device");
-
-    // Set the uid_locked problem to true as we have a Mifare Classic card
-    problems.uid_locked = true;
-
-    // Count the number of problems
-    for(uint8_t i = 0; i < GEN2_POLLER_WRITE_PROBLEMS_LEN; i++) {
-        if(problems.all_problems & (1 << i)) {
-            problems_count++;
-        }
-    }
-
-    // Init the view
-    write_problems_set_callback(
-        write_problems, nfc_magic_scene_mf_classic_write_check_view_callback, instance);
-    write_problems_set_problems_total(write_problems, problems_count);
-    write_problems_set_problem_index(write_problems, current_problem);
-
-    // Set the first problem
-    for(uint8_t i = current_problem; i < GEN2_POLLER_WRITE_PROBLEMS_LEN; i++) {
-        if(problems.all_problems & (1 << i)) {
-            write_problems_set_content(instance->write_problems, gen2_problem_strings[i]);
-            instance->write_problems_context.problem_index_abs = i;
-            break;
-        }
-    }
-
-    // Save the problems context
-    instance->write_problems_context.problem_index = current_problem;
-    instance->write_problems_context.problems_total = problems_count;
-    instance->write_problems_context.problems = problems;
-
-    // Setup and start worker
-    view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWriteProblems);
-}
-
-bool nfc_magic_scene_mf_classic_write_check_on_event(void* context, SceneManagerEvent event) {
-    NfcMagicApp* instance = context;
-    UNUSED(event);
-    UNUSED(context);
-    UNUSED(instance);
-    bool consumed = false;
-
-    return consumed;
-}
-
-void nfc_magic_scene_mf_classic_write_check_on_exit(void* context) {
-    NfcMagicApp* instance = context;
-
-    instance->write_problems_context.problem_index = 0;
-    instance->write_problems_context.problems_total = 0;
-    instance->write_problems_context.problems.all_problems = 0;
-
-    write_problems_reset(instance->write_problems);
-}

+ 1 - 1
nfc_magic/scenes/nfc_magic_scene_start.c

@@ -27,7 +27,7 @@ void nfc_magic_scene_start_on_enter(void* context) {
         nfc_magic_scene_start_submenu_callback,
         instance);
 
-    instance->gen4_password = 0;
+    instance->gen4_password.value = 0;
 
     submenu_set_selected_item(
         submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneStart));

+ 2 - 2
nfc_magic/scenes/nfc_magic_scene_success.c

@@ -11,8 +11,8 @@ void nfc_magic_scene_success_on_enter(void* context) {
     notification_message(instance->notifications, &sequence_success);
 
     Popup* popup = instance->popup;
-    popup_set_icon(popup, 0, 9, &I_DolphinSuccess_91x55);
-    popup_set_header(popup, "Success!", 75, 12, AlignLeft, AlignCenter);
+    popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
+    popup_set_header(popup, "Success!", 10, 20, AlignLeft, AlignBottom);
     popup_set_timeout(popup, 1500);
     popup_set_context(popup, instance);
     popup_set_callback(popup, nfc_magic_scene_success_popup_callback);

+ 6 - 48
nfc_magic/scenes/nfc_magic_scene_wipe.c

@@ -5,7 +5,7 @@ enum {
     NfcMagicSceneWipeStateCardFound,
 };
 
-NfcCommand nfc_magic_scene_wipe_gen1_poller_callback(Gen1aPollerEvent event, void* context) {
+NfcCommand nfc_mafic_scene_wipe_gen1_poller_callback(Gen1aPollerEvent event, void* context) {
     NfcMagicApp* instance = context;
     furi_assert(event.data);
 
@@ -29,35 +29,7 @@ NfcCommand nfc_magic_scene_wipe_gen1_poller_callback(Gen1aPollerEvent event, voi
     return command;
 }
 
-NfcCommand nfc_magic_scene_wipe_gen2_poller_callback(Gen2PollerEvent event, void* context) {
-    NfcMagicApp* instance = context;
-
-    NfcCommand command = NfcCommandContinue;
-
-    if(event.type == Gen2PollerEventTypeDetected) {
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicCustomEventCardDetected);
-    } else if(event.type == Gen2PollerEventTypeRequestMode) {
-        event.data->poller_mode.mode = Gen2PollerModeWipe;
-    } else if(event.type == Gen2PollerEventTypeRequestTargetData) {
-        const MfClassicData* mfc_data =
-            nfc_device_get_data(instance->target_dev, NfcProtocolMfClassic);
-        event.data->target_data.mfc_data = mfc_data;
-
-    } else if(event.type == Gen2PollerEventTypeSuccess) {
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
-        command = NfcCommandStop;
-    } else if(event.type == Gen2PollerEventTypeFail) {
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicCustomEventWorkerFail);
-        command = NfcCommandStop;
-    }
-
-    return command;
-}
-
-NfcCommand nfc_magic_scene_wipe_gen4_poller_callback(Gen4PollerEvent event, void* context) {
+NfcCommand nfc_mafic_scene_wipe_gen4_poller_callback(Gen4PollerEvent event, void* context) {
     NfcMagicApp* instance = context;
 
     NfcCommand command = NfcCommandContinue;
@@ -109,20 +81,12 @@ void nfc_magic_scene_wipe_on_enter(void* context) {
     if(instance->protocol == NfcMagicProtocolGen1) {
         instance->gen1a_poller = gen1a_poller_alloc(instance->nfc);
         gen1a_poller_start(
-            instance->gen1a_poller, nfc_magic_scene_wipe_gen1_poller_callback, instance);
-    } else if(instance->protocol == NfcMagicProtocolGen2) {
-        instance->gen2_poller = gen2_poller_alloc(instance->nfc);
-        gen2_poller_start(
-            instance->gen2_poller, nfc_magic_scene_wipe_gen2_poller_callback, instance);
-    } else if(instance->protocol == NfcMagicProtocolClassic) {
-        instance->gen2_poller = gen2_poller_alloc(instance->nfc);
-        gen2_poller_start(
-            instance->gen2_poller, nfc_magic_scene_wipe_gen2_poller_callback, instance);
-    } else if(instance->protocol == NfcMagicProtocolGen4) {
+            instance->gen1a_poller, nfc_mafic_scene_wipe_gen1_poller_callback, instance);
+    } else {
         instance->gen4_poller = gen4_poller_alloc(instance->nfc);
         gen4_poller_set_password(instance->gen4_poller, instance->gen4_password);
         gen4_poller_start(
-            instance->gen4_poller, nfc_magic_scene_wipe_gen4_poller_callback, instance);
+            instance->gen4_poller, nfc_mafic_scene_wipe_gen4_poller_callback, instance);
     }
 }
 
@@ -159,13 +123,7 @@ void nfc_magic_scene_wipe_on_exit(void* context) {
     if(instance->protocol == NfcMagicProtocolGen1) {
         gen1a_poller_stop(instance->gen1a_poller);
         gen1a_poller_free(instance->gen1a_poller);
-    } else if(instance->protocol == NfcMagicProtocolGen2) {
-        gen2_poller_stop(instance->gen2_poller);
-        gen2_poller_free(instance->gen2_poller);
-    } else if(instance->protocol == NfcMagicProtocolClassic) {
-        gen2_poller_stop(instance->gen2_poller);
-        gen2_poller_free(instance->gen2_poller);
-    } else if(instance->protocol == NfcMagicProtocolGen4) {
+    } else {
         gen4_poller_stop(instance->gen4_poller);
         gen4_poller_free(instance->gen4_poller);
     }

+ 2 - 5
nfc_magic/scenes/nfc_magic_scene_wipe_fail.c

@@ -14,11 +14,8 @@ void nfc_magic_scene_wipe_fail_on_enter(void* context) {
     Widget* widget = instance->widget;
     notification_message(instance->notifications, &sequence_error);
 
-    widget_add_icon_element(widget, 83, 22, &I_WarningDolphinFlip_45x42);
-    widget_add_string_element(widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Failed to Wipe");
-    widget_add_string_multiline_element(
-        widget, 0, 13, AlignLeft, AlignTop, FontSecondary, "Something went\nwrong while wiping");
-
+    widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48);
+    widget_add_string_element(widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Wipe failed");
     widget_add_button_element(
         widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wipe_fail_widget_callback, instance);
 

+ 5 - 50
nfc_magic/scenes/nfc_magic_scene_write.c

@@ -5,7 +5,7 @@ enum {
     NfcMagicSceneWriteStateCardFound,
 };
 
-NfcCommand nfc_magic_scene_write_gen1_poller_callback(Gen1aPollerEvent event, void* context) {
+NfcCommand nfc_mafic_scene_write_gen1_poller_callback(Gen1aPollerEvent event, void* context) {
     NfcMagicApp* instance = context;
     furi_assert(event.data);
 
@@ -33,39 +33,7 @@ NfcCommand nfc_magic_scene_write_gen1_poller_callback(Gen1aPollerEvent event, vo
     return command;
 }
 
-NfcCommand nfc_magic_scene_write_gen2_poller_callback(Gen2PollerEvent event, void* context) {
-    NfcMagicApp* instance = context;
-    furi_assert(event.data);
-
-    NfcCommand command = NfcCommandContinue;
-
-    if(event.type == Gen2PollerEventTypeDetected) {
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicCustomEventCardDetected);
-    } else if(event.type == Gen2PollerEventTypeRequestMode) {
-        event.data->poller_mode.mode = Gen2PollerModeWrite;
-    } else if(event.type == Gen2PollerEventTypeRequestDataToWrite) {
-        const MfClassicData* mfc_data =
-            nfc_device_get_data(instance->source_dev, NfcProtocolMfClassic);
-        event.data->data_to_write.mfc_data = mfc_data;
-    } else if(event.type == Gen2PollerEventTypeRequestTargetData) {
-        const MfClassicData* mfc_data =
-            nfc_device_get_data(instance->target_dev, NfcProtocolMfClassic);
-        event.data->target_data.mfc_data = mfc_data;
-    } else if(event.type == Gen2PollerEventTypeSuccess) {
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
-        command = NfcCommandStop;
-    } else if(event.type == Gen2PollerEventTypeFail) {
-        view_dispatcher_send_custom_event(
-            instance->view_dispatcher, NfcMagicCustomEventWorkerFail);
-        command = NfcCommandStop;
-    }
-
-    return command;
-}
-
-NfcCommand nfc_magic_scene_write_gen4_poller_callback(Gen4PollerEvent event, void* context) {
+NfcCommand nfc_mafic_scene_write_gen4_poller_callback(Gen4PollerEvent event, void* context) {
     NfcMagicApp* instance = context;
     furi_assert(event.data);
 
@@ -122,20 +90,12 @@ void nfc_magic_scene_write_on_enter(void* context) {
     if(instance->protocol == NfcMagicProtocolGen1) {
         instance->gen1a_poller = gen1a_poller_alloc(instance->nfc);
         gen1a_poller_start(
-            instance->gen1a_poller, nfc_magic_scene_write_gen1_poller_callback, instance);
-    } else if(instance->protocol == NfcMagicProtocolGen2) {
-        instance->gen2_poller = gen2_poller_alloc(instance->nfc);
-        gen2_poller_start(
-            instance->gen2_poller, nfc_magic_scene_write_gen2_poller_callback, instance);
-    } else if(instance->protocol == NfcMagicProtocolClassic) {
-        instance->gen2_poller = gen2_poller_alloc(instance->nfc);
-        gen2_poller_start(
-            instance->gen2_poller, nfc_magic_scene_write_gen2_poller_callback, instance);
+            instance->gen1a_poller, nfc_mafic_scene_write_gen1_poller_callback, instance);
     } else {
         instance->gen4_poller = gen4_poller_alloc(instance->nfc);
         gen4_poller_set_password(instance->gen4_poller, instance->gen4_password);
         gen4_poller_start(
-            instance->gen4_poller, nfc_magic_scene_write_gen4_poller_callback, instance);
+            instance->gen4_poller, nfc_mafic_scene_write_gen4_poller_callback, instance);
     }
 }
 
@@ -172,12 +132,7 @@ void nfc_magic_scene_write_on_exit(void* context) {
     if(instance->protocol == NfcMagicProtocolGen1) {
         gen1a_poller_stop(instance->gen1a_poller);
         gen1a_poller_free(instance->gen1a_poller);
-    } else if(
-        instance->protocol == NfcMagicProtocolGen2 ||
-        instance->protocol == NfcMagicProtocolClassic) {
-        gen2_poller_stop(instance->gen2_poller);
-        gen2_poller_free(instance->gen2_poller);
-    } else if(instance->protocol == NfcMagicProtocolGen4) {
+    } else {
         gen4_poller_stop(instance->gen4_poller);
         gen4_poller_free(instance->gen4_poller);
     }

+ 14 - 6
nfc_magic/scenes/nfc_magic_scene_write_fail.c

@@ -16,14 +16,20 @@ void nfc_magic_scene_write_fail_on_enter(void* context) {
 
     notification_message(instance->notifications, &sequence_error);
 
-    widget_add_icon_element(widget, 83, 22, &I_WarningDolphinFlip_45x42);
+    widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48);
     widget_add_string_element(
-        widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Failed to Write");
+        widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!");
     widget_add_string_multiline_element(
-        widget, 0, 13, AlignLeft, AlignTop, FontSecondary, "Something went\nwrong while\nwriting");
+        widget,
+        7,
+        17,
+        AlignLeft,
+        AlignTop,
+        FontSecondary,
+        "Not all sectors\nwere written\ncorrectly.");
 
     widget_add_button_element(
-        widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_write_fail_widget_callback, instance);
+        widget, GuiButtonTypeLeft, "Finish", nfc_magic_scene_write_fail_widget_callback, instance);
 
     // Setup and start worker
     view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
@@ -35,10 +41,12 @@ bool nfc_magic_scene_write_fail_on_event(void* context, SceneManagerEvent event)
 
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == GuiButtonTypeLeft) {
-            consumed = scene_manager_previous_scene(instance->scene_manager);
+            consumed = scene_manager_search_and_switch_to_previous_scene(
+                instance->scene_manager, NfcMagicSceneStart);
         }
     } else if(event.type == SceneManagerEventTypeBack) {
-        consumed = scene_manager_previous_scene(instance->scene_manager);
+        consumed = scene_manager_search_and_switch_to_previous_scene(
+            instance->scene_manager, NfcMagicSceneStart);
     }
     return consumed;
 }

+ 0 - 245
nfc_magic/views/dict_attack.c

@@ -1,245 +0,0 @@
-#include "dict_attack.h"
-
-#include <gui/elements.h>
-
-#define NFC_CLASSIC_KEYS_PER_SECTOR 2
-
-struct DictAttack {
-    View* view;
-    DictAttackCallback callback;
-    void* context;
-};
-
-typedef struct {
-    FuriString* header;
-    bool card_detected;
-    uint8_t sectors_total;
-    uint8_t sectors_read;
-    uint8_t current_sector;
-    uint8_t keys_found;
-    size_t dict_keys_total;
-    size_t dict_keys_current;
-    bool is_key_attack;
-    uint8_t key_attack_current_sector;
-} DictAttackViewModel;
-
-static void dict_attack_draw_callback(Canvas* canvas, void* model) {
-    DictAttackViewModel* m = model;
-    if(!m->card_detected) {
-        canvas_set_font(canvas, FontPrimary);
-        canvas_draw_str_aligned(
-            canvas, 64, 4, AlignCenter, AlignTop, "Hold the tag to the Flipper!");
-        canvas_set_font(canvas, FontSecondary);
-        elements_multiline_text_aligned(
-            canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly.");
-    } else {
-        char draw_str[32] = {};
-        canvas_set_font(canvas, FontSecondary);
-        canvas_draw_str_aligned(
-            canvas, 64, 0, AlignCenter, AlignTop, furi_string_get_cstr(m->header));
-        if(m->is_key_attack) {
-            snprintf(
-                draw_str,
-                sizeof(draw_str),
-                "Reuse key check for sector: %d",
-                m->key_attack_current_sector);
-        } else {
-            snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->current_sector);
-        }
-        canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str);
-        float dict_progress = m->dict_keys_total == 0 ?
-                                  0 :
-                                  (float)(m->dict_keys_current) / (float)(m->dict_keys_total);
-        float progress = m->sectors_total == 0 ? 0 :
-                                                 ((float)(m->current_sector) + dict_progress) /
-                                                     (float)(m->sectors_total);
-        if(progress > 1.0f) {
-            progress = 1.0f;
-        }
-        if(m->dict_keys_current == 0) {
-            // Cause when people see 0 they think it's broken
-            snprintf(draw_str, sizeof(draw_str), "%d/%zu", 1, m->dict_keys_total);
-        } else {
-            snprintf(
-                draw_str, sizeof(draw_str), "%zu/%zu", m->dict_keys_current, m->dict_keys_total);
-        }
-        elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str);
-        canvas_set_font(canvas, FontSecondary);
-        snprintf(
-            draw_str,
-            sizeof(draw_str),
-            "Keys found: %d/%d",
-            m->keys_found,
-            m->sectors_total * NFC_CLASSIC_KEYS_PER_SECTOR);
-        canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str);
-        snprintf(
-            draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total);
-        canvas_draw_str_aligned(canvas, 0, 43, AlignLeft, AlignTop, draw_str);
-    }
-    elements_button_center(canvas, "Skip");
-}
-
-static bool dict_attack_input_callback(InputEvent* event, void* context) {
-    DictAttack* instance = context;
-    bool consumed = false;
-
-    if(event->type == InputTypeShort && event->key == InputKeyOk) {
-        if(instance->callback) {
-            instance->callback(DictAttackEventSkipPressed, instance->context);
-        }
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-DictAttack* dict_attack_alloc() {
-    DictAttack* instance = malloc(sizeof(DictAttack));
-    instance->view = view_alloc();
-    view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(DictAttackViewModel));
-    view_set_draw_callback(instance->view, dict_attack_draw_callback);
-    view_set_input_callback(instance->view, dict_attack_input_callback);
-    view_set_context(instance->view, instance);
-    with_view_model(
-        instance->view,
-        DictAttackViewModel * model,
-        { model->header = furi_string_alloc(); },
-        false);
-
-    return instance;
-}
-
-void dict_attack_free(DictAttack* instance) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view, DictAttackViewModel * model, { furi_string_free(model->header); }, false);
-
-    view_free(instance->view);
-    free(instance);
-}
-
-void dict_attack_reset(DictAttack* instance) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        DictAttackViewModel * model,
-        {
-            model->sectors_total = 0;
-            model->sectors_read = 0;
-            model->current_sector = 0;
-            model->keys_found = 0;
-            model->dict_keys_total = 0;
-            model->dict_keys_current = 0;
-            model->is_key_attack = false;
-            furi_string_reset(model->header);
-        },
-        false);
-}
-
-View* dict_attack_get_view(DictAttack* instance) {
-    furi_assert(instance);
-
-    return instance->view;
-}
-
-void dict_attack_set_callback(DictAttack* instance, DictAttackCallback callback, void* context) {
-    furi_assert(instance);
-    furi_assert(callback);
-
-    instance->callback = callback;
-    instance->context = context;
-}
-
-void dict_attack_set_header(DictAttack* instance, const char* header) {
-    furi_assert(instance);
-    furi_assert(header);
-
-    with_view_model(
-        instance->view,
-        DictAttackViewModel * model,
-        { furi_string_set(model->header, header); },
-        true);
-}
-
-void dict_attack_set_card_state(DictAttack* instance, bool detected) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view, DictAttackViewModel * model, { model->card_detected = detected; }, true);
-}
-
-void dict_attack_set_sectors_total(DictAttack* instance, uint8_t sectors_total) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        DictAttackViewModel * model,
-        { model->sectors_total = sectors_total; },
-        true);
-}
-
-void dict_attack_set_sectors_read(DictAttack* instance, uint8_t sectors_read) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view, DictAttackViewModel * model, { model->sectors_read = sectors_read; }, true);
-}
-
-void dict_attack_set_keys_found(DictAttack* instance, uint8_t keys_found) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view, DictAttackViewModel * model, { model->keys_found = keys_found; }, true);
-}
-
-void dict_attack_set_current_sector(DictAttack* instance, uint8_t current_sector) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        DictAttackViewModel * model,
-        { model->current_sector = current_sector; },
-        true);
-}
-
-void dict_attack_set_total_dict_keys(DictAttack* instance, size_t dict_keys_total) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        DictAttackViewModel * model,
-        { model->dict_keys_total = dict_keys_total; },
-        true);
-}
-
-void dict_attack_set_current_dict_key(DictAttack* instance, size_t cur_key_num) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        DictAttackViewModel * model,
-        { model->dict_keys_current = cur_key_num; },
-        true);
-}
-
-void dict_attack_set_key_attack(DictAttack* instance, uint8_t sector) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        DictAttackViewModel * model,
-        {
-            model->is_key_attack = true;
-            model->key_attack_current_sector = sector;
-        },
-        true);
-}
-
-void dict_attack_reset_key_attack(DictAttack* instance) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view, DictAttackViewModel * model, { model->is_key_attack = false; }, true);
-}

+ 0 - 50
nfc_magic/views/dict_attack.h

@@ -1,50 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <gui/view.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct DictAttack DictAttack;
-
-typedef enum {
-    DictAttackEventSkipPressed,
-} DictAttackEvent;
-
-typedef void (*DictAttackCallback)(DictAttackEvent event, void* context);
-
-DictAttack* dict_attack_alloc();
-
-void dict_attack_free(DictAttack* instance);
-
-void dict_attack_reset(DictAttack* instance);
-
-View* dict_attack_get_view(DictAttack* instance);
-
-void dict_attack_set_callback(DictAttack* instance, DictAttackCallback callback, void* context);
-
-void dict_attack_set_header(DictAttack* instance, const char* header);
-
-void dict_attack_set_card_state(DictAttack* instance, bool detected);
-
-void dict_attack_set_sectors_total(DictAttack* instance, uint8_t sectors_total);
-
-void dict_attack_set_sectors_read(DictAttack* instance, uint8_t sectors_read);
-
-void dict_attack_set_keys_found(DictAttack* instance, uint8_t keys_found);
-
-void dict_attack_set_current_sector(DictAttack* instance, uint8_t curr_sec);
-
-void dict_attack_set_total_dict_keys(DictAttack* instance, size_t dict_keys_total);
-
-void dict_attack_set_current_dict_key(DictAttack* instance, size_t cur_key_num);
-
-void dict_attack_set_key_attack(DictAttack* instance, uint8_t sector);
-
-void dict_attack_reset_key_attack(DictAttack* instance);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 160
nfc_magic/views/write_problems.c

@@ -1,160 +0,0 @@
-#include "write_problems.h"
-
-#include <gui/elements.h>
-#include "nfc_magic_icons.h"
-
-struct WriteProblems {
-    View* view;
-    WriteProblemsCallback callback;
-    void* context;
-};
-
-typedef struct {
-    uint8_t problem_index;
-    uint8_t problems_total;
-    FuriString* content;
-} WriteProblemsViewModel;
-
-static void write_problems_view_draw_callback(Canvas* canvas, void* _model) {
-    WriteProblemsViewModel* model = _model;
-    FuriString* header = furi_string_alloc();
-    canvas_clear(canvas);
-
-    // Header
-    if(model->problems_total > 1) {
-        furi_string_printf(
-            header, "Warnings: %d of %d\n", model->problem_index + 1, model->problems_total);
-    } else {
-        furi_string_printf(header, "Warning!");
-    }
-
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str_aligned(canvas, 64, 0, AlignCenter, AlignTop, furi_string_get_cstr(header));
-
-    // Warning message
-    canvas_set_font(canvas, FontSecondary);
-    elements_text_box(
-        canvas, 1, 13, 76, 42, AlignLeft, AlignTop, furi_string_get_cstr(model->content), false);
-
-    // Butttons
-    if(model->problem_index == model->problems_total - 1) {
-        elements_button_center(canvas, "Skip");
-        elements_button_left(canvas, "Retry");
-    } else {
-        elements_button_center(canvas, "Next");
-        elements_button_left(canvas, "Back");
-    }
-
-    // Dolphin
-    canvas_draw_icon(canvas, 83, 22, &I_WarningDolphinFlip_45x42);
-
-    furi_string_free(header);
-}
-
-static bool write_problems_input_callback(InputEvent* event, void* context) {
-    WriteProblems* instance = context;
-
-    if(event->type == InputTypeShort) {
-        if(event->key == InputKeyLeft) {
-            instance->callback(WriteProblemsEventLeftPressed, instance->context);
-            return true;
-        } else if(event->key == InputKeyOk) {
-            instance->callback(WriteProblemsEventCenterPressed, instance->context);
-            return true;
-        }
-    }
-    return false;
-}
-
-WriteProblems* write_problems_alloc() {
-    WriteProblems* instance = malloc(sizeof(WriteProblems));
-    instance->view = view_alloc();
-    view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(WriteProblemsViewModel));
-    view_set_draw_callback(instance->view, write_problems_view_draw_callback);
-    view_set_input_callback(instance->view, write_problems_input_callback);
-    view_set_context(instance->view, instance);
-    with_view_model(
-        instance->view,
-        WriteProblemsViewModel * model,
-        {
-            model->content = furi_string_alloc();
-            model->problem_index = 0;
-            model->problems_total = 0;
-        },
-        false);
-
-    return instance;
-}
-
-void write_problems_free(WriteProblems* instance) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        WriteProblemsViewModel * model,
-        { furi_string_free(model->content); },
-        false);
-
-    view_free(instance->view);
-    free(instance);
-}
-
-void write_problems_reset(WriteProblems* instance) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        WriteProblemsViewModel * model,
-        {
-            model->problem_index = 0;
-            model->problems_total = 0;
-            furi_string_reset(model->content);
-        },
-        true);
-}
-
-View* write_problems_get_view(WriteProblems* instance) {
-    furi_assert(instance);
-
-    return instance->view;
-}
-
-void write_problems_set_callback(
-    WriteProblems* instance,
-    WriteProblemsCallback callback,
-    void* context) {
-    furi_assert(instance);
-    instance->callback = callback;
-    instance->context = context;
-}
-
-void write_problems_set_content(WriteProblems* instance, const char* content) {
-    furi_assert(instance);
-    furi_assert(content);
-
-    with_view_model(
-        instance->view,
-        WriteProblemsViewModel * model,
-        { furi_string_set(model->content, content); },
-        true);
-}
-
-void write_problems_set_problems_total(WriteProblems* instance, uint8_t problems_total) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        WriteProblemsViewModel * model,
-        { model->problems_total = problems_total; },
-        true);
-}
-
-void write_problems_set_problem_index(WriteProblems* instance, uint8_t problem_index) {
-    furi_assert(instance);
-
-    with_view_model(
-        instance->view,
-        WriteProblemsViewModel * model,
-        { model->problem_index = problem_index; },
-        true);
-}

+ 0 - 32
nfc_magic/views/write_problems.h

@@ -1,32 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <gui/view.h>
-
-typedef struct WriteProblems WriteProblems;
-
-typedef enum {
-    WriteProblemsEventCenterPressed,
-    WriteProblemsEventLeftPressed,
-} WriteProblemsEvent;
-
-typedef void (*WriteProblemsCallback)(WriteProblemsEvent event, void* context);
-
-WriteProblems* write_problems_alloc();
-
-void write_problems_free(WriteProblems* instance);
-
-void write_problems_reset(WriteProblems* instance);
-
-View* write_problems_get_view(WriteProblems* instance);
-
-void write_problems_set_callback(
-    WriteProblems* instance,
-    WriteProblemsCallback callback,
-    void* context);
-
-void write_problems_set_content(WriteProblems* instance, const char* content);
-
-void write_problems_set_problem_index(WriteProblems* instance, uint8_t index);
-
-void write_problems_set_problems_total(WriteProblems* instance, uint8_t total);