From 3846852f2bd4cad37f5e4ce95fe453aa129f978f Mon Sep 17 00:00:00 2001 From: Andrea Sacchi Date: Thu, 22 Sep 2022 19:35:28 +0200 Subject: [PATCH] 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 --- applications/debug/unit_tests/nfc/nfc_test.c | 50 ++++++++++++++++++ lib/nfc/helpers/mf_classic_dict.c | 15 +++++- lib/nfc/helpers/mf_classic_dict.h | 53 ++++++++++++++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index e8119992..580943f2 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -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(); } diff --git a/lib/nfc/helpers/mf_classic_dict.c b/lib/nfc/helpers/mf_classic_dict.c index a615e789..5bb67145 100644 --- a/lib/nfc/helpers/mf_classic_dict.c +++ b/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); } } diff --git a/lib/nfc/helpers/mf_classic_dict.h b/lib/nfc/helpers/mf_classic_dict.h index aaea3c40..9241a37b 100644 --- a/lib/nfc/helpers/mf_classic_dict.h +++ b/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);