 3857cd7d5f
			
		
	
	
		3857cd7d5f
		
			
		
	
	
	
	
		
			
			* Fix TextBox word wrap behavior * Wrap width is 120 pixels, not 140. (140 is larger than the screen!) * Glyph width already includes spacing; don't add 1 additional px * When starting a new line, include wrapped glyph width in new line_width. * Call canvas_set_font before text_box_insert_endline so that glyph width is calculated using correct font. Previous approach worked somewhat well using default TextBoxFontText but this version is more robust, particularly when using TextBoxFontHex. * Add basic Mifare DESFire reading, file/app browser * Fix build with APP_ARCHIVE=0 * Add bool type to flipper_format * Add ability to save and load DESFire card data * Skip over NfcSceneDeviceInfo when viewing saved DESFire info * mf_df_clear: don't leak master key settings key versions * When opening a DESFire card from Archive, retain UID emulation behavior * rm unnecessary \r\n * show Popup instead of leaving view in bad state * Move NfcReaderRequestData out of union This makes it safe to emulate DESFire/EMV without clobbering card data. * Display saved DESFire cards via NfcSceneDeviceInfo * Display and save file metadata even when contents are missing This can happen when a file doesn't allow unauthenticated reads (see the call to mf_df_parse_read_data_response in nfc_worker.c). Co-authored-by: Kevin Wallace <git+flipperzero@kevin.wallace.seattle.wa.us> Co-authored-by: あく <alleteam@gmail.com> Co-authored-by: gornekich <n.gorbadey@gmail.com>
		
			
				
	
	
		
			165 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #pragma once
 | |
| 
 | |
| #include <m-string.h>
 | |
| #include <stdint.h>
 | |
| #include <stdbool.h>
 | |
| 
 | |
| #define MF_DF_GET_VERSION (0x60)
 | |
| #define MF_DF_GET_FREE_MEMORY (0x6E)
 | |
| #define MF_DF_GET_KEY_SETTINGS (0x45)
 | |
| #define MF_DF_GET_KEY_VERSION (0x64)
 | |
| #define MF_DF_GET_APPLICATION_IDS (0x6A)
 | |
| #define MF_DF_SELECT_APPLICATION (0x5A)
 | |
| #define MF_DF_GET_FILE_IDS (0x6F)
 | |
| #define MF_DF_GET_FILE_SETTINGS (0xF5)
 | |
| 
 | |
| #define MF_DF_READ_DATA (0xBD)
 | |
| #define MF_DF_GET_VALUE (0x6C)
 | |
| #define MF_DF_READ_RECORDS (0xBB)
 | |
| 
 | |
| typedef struct {
 | |
|     uint8_t hw_vendor;
 | |
|     uint8_t hw_type;
 | |
|     uint8_t hw_subtype;
 | |
|     uint8_t hw_major;
 | |
|     uint8_t hw_minor;
 | |
|     uint8_t hw_storage;
 | |
|     uint8_t hw_proto;
 | |
| 
 | |
|     uint8_t sw_vendor;
 | |
|     uint8_t sw_type;
 | |
|     uint8_t sw_subtype;
 | |
|     uint8_t sw_major;
 | |
|     uint8_t sw_minor;
 | |
|     uint8_t sw_storage;
 | |
|     uint8_t sw_proto;
 | |
| 
 | |
|     uint8_t uid[7];
 | |
|     uint8_t batch[5];
 | |
|     uint8_t prod_week;
 | |
|     uint8_t prod_year;
 | |
| } MifareDesfireVersion;
 | |
| 
 | |
| typedef struct {
 | |
|     uint32_t bytes;
 | |
| } MifareDesfireFreeMemory; // EV1+ only
 | |
| 
 | |
| typedef struct MifareDesfireKeyVersion {
 | |
|     uint8_t id;
 | |
|     uint8_t version;
 | |
|     struct MifareDesfireKeyVersion* next;
 | |
| } MifareDesfireKeyVersion;
 | |
| 
 | |
| typedef struct {
 | |
|     uint8_t change_key_id;
 | |
|     bool config_changeable;
 | |
|     bool free_create_delete;
 | |
|     bool free_directory_list;
 | |
|     bool master_key_changeable;
 | |
|     uint8_t max_keys;
 | |
|     MifareDesfireKeyVersion* key_version_head;
 | |
| } MifareDesfireKeySettings;
 | |
| 
 | |
| typedef enum {
 | |
|     MifareDesfireFileTypeStandard = 0,
 | |
|     MifareDesfireFileTypeBackup = 1,
 | |
|     MifareDesfireFileTypeValue = 2,
 | |
|     MifareDesfireFileTypeLinearRecord = 3,
 | |
|     MifareDesfireFileTypeCyclicRecord = 4,
 | |
| } MifareDesfireFileType;
 | |
| 
 | |
| typedef enum {
 | |
|     MifareDesfireFileCommunicationSettingsPlaintext = 0,
 | |
|     MifareDesfireFileCommunicationSettingsAuthenticated = 1,
 | |
|     MifareDesfireFileCommunicationSettingsEnciphered = 3,
 | |
| } MifareDesfireFileCommunicationSettings;
 | |
| 
 | |
| typedef struct MifareDesfireFile {
 | |
|     uint8_t id;
 | |
|     MifareDesfireFileType type;
 | |
|     MifareDesfireFileCommunicationSettings comm;
 | |
|     uint16_t access_rights;
 | |
|     union {
 | |
|         struct {
 | |
|             uint32_t size;
 | |
|         } data;
 | |
|         struct {
 | |
|             uint32_t lo_limit;
 | |
|             uint32_t hi_limit;
 | |
|             uint32_t limited_credit_value;
 | |
|             bool limited_credit_enabled;
 | |
|         } value;
 | |
|         struct {
 | |
|             uint32_t size;
 | |
|             uint32_t max;
 | |
|             uint32_t cur;
 | |
|         } record;
 | |
|     } settings;
 | |
|     uint8_t* contents;
 | |
| 
 | |
|     struct MifareDesfireFile* next;
 | |
| } MifareDesfireFile;
 | |
| 
 | |
| typedef struct MifareDesfireApplication {
 | |
|     uint8_t id[3];
 | |
|     MifareDesfireKeySettings* key_settings;
 | |
|     MifareDesfireFile* file_head;
 | |
| 
 | |
|     struct MifareDesfireApplication* next;
 | |
| } MifareDesfireApplication;
 | |
| 
 | |
| typedef struct {
 | |
|     MifareDesfireVersion version;
 | |
|     MifareDesfireFreeMemory* free_memory;
 | |
|     MifareDesfireKeySettings* master_key_settings;
 | |
|     MifareDesfireApplication* app_head;
 | |
| } MifareDesfireData;
 | |
| 
 | |
| void mf_df_clear(MifareDesfireData* data);
 | |
| 
 | |
| void mf_df_cat_data(MifareDesfireData* data, string_t out);
 | |
| void mf_df_cat_card_info(MifareDesfireData* data, string_t out);
 | |
| void mf_df_cat_version(MifareDesfireVersion* version, string_t out);
 | |
| void mf_df_cat_free_mem(MifareDesfireFreeMemory* free_mem, string_t out);
 | |
| void mf_df_cat_key_settings(MifareDesfireKeySettings* ks, string_t out);
 | |
| void mf_df_cat_application_info(MifareDesfireApplication* app, string_t out);
 | |
| void mf_df_cat_application(MifareDesfireApplication* app, string_t out);
 | |
| void mf_df_cat_file(MifareDesfireFile* file, string_t out);
 | |
| 
 | |
| bool mf_df_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
 | |
| 
 | |
| uint16_t mf_df_prepare_get_version(uint8_t* dest);
 | |
| bool mf_df_parse_get_version_response(uint8_t* buf, uint16_t len, MifareDesfireVersion* out);
 | |
| 
 | |
| uint16_t mf_df_prepare_get_free_memory(uint8_t* dest);
 | |
| bool mf_df_parse_get_free_memory_response(uint8_t* buf, uint16_t len, MifareDesfireFreeMemory* out);
 | |
| 
 | |
| uint16_t mf_df_prepare_get_key_settings(uint8_t* dest);
 | |
| bool mf_df_parse_get_key_settings_response(
 | |
|     uint8_t* buf,
 | |
|     uint16_t len,
 | |
|     MifareDesfireKeySettings* out);
 | |
| 
 | |
| uint16_t mf_df_prepare_get_key_version(uint8_t* dest, uint8_t key_id);
 | |
| bool mf_df_parse_get_key_version_response(uint8_t* buf, uint16_t len, MifareDesfireKeyVersion* out);
 | |
| 
 | |
| uint16_t mf_df_prepare_get_application_ids(uint8_t* dest);
 | |
| bool mf_df_parse_get_application_ids_response(
 | |
|     uint8_t* buf,
 | |
|     uint16_t len,
 | |
|     MifareDesfireApplication** app_head);
 | |
| 
 | |
| uint16_t mf_df_prepare_select_application(uint8_t* dest, uint8_t id[3]);
 | |
| bool mf_df_parse_select_application_response(uint8_t* buf, uint16_t len);
 | |
| 
 | |
| uint16_t mf_df_prepare_get_file_ids(uint8_t* dest);
 | |
| bool mf_df_parse_get_file_ids_response(uint8_t* buf, uint16_t len, MifareDesfireFile** file_head);
 | |
| 
 | |
| uint16_t mf_df_prepare_get_file_settings(uint8_t* dest, uint8_t file_id);
 | |
| bool mf_df_parse_get_file_settings_response(uint8_t* buf, uint16_t len, MifareDesfireFile* out);
 | |
| 
 | |
| uint16_t mf_df_prepare_read_data(uint8_t* dest, uint8_t file_id, uint32_t offset, uint32_t len);
 | |
| uint16_t mf_df_prepare_get_value(uint8_t* dest, uint8_t file_id);
 | |
| uint16_t mf_df_prepare_read_records(uint8_t* dest, uint8_t file_id, uint32_t offset, uint32_t len);
 | |
| bool mf_df_parse_read_data_response(uint8_t* buf, uint16_t len, MifareDesfireFile* out);
 |