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>
This commit is contained in:
		
							parent
							
								
									17d01f5c29
								
							
						
					
					
						commit
						3846852f2b
					
				| @ -3,6 +3,7 @@ | |||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| #include <lib/flipper_format/flipper_format.h> | #include <lib/flipper_format/flipper_format.h> | ||||||
| #include <lib/nfc/protocols/nfca.h> | #include <lib/nfc/protocols/nfca.h> | ||||||
|  | #include <lib/nfc/helpers/mf_classic_dict.h> | ||||||
| #include <lib/digital_signal/digital_signal.h> | #include <lib/digital_signal/digital_signal.h> | ||||||
| 
 | 
 | ||||||
| #include <lib/flipper_format/flipper_format_i.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"); |         "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) { | MU_TEST_SUITE(nfc) { | ||||||
|     nfc_test_alloc(); |     nfc_test_alloc(); | ||||||
| 
 | 
 | ||||||
|     MU_RUN_TEST(nfc_digital_signal_test); |     MU_RUN_TEST(nfc_digital_signal_test); | ||||||
|  |     MU_RUN_TEST(mf_classic_dict_test); | ||||||
| 
 | 
 | ||||||
|     nfc_test_free(); |     nfc_test_free(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| 
 | 
 | ||||||
| #define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") | #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_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" | #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; |         dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK; | ||||||
|     } else if(dict_type == MfClassicDictTypeUser) { |     } else if(dict_type == MfClassicDictTypeUser) { | ||||||
|         dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK; |         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); |     furi_record_close(RECORD_STORAGE); | ||||||
| @ -50,6 +54,15 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) { | |||||||
|                 buffered_file_stream_close(dict->stream); |                 buffered_file_stream_close(dict->stream); | ||||||
|                 break; |                 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
 |         // 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) { |     for(uint8_t i = 0; i < 12; i += 2) { | ||||||
|         args_char_to_hex( |         args_char_to_hex( | ||||||
|             string_get_char(key_str, i), string_get_char(key_str, i + 1), &key_byte_tmp); |             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); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -9,18 +9,41 @@ | |||||||
| typedef enum { | typedef enum { | ||||||
|     MfClassicDictTypeUser, |     MfClassicDictTypeUser, | ||||||
|     MfClassicDictTypeFlipper, |     MfClassicDictTypeFlipper, | ||||||
|  |     MfClassicDictTypeUnitTest, | ||||||
| } MfClassicDictType; | } MfClassicDictType; | ||||||
| 
 | 
 | ||||||
| typedef struct MfClassicDict MfClassicDict; | typedef struct MfClassicDict MfClassicDict; | ||||||
| 
 | 
 | ||||||
| bool mf_classic_dict_check_presence(MfClassicDictType dict_type); | 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); | MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type); | ||||||
| 
 | 
 | ||||||
|  | /** Free MfClassicDict instance
 | ||||||
|  |  * | ||||||
|  |  * @param      dict  MfClassicDict instance | ||||||
|  |  */ | ||||||
| void mf_classic_dict_free(MfClassicDict* dict); | 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); | 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_rewind(MfClassicDict* dict); | ||||||
| 
 | 
 | ||||||
| bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key); | 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); | 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); | 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_get_key_at_index_str(MfClassicDict* dict, string_t key, uint32_t target); | ||||||
| 
 | 
 | ||||||
| bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key); | 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_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(MfClassicDict* dict, uint8_t* key, uint32_t* target); | ||||||
| 
 | 
 | ||||||
| bool mf_classic_dict_find_index_str(MfClassicDict* dict, string_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); | bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Andrea Sacchi
						Andrea Sacchi