Просмотр исходного кода

NFC: add MIFARE MINI support (#2307)

* NFC: add MIFARE MINI support
* Move new value to end of enum
* nfc: added missing unit test

Co-authored-by: gornekich <n.gorbadey@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
Giacomo Ferretti 3 лет назад
Родитель
Сommit
eee5c35400

+ 5 - 0
applications/debug/unit_tests/nfc/nfc_test.c

@@ -466,6 +466,10 @@ static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) {
     nfc_device_free(nfc_keys);
 }
 
+MU_TEST(mf_mini_file_test) {
+    mf_classic_generator_test(4, MfClassicTypeMini);
+}
+
 MU_TEST(mf_classic_1k_4b_file_test) {
     mf_classic_generator_test(4, MfClassicType1k);
 }
@@ -486,6 +490,7 @@ MU_TEST_SUITE(nfc) {
     nfc_test_alloc();
 
     MU_RUN_TEST(nfca_file_test);
+    MU_RUN_TEST(mf_mini_file_test);
     MU_RUN_TEST(mf_classic_1k_4b_file_test);
     MU_RUN_TEST(mf_classic_4k_4b_file_test);
     MU_RUN_TEST(mf_classic_1k_7b_file_test);

+ 22 - 0
lib/nfc/helpers/nfc_generators.c

@@ -352,11 +352,27 @@ void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType
         }
         // Set SAK to 08
         data->nfc_data.sak = 0x08;
+    } else if(type == MfClassicTypeMini) {
+        // Set every block to 0xFF
+        for(uint16_t i = 1; i < MF_MINI_TOTAL_SECTORS_NUM * 4; i += 1) {
+            if(mf_classic_is_sector_trailer(i)) {
+                nfc_generate_mf_classic_sector_trailer(mfc, i);
+            } else {
+                memset(&mfc->block[i].value, 0xFF, 16);
+            }
+            mf_classic_set_block_read(mfc, i, &mfc->block[i]);
+        }
+        // Set SAK to 09
+        data->nfc_data.sak = 0x09;
     }
 
     mfc->type = type;
 }
 
+static void nfc_generate_mf_mini(NfcDeviceData* data) {
+    nfc_generate_mf_classic(data, 4, MfClassicTypeMini);
+}
+
 static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) {
     nfc_generate_mf_classic(data, 4, MfClassicType1k);
 }
@@ -438,6 +454,11 @@ static const NfcGenerator ntag_i2c_plus_2k_generator = {
     .generator_func = nfc_generate_ntag_i2c_plus_2k,
 };
 
+static const NfcGenerator mifare_mini_generator = {
+    .name = "Mifare Mini",
+    .generator_func = nfc_generate_mf_mini,
+};
+
 static const NfcGenerator mifare_classic_1k_4b_uid_generator = {
     .name = "Mifare Classic 1k 4byte UID",
     .generator_func = nfc_generate_mf_classic_1k_4b_uid,
@@ -472,6 +493,7 @@ const NfcGenerator* const nfc_generators[] = {
     &ntag_i2c_2k_generator,
     &ntag_i2c_plus_1k_generator,
     &ntag_i2c_plus_2k_generator,
+    &mifare_mini_generator,
     &mifare_classic_1k_4b_uid_generator,
     &mifare_classic_1k_7b_uid_generator,
     &mifare_classic_4k_4b_uid_generator,

+ 14 - 4
lib/nfc/nfc_device.c

@@ -745,7 +745,10 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice*
     do {
         if(!flipper_format_write_comment_cstr(file, "Mifare Classic specific data")) break;
 
-        if(data->type == MfClassicType1k) {
+        if(data->type == MfClassicTypeMini) {
+            if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "MINI")) break;
+            blocks = 20;
+        } else if(data->type == MfClassicType1k) {
             if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break;
             blocks = 64;
         } else if(data->type == MfClassicType4k) {
@@ -843,7 +846,10 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice*
     do {
         // Read Mifare Classic type
         if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break;
-        if(!furi_string_cmp(temp_str, "1K")) {
+        if(!furi_string_cmp(temp_str, "MINI")) {
+            data->type = MfClassicTypeMini;
+            data_blocks = 20;
+        } else if(!furi_string_cmp(temp_str, "1K")) {
             data->type = MfClassicType1k;
             data_blocks = 64;
         } else if(!furi_string_cmp(temp_str, "4K")) {
@@ -918,7 +924,9 @@ static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) {
         if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
         if(!flipper_format_write_header_cstr(file, nfc_keys_file_header, nfc_keys_file_version))
             break;
-        if(data->type == MfClassicType1k) {
+        if(data->type == MfClassicTypeMini) {
+            if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "MINI")) break;
+        } else if(data->type == MfClassicType1k) {
             if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break;
         } else if(data->type == MfClassicType4k) {
             if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "4K")) break;
@@ -968,7 +976,9 @@ bool nfc_device_load_key_cache(NfcDevice* dev) {
         if(furi_string_cmp_str(temp_str, nfc_keys_file_header)) break;
         if(version != nfc_keys_file_version) break;
         if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break;
-        if(!furi_string_cmp(temp_str, "1K")) {
+        if(!furi_string_cmp(temp_str, "MINI")) {
+            data->type = MfClassicTypeMini;
+        } else if(!furi_string_cmp(temp_str, "1K")) {
             data->type = MfClassicType1k;
         } else if(!furi_string_cmp(temp_str, "4K")) {
             data->type = MfClassicType4k;

+ 3 - 1
lib/nfc/nfc_types.c

@@ -55,7 +55,9 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) {
 }
 
 const char* nfc_mf_classic_type(MfClassicType type) {
-    if(type == MfClassicType1k) {
+    if(type == MfClassicTypeMini) {
+        return "Mifare Mini 0.3K";
+    } else if(type == MfClassicType1k) {
         return "Mifare Classic 1K";
     } else if(type == MfClassicType4k) {
         return "Mifare Classic 4K";

+ 15 - 5
lib/nfc/protocols/mifare_classic.c

@@ -13,7 +13,9 @@
 #define MF_CLASSIC_WRITE_BLOCK_CMD (0xA0)
 
 const char* mf_classic_get_type_str(MfClassicType type) {
-    if(type == MfClassicType1k) {
+    if(type == MfClassicTypeMini) {
+        return "MIFARE Mini 0.3K";
+    } else if(type == MfClassicType1k) {
         return "MIFARE Classic 1K";
     } else if(type == MfClassicType4k) {
         return "MIFARE Classic 4K";
@@ -73,7 +75,9 @@ MfClassicSectorTrailer*
 }
 
 uint8_t mf_classic_get_total_sectors_num(MfClassicType type) {
-    if(type == MfClassicType1k) {
+    if(type == MfClassicTypeMini) {
+        return MF_MINI_TOTAL_SECTORS_NUM;
+    } else if(type == MfClassicType1k) {
         return MF_CLASSIC_1K_TOTAL_SECTORS_NUM;
     } else if(type == MfClassicType4k) {
         return MF_CLASSIC_4K_TOTAL_SECTORS_NUM;
@@ -83,7 +87,9 @@ uint8_t mf_classic_get_total_sectors_num(MfClassicType type) {
 }
 
 uint16_t mf_classic_get_total_block_num(MfClassicType type) {
-    if(type == MfClassicType1k) {
+    if(type == MfClassicTypeMini) {
+        return 20;
+    } else if(type == MfClassicType1k) {
         return 64;
     } else if(type == MfClassicType4k) {
         return 256;
@@ -363,8 +369,12 @@ bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
 
 MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
     UNUSED(ATQA1);
-    if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) {
-        return MfClassicType1k;
+    if((ATQA0 == 0x44 || ATQA0 == 0x04)) {
+        if((SAK == 0x08 || SAK == 0x88)) {
+            return MfClassicType1k;
+        } else if(SAK == 0x09) {
+            return MfClassicTypeMini;
+        }
     } else if((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01)) {
         //skylanders support
         return MfClassicType1k;

+ 2 - 0
lib/nfc/protocols/mifare_classic.h

@@ -6,6 +6,7 @@
 
 #define MF_CLASSIC_BLOCK_SIZE (16)
 #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256)
+#define MF_MINI_TOTAL_SECTORS_NUM (5)
 #define MF_CLASSIC_1K_TOTAL_SECTORS_NUM (16)
 #define MF_CLASSIC_4K_TOTAL_SECTORS_NUM (40)
 
@@ -20,6 +21,7 @@
 typedef enum {
     MfClassicType1k,
     MfClassicType4k,
+    MfClassicTypeMini,
 } MfClassicType;
 
 typedef enum {