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

NFC Fix Mifare Classic (#1769)

* Fix Mifare Classic key str to int conversion: Wrong cast lead to unexpected behavior converting key from str to int.
* Nfc: fix type cast in mf_classic_dict and add basic unit tests

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Andrea Sacchi 3 лет назад
Родитель
Сommit
3846852f2b

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

@@ -3,6 +3,7 @@
 #include <storage/storage.h>
 #include <lib/flipper_format/flipper_format.h>
 #include <lib/nfc/protocols/nfca.h>
+#include <lib/nfc/helpers/mf_classic_dict.h>
 #include <lib/digital_signal/digital_signal.h>
 
 #include <lib/flipper_format/flipper_format_i.h>
@@ -170,10 +171,59 @@ MU_TEST(nfc_digital_signal_test) {
         "NFC long digital signal test failed\r\n");
 }
 
+MU_TEST(mf_classic_dict_test) {
+    MfClassicDict* instance = NULL;
+    uint64_t key = 0;
+    string_t temp_str;
+    string_init(temp_str);
+
+    instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest);
+    mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n");
+
+    mu_assert(
+        mf_classic_dict_get_total_keys(instance) == 0,
+        "mf_classic_dict_get_total_keys == 0 assert failed\r\n");
+
+    string_set(temp_str, "2196FAD8115B");
+    mu_assert(
+        mf_classic_dict_add_key_str(instance, temp_str),
+        "mf_classic_dict_add_key == true assert failed\r\n");
+
+    mu_assert(
+        mf_classic_dict_get_total_keys(instance) == 1,
+        "mf_classic_dict_get_total_keys == 1 assert failed\r\n");
+
+    mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n");
+
+    mu_assert(
+        mf_classic_dict_get_key_at_index_str(instance, temp_str, 0),
+        "mf_classic_dict_get_key_at_index_str == true assert failed\r\n");
+    mu_assert(
+        string_cmp(temp_str, "2196FAD8115B") == 0,
+        "string_cmp(temp_str, \"2196FAD8115B\") == 0 assert failed\r\n");
+
+    mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n");
+
+    mu_assert(
+        mf_classic_dict_get_key_at_index(instance, &key, 0),
+        "mf_classic_dict_get_key_at_index == true assert failed\r\n");
+    mu_assert(key == 0x2196FAD8115B, "key == 0x2196FAD8115B assert failed\r\n");
+
+    mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n");
+
+    mu_assert(
+        mf_classic_dict_delete_index(instance, 0),
+        "mf_classic_dict_delete_index == true assert failed\r\n");
+
+    mf_classic_dict_free(instance);
+    string_clear(temp_str);
+}
+
 MU_TEST_SUITE(nfc) {
     nfc_test_alloc();
 
     MU_RUN_TEST(nfc_digital_signal_test);
+    MU_RUN_TEST(mf_classic_dict_test);
 
     nfc_test_free();
 }

+ 14 - 1
lib/nfc/helpers/mf_classic_dict.c

@@ -5,6 +5,7 @@
 
 #define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc")
 #define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc")
+#define MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc")
 
 #define TAG "MfClassicDict"
 
@@ -23,6 +24,9 @@ bool mf_classic_dict_check_presence(MfClassicDictType dict_type) {
         dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK;
     } else if(dict_type == MfClassicDictTypeUser) {
         dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK;
+    } else if(dict_type == MfClassicDictTypeUnitTest) {
+        dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_UNIT_TEST_PATH, NULL) ==
+                       FSE_OK;
     }
 
     furi_record_close(RECORD_STORAGE);
@@ -50,6 +54,15 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) {
                 buffered_file_stream_close(dict->stream);
                 break;
             }
+        } else if(dict_type == MfClassicDictTypeUnitTest) {
+            if(!buffered_file_stream_open(
+                   dict->stream,
+                   MF_CLASSIC_DICT_UNIT_TEST_PATH,
+                   FSAM_READ_WRITE,
+                   FSOM_CREATE_ALWAYS)) {
+                buffered_file_stream_close(dict->stream);
+                break;
+            }
         }
 
         // Read total amount of keys
@@ -100,7 +113,7 @@ static void mf_classic_dict_str_to_int(string_t key_str, uint64_t* key_int) {
     for(uint8_t i = 0; i < 12; i += 2) {
         args_char_to_hex(
             string_get_char(key_str, i), string_get_char(key_str, i + 1), &key_byte_tmp);
-        *key_int |= (uint8_t)key_byte_tmp << 8 * (5 - i / 2);
+        *key_int |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2);
     }
 }
 

+ 53 - 0
lib/nfc/helpers/mf_classic_dict.h

@@ -9,18 +9,41 @@
 typedef enum {
     MfClassicDictTypeUser,
     MfClassicDictTypeFlipper,
+    MfClassicDictTypeUnitTest,
 } MfClassicDictType;
 
 typedef struct MfClassicDict MfClassicDict;
 
 bool mf_classic_dict_check_presence(MfClassicDictType dict_type);
 
+/** Allocate MfClassicDict instance
+ *
+ * @param[in]  dict_type  The dictionary type
+ *
+ * @return     MfClassicDict instance
+ */
 MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type);
 
+/** Free MfClassicDict instance
+ *
+ * @param      dict  MfClassicDict instance
+ */
 void mf_classic_dict_free(MfClassicDict* dict);
 
+/** Get total keys count
+ *
+ * @param      dict  MfClassicDict instance
+ *
+ * @return     total keys count
+ */
 uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict);
 
+/** Rewind to the beginning
+ *
+ * @param      dict  MfClassicDict instance
+ *
+ * @return     true on success
+ */
 bool mf_classic_dict_rewind(MfClassicDict* dict);
 
 bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key);
@@ -31,16 +54,46 @@ bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key);
 
 bool mf_classic_dict_get_next_key_str(MfClassicDict* dict, string_t key);
 
+/** Get key at target offset as uint64_t
+ *
+ * @param      dict    MfClassicDict instance
+ * @param[out] key     Pointer to the uint64_t key
+ * @param[in]  target  Target offset from current position
+ *
+ * @return     true on success
+ */
 bool mf_classic_dict_get_key_at_index(MfClassicDict* dict, uint64_t* key, uint32_t target);
 
+/** Get key at target offset as string_t
+ *
+ * @param      dict    MfClassicDict instance
+ * @param[out] key     Found key destination buffer
+ * @param[in]  target  Target offset from current position
+ *
+ * @return     true on success
+ */
 bool mf_classic_dict_get_key_at_index_str(MfClassicDict* dict, string_t key, uint32_t target);
 
 bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key);
 
+/** Add string representation of the key
+ *
+ * @param      dict  MfClassicDict instance
+ * @param[in]  key   String representation of the key
+ *
+ * @return     true on success
+ */
 bool mf_classic_dict_add_key_str(MfClassicDict* dict, string_t key);
 
 bool mf_classic_dict_find_index(MfClassicDict* dict, uint8_t* key, uint32_t* target);
 
 bool mf_classic_dict_find_index_str(MfClassicDict* dict, string_t key, uint32_t* target);
 
+/** Delete key at target offset
+ *
+ * @param      dict    MfClassicDict instance
+ * @param[in]  target  Target offset from current position
+ *
+ * @return     true on success
+ */
 bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target);