* nfc: refactor nfc_worker_read_mifare_desfire to use furi_hal_nfc_tx_rx Renames furi_hal_nfc_exchange_full to furi_hal_nfc_tx_rx_full, and rewrites it to use furi_hal_nfc_tx_rx. This eliminates the final remaining use of furi_hal_nfc_exchange, so remove that. * nfc: write debug.pcap when debug mode enabled Limited to NFC protocols that use furi_hal_nfc_tx_rx to communicate. * switch to Doxygen style comment Co-authored-by: Kevin Wallace <git+flipperzero@kevin.wallace.seattle.wa.us> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									d5df4027d7
								
							
						
					
					
						commit
						9c9f66a30f
					
				
							
								
								
									
										99
									
								
								applications/nfc/helpers/nfc_debug_pcap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								applications/nfc/helpers/nfc_debug_pcap.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | ||||
| #include "nfc_debug_pcap.h" | ||||
| 
 | ||||
| #include <furi_hal_rtc.h> | ||||
| 
 | ||||
| #define TAG "NfcDebugPcap" | ||||
| 
 | ||||
| #define PCAP_MAGIC 0xa1b2c3d4 | ||||
| #define PCAP_MAJOR 2 | ||||
| #define PCAP_MINOR 4 | ||||
| #define DLT_ISO_14443 264 | ||||
| 
 | ||||
| #define DATA_PICC_TO_PCD 0xFF | ||||
| #define DATA_PCD_TO_PICC 0xFE | ||||
| #define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB | ||||
| #define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA | ||||
| 
 | ||||
| File* nfc_debug_pcap_open(Storage* storage) { | ||||
|     File* file = storage_file_alloc(storage); | ||||
|     if(!storage_file_open(file, "/ext/nfc/debug.pcap", FSAM_WRITE, FSOM_OPEN_APPEND)) { | ||||
|         storage_file_free(file); | ||||
|         return NULL; | ||||
|     } | ||||
|     if(!storage_file_tell(file)) { | ||||
|         struct { | ||||
|             uint32_t magic; | ||||
|             uint16_t major, minor; | ||||
|             uint32_t reserved[2]; | ||||
|             uint32_t snaplen; | ||||
|             uint32_t link_type; | ||||
|         } __attribute__((__packed__)) pcap_hdr = { | ||||
|             .magic = PCAP_MAGIC, | ||||
|             .major = PCAP_MAJOR, | ||||
|             .minor = PCAP_MINOR, | ||||
|             .snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE, | ||||
|             .link_type = DLT_ISO_14443, | ||||
|         }; | ||||
|         if(storage_file_write(file, &pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) { | ||||
|             FURI_LOG_E(TAG, "Failed to write pcap header"); | ||||
|         } | ||||
|     } | ||||
|     return file; | ||||
| } | ||||
| 
 | ||||
| void nfc_debug_pcap_write(Storage* storage, uint8_t event, uint8_t* data, uint16_t len) { | ||||
|     File* file = nfc_debug_pcap_open(storage); | ||||
|     if(!file) return; | ||||
| 
 | ||||
|     FuriHalRtcDateTime datetime; | ||||
|     furi_hal_rtc_get_datetime(&datetime); | ||||
| 
 | ||||
|     struct { | ||||
|         // https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header
 | ||||
|         uint32_t ts_sec; | ||||
|         uint32_t ts_usec; | ||||
|         uint32_t incl_len; | ||||
|         uint32_t orig_len; | ||||
|         // https://www.kaiser.cx/posts/pcap-iso14443/#_packet_data
 | ||||
|         uint8_t version; | ||||
|         uint8_t event; | ||||
|         uint16_t len; | ||||
|     } __attribute__((__packed__)) pkt_hdr = { | ||||
|         .ts_sec = furi_hal_rtc_datetime_to_timestamp(&datetime), | ||||
|         .ts_usec = 0, | ||||
|         .incl_len = len + 4, | ||||
|         .orig_len = len + 4, | ||||
|         .version = 0, | ||||
|         .event = event, | ||||
|         .len = len << 8 | len >> 8, | ||||
|     }; | ||||
|     if(storage_file_write(file, &pkt_hdr, sizeof(pkt_hdr)) != sizeof(pkt_hdr)) { | ||||
|         FURI_LOG_E(TAG, "Failed to write pcap packet header"); | ||||
|     } else if(storage_file_write(file, data, len) != len) { | ||||
|         FURI_LOG_E(TAG, "Failed to write pcap packet data"); | ||||
|     } | ||||
|     storage_file_free(file); | ||||
| } | ||||
| 
 | ||||
| void nfc_debug_pcap_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { | ||||
|     uint8_t event = crc_dropped ? DATA_PCD_TO_PICC_CRC_DROPPED : DATA_PCD_TO_PICC; | ||||
|     nfc_debug_pcap_write(context, event, data, bits / 8); | ||||
| } | ||||
| 
 | ||||
| void nfc_debug_pcap_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) { | ||||
|     uint8_t event = crc_dropped ? DATA_PICC_TO_PCD_CRC_DROPPED : DATA_PICC_TO_PCD; | ||||
|     nfc_debug_pcap_write(context, event, data, bits / 8); | ||||
| } | ||||
| 
 | ||||
| void nfc_debug_pcap_prepare_tx_rx(FuriHalNfcTxRxContext* tx_rx, Storage* storage, bool is_picc) { | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { | ||||
|         if(is_picc) { | ||||
|             tx_rx->sniff_tx = nfc_debug_pcap_write_rx; | ||||
|             tx_rx->sniff_rx = nfc_debug_pcap_write_tx; | ||||
|         } else { | ||||
|             tx_rx->sniff_tx = nfc_debug_pcap_write_tx; | ||||
|             tx_rx->sniff_rx = nfc_debug_pcap_write_rx; | ||||
|         } | ||||
|         tx_rx->sniff_context = storage; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								applications/nfc/helpers/nfc_debug_pcap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								applications/nfc/helpers/nfc_debug_pcap.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <furi_hal_nfc.h> | ||||
| #include <storage/storage.h> | ||||
| 
 | ||||
| /** Prepare tx/rx context for debug pcap logging, if enabled.
 | ||||
|  * | ||||
|  * @param      tx_rx   TX/RX context to log | ||||
|  * @param      storage Storage to log to | ||||
|  * @param      is_picc if true, record Flipper as PICC, else PCD. | ||||
|  */ | ||||
| void nfc_debug_pcap_prepare_tx_rx(FuriHalNfcTxRxContext* tx_rx, Storage* storage, bool is_picc); | ||||
| @ -10,6 +10,7 @@ | ||||
| #include <lib/nfc_protocols/nfca.h> | ||||
| 
 | ||||
| #include "helpers/nfc_mf_classic_dict.h" | ||||
| #include "helpers/nfc_debug_pcap.h" | ||||
| 
 | ||||
| #define TAG "NfcWorker" | ||||
| 
 | ||||
| @ -153,6 +154,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { | ||||
| 
 | ||||
| void nfc_worker_emulate(NfcWorker* nfc_worker) { | ||||
|     FuriHalNfcTxRxContext tx_rx = {}; | ||||
|     nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true); | ||||
|     FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; | ||||
|     NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; | ||||
| 
 | ||||
| @ -175,6 +177,7 @@ void nfc_worker_emulate(NfcWorker* nfc_worker) { | ||||
| 
 | ||||
| void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { | ||||
|     FuriHalNfcTxRxContext tx_rx = {}; | ||||
|     nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false); | ||||
|     EmvApplication emv_app = {}; | ||||
|     NfcDeviceData* result = nfc_worker->dev_data; | ||||
|     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; | ||||
| @ -206,6 +209,7 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { | ||||
| 
 | ||||
| void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|     FuriHalNfcTxRxContext tx_rx = {}; | ||||
|     nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false); | ||||
|     EmvApplication emv_app = {}; | ||||
|     NfcDeviceData* result = nfc_worker->dev_data; | ||||
|     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; | ||||
| @ -254,6 +258,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
| 
 | ||||
| void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { | ||||
|     FuriHalNfcTxRxContext tx_rx = {}; | ||||
|     nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true); | ||||
|     FuriHalNfcDevData params = { | ||||
|         .uid = {0xCF, 0x72, 0xd4, 0x40}, | ||||
|         .uid_len = 4, | ||||
| @ -278,6 +283,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { | ||||
| 
 | ||||
| void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) { | ||||
|     FuriHalNfcTxRxContext tx_rx = {}; | ||||
|     nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false); | ||||
|     MfUltralightReader reader = {}; | ||||
|     MfUltralightData data = {}; | ||||
|     NfcDeviceData* result = nfc_worker->dev_data; | ||||
| @ -342,6 +348,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | ||||
| void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { | ||||
|     furi_assert(nfc_worker->callback); | ||||
|     FuriHalNfcTxRxContext tx_rx_ctx = {}; | ||||
|     nfc_debug_pcap_prepare_tx_rx(&tx_rx_ctx, nfc_worker->storage, false); | ||||
|     MfClassicAuthContext auth_ctx = {}; | ||||
|     MfClassicReader reader = {}; | ||||
|     uint64_t curr_key = 0; | ||||
| @ -483,7 +490,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { | ||||
| } | ||||
| 
 | ||||
| void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) { | ||||
|     FuriHalNfcTxRxContext tx_rx; | ||||
|     FuriHalNfcTxRxContext tx_rx = {}; | ||||
|     nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true); | ||||
|     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; | ||||
|     MfClassicEmulator emulator = { | ||||
|         .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), | ||||
| @ -511,11 +519,8 @@ void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) { | ||||
| } | ||||
| 
 | ||||
| void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | ||||
|     ReturnCode err; | ||||
|     uint8_t tx_buff[64] = {}; | ||||
|     uint16_t tx_len = 0; | ||||
|     uint8_t rx_buff[512] = {}; | ||||
|     uint16_t rx_len; | ||||
|     FuriHalNfcTxRxContext tx_rx = {}; | ||||
|     nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false); | ||||
|     NfcDeviceData* result = nfc_worker->dev_data; | ||||
|     nfc_device_data_clear(result); | ||||
|     MifareDesfireData* data = &result->mf_df_data; | ||||
| @ -540,37 +545,36 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | ||||
|         result->protocol = NfcDeviceProtocolMifareDesfire; | ||||
| 
 | ||||
|         // Get DESFire version
 | ||||
|         tx_len = mf_df_prepare_get_version(tx_buff); | ||||
|         err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|         if(err != ERR_NONE) { | ||||
|             FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err); | ||||
|         tx_rx.tx_bits = 8 * mf_df_prepare_get_version(tx_rx.tx_data); | ||||
|         if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|             FURI_LOG_W(TAG, "Bad exchange getting version"); | ||||
|             continue; | ||||
|         } | ||||
|         if(!mf_df_parse_get_version_response(rx_buff, rx_len, &data->version)) { | ||||
|         if(!mf_df_parse_get_version_response(tx_rx.rx_data, tx_rx.rx_bits / 8, &data->version)) { | ||||
|             FURI_LOG_W(TAG, "Bad DESFire GET_VERSION response"); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         tx_len = mf_df_prepare_get_free_memory(tx_buff); | ||||
|         err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|         if(err == ERR_NONE) { | ||||
|         tx_rx.tx_bits = 8 * mf_df_prepare_get_free_memory(tx_rx.tx_data); | ||||
|         if(furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|             data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); | ||||
|             memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory)); | ||||
|             if(!mf_df_parse_get_free_memory_response(rx_buff, rx_len, data->free_memory)) { | ||||
|             if(!mf_df_parse_get_free_memory_response( | ||||
|                    tx_rx.rx_data, tx_rx.rx_bits / 8, data->free_memory)) { | ||||
|                 FURI_LOG_D(TAG, "Bad DESFire GET_FREE_MEMORY response (normal for pre-EV1 cards)"); | ||||
|                 free(data->free_memory); | ||||
|                 data->free_memory = NULL; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         tx_len = mf_df_prepare_get_key_settings(tx_buff); | ||||
|         err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|         if(err != ERR_NONE) { | ||||
|             FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err); | ||||
|         tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data); | ||||
|         if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|             FURI_LOG_D(TAG, "Bad exchange getting key settings"); | ||||
|         } else { | ||||
|             data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); | ||||
|             memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); | ||||
|             if(!mf_df_parse_get_key_settings_response(rx_buff, rx_len, data->master_key_settings)) { | ||||
|             if(!mf_df_parse_get_key_settings_response( | ||||
|                    tx_rx.rx_data, tx_rx.rx_bits / 8, data->master_key_settings)) { | ||||
|                 FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); | ||||
|                 free(data->master_key_settings); | ||||
|                 data->master_key_settings = NULL; | ||||
| @ -580,17 +584,16 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | ||||
|             MifareDesfireKeyVersion** key_version_head = | ||||
|                 &data->master_key_settings->key_version_head; | ||||
|             for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { | ||||
|                 tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); | ||||
|                 err = | ||||
|                     furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); | ||||
|                 tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); | ||||
|                 if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|                     FURI_LOG_W(TAG, "Bad exchange getting key version"); | ||||
|                     continue; | ||||
|                 } | ||||
|                 MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); | ||||
|                 memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); | ||||
|                 key_version->id = key_id; | ||||
|                 if(!mf_df_parse_get_key_version_response(rx_buff, rx_len, key_version)) { | ||||
|                 if(!mf_df_parse_get_key_version_response( | ||||
|                        tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { | ||||
|                     FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); | ||||
|                     free(key_version); | ||||
|                     continue; | ||||
| @ -600,31 +603,31 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         tx_len = mf_df_prepare_get_application_ids(tx_buff); | ||||
|         err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|         if(err != ERR_NONE) { | ||||
|             FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err); | ||||
|         tx_rx.tx_bits = 8 * mf_df_prepare_get_application_ids(tx_rx.tx_data); | ||||
|         if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|             FURI_LOG_W(TAG, "Bad exchange getting application IDs"); | ||||
|         } else { | ||||
|             if(!mf_df_parse_get_application_ids_response(rx_buff, rx_len, &data->app_head)) { | ||||
|             if(!mf_df_parse_get_application_ids_response( | ||||
|                    tx_rx.rx_data, tx_rx.rx_bits / 8, &data->app_head)) { | ||||
|                 FURI_LOG_W(TAG, "Bad DESFire GET_APPLICATION_IDS response"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||
|             tx_len = mf_df_prepare_select_application(tx_buff, app->id); | ||||
|             err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|             if(!mf_df_parse_select_application_response(rx_buff, rx_len)) { | ||||
|                 FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err); | ||||
|             tx_rx.tx_bits = 8 * mf_df_prepare_select_application(tx_rx.tx_data, app->id); | ||||
|             if(!furi_hal_nfc_tx_rx_full(&tx_rx) || | ||||
|                !mf_df_parse_select_application_response(tx_rx.rx_data, tx_rx.rx_bits / 8)) { | ||||
|                 FURI_LOG_W(TAG, "Bad exchange selecting application"); | ||||
|                 continue; | ||||
|             } | ||||
|             tx_len = mf_df_prepare_get_key_settings(tx_buff); | ||||
|             err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|             if(err != ERR_NONE) { | ||||
|                 FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err); | ||||
|             tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data); | ||||
|             if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|                 FURI_LOG_W(TAG, "Bad exchange getting key settings"); | ||||
|             } else { | ||||
|                 app->key_settings = malloc(sizeof(MifareDesfireKeySettings)); | ||||
|                 memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings)); | ||||
|                 if(!mf_df_parse_get_key_settings_response(rx_buff, rx_len, app->key_settings)) { | ||||
|                 if(!mf_df_parse_get_key_settings_response( | ||||
|                        tx_rx.rx_data, tx_rx.rx_bits / 8, app->key_settings)) { | ||||
|                     FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); | ||||
|                     free(app->key_settings); | ||||
|                     app->key_settings = NULL; | ||||
| @ -633,17 +636,16 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | ||||
| 
 | ||||
|                 MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head; | ||||
|                 for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) { | ||||
|                     tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); | ||||
|                     err = furi_hal_nfc_exchange_full( | ||||
|                         tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|                     if(err != ERR_NONE) { | ||||
|                         FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); | ||||
|                     tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); | ||||
|                     if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|                         FURI_LOG_W(TAG, "Bad exchange getting key version"); | ||||
|                         continue; | ||||
|                     } | ||||
|                     MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); | ||||
|                     memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); | ||||
|                     key_version->id = key_id; | ||||
|                     if(!mf_df_parse_get_key_version_response(rx_buff, rx_len, key_version)) { | ||||
|                     if(!mf_df_parse_get_key_version_response( | ||||
|                            tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { | ||||
|                         FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); | ||||
|                         free(key_version); | ||||
|                         continue; | ||||
| @ -653,48 +655,45 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             tx_len = mf_df_prepare_get_file_ids(tx_buff); | ||||
|             err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|             if(err != ERR_NONE) { | ||||
|                 FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err); | ||||
|             tx_rx.tx_bits = 8 * mf_df_prepare_get_file_ids(tx_rx.tx_data); | ||||
|             if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|                 FURI_LOG_W(TAG, "Bad exchange getting file IDs"); | ||||
|             } else { | ||||
|                 if(!mf_df_parse_get_file_ids_response(rx_buff, rx_len, &app->file_head)) { | ||||
|                 if(!mf_df_parse_get_file_ids_response( | ||||
|                        tx_rx.rx_data, tx_rx.rx_bits / 8, &app->file_head)) { | ||||
|                     FURI_LOG_W(TAG, "Bad DESFire GET_FILE_IDS response"); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             for(MifareDesfireFile* file = app->file_head; file; file = file->next) { | ||||
|                 tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id); | ||||
|                 err = | ||||
|                     furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err); | ||||
|                 tx_rx.tx_bits = 8 * mf_df_prepare_get_file_settings(tx_rx.tx_data, file->id); | ||||
|                 if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|                     FURI_LOG_W(TAG, "Bad exchange getting file settings"); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if(!mf_df_parse_get_file_settings_response(rx_buff, rx_len, file)) { | ||||
|                 if(!mf_df_parse_get_file_settings_response( | ||||
|                        tx_rx.rx_data, tx_rx.rx_bits / 8, file)) { | ||||
|                     FURI_LOG_W(TAG, "Bad DESFire GET_FILE_SETTINGS response"); | ||||
|                     continue; | ||||
|                 } | ||||
|                 switch(file->type) { | ||||
|                 case MifareDesfireFileTypeStandard: | ||||
|                 case MifareDesfireFileTypeBackup: | ||||
|                     tx_len = mf_df_prepare_read_data(tx_buff, file->id, 0, 0); | ||||
|                     tx_rx.tx_bits = 8 * mf_df_prepare_read_data(tx_rx.tx_data, file->id, 0, 0); | ||||
|                     break; | ||||
|                 case MifareDesfireFileTypeValue: | ||||
|                     tx_len = mf_df_prepare_get_value(tx_buff, file->id); | ||||
|                     tx_rx.tx_bits = 8 * mf_df_prepare_get_value(tx_rx.tx_data, file->id); | ||||
|                     break; | ||||
|                 case MifareDesfireFileTypeLinearRecord: | ||||
|                 case MifareDesfireFileTypeCyclicRecord: | ||||
|                     tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0); | ||||
|                     tx_rx.tx_bits = 8 * mf_df_prepare_read_records(tx_rx.tx_data, file->id, 0, 0); | ||||
|                     break; | ||||
|                 } | ||||
|                 err = | ||||
|                     furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err); | ||||
|                 if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { | ||||
|                     FURI_LOG_W(TAG, "Bad exchange reading file %d", file->id); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if(!mf_df_parse_read_data_response(rx_buff, rx_len, file)) { | ||||
|                 if(!mf_df_parse_read_data_response(tx_rx.rx_data, tx_rx.rx_bits / 8, file)) { | ||||
|                     FURI_LOG_W(TAG, "Bad response reading file %d", file->id); | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
| @ -366,44 +366,6 @@ bool furi_hal_nfc_emulate_nfca( | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| ReturnCode furi_hal_nfc_data_exchange( | ||||
|     uint8_t* tx_buff, | ||||
|     uint16_t tx_len, | ||||
|     uint8_t** rx_buff, | ||||
|     uint16_t** rx_len, | ||||
|     bool deactivate) { | ||||
|     furi_assert(rx_buff); | ||||
|     furi_assert(rx_len); | ||||
| 
 | ||||
|     ReturnCode ret; | ||||
|     rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; | ||||
|     ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); | ||||
|     if(ret != ERR_NONE) { | ||||
|         return ret; | ||||
|     } | ||||
|     uint32_t start = DWT->CYCCNT; | ||||
|     while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { | ||||
|         rfalNfcWorker(); | ||||
|         state = rfalNfcGetState(); | ||||
|         ret = rfalNfcDataExchangeGetStatus(); | ||||
|         if(ret == ERR_BUSY) { | ||||
|             if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { | ||||
|                 ret = ERR_TIMEOUT; | ||||
|                 break; | ||||
|             } | ||||
|             continue; | ||||
|         } else { | ||||
|             start = DWT->CYCCNT; | ||||
|         } | ||||
|         taskYIELD(); | ||||
|     } | ||||
|     if(deactivate) { | ||||
|         rfalNfcDeactivate(false); | ||||
|         rfalLowPowerModeStart(); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { | ||||
|     furi_assert(tx_rx->nfca_signal); | ||||
| 
 | ||||
| @ -576,6 +538,12 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { | ||||
|         FURI_LOG_E(TAG, "Failed to start data exchange"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if(tx_rx->sniff_tx) { | ||||
|         bool crc_dropped = !(flags & RFAL_TXRX_FLAGS_CRC_TX_MANUAL); | ||||
|         tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, crc_dropped, tx_rx->sniff_context); | ||||
|     } | ||||
| 
 | ||||
|     uint32_t start = DWT->CYCCNT; | ||||
|     while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { | ||||
|         rfalNfcWorker(); | ||||
| @ -602,42 +570,42 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { | ||||
|         tx_rx->rx_bits = *temp_rx_bits; | ||||
|     } | ||||
| 
 | ||||
|     if(tx_rx->sniff_rx) { | ||||
|         bool crc_dropped = !(flags & RFAL_TXRX_FLAGS_CRC_RX_KEEP); | ||||
|         tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, crc_dropped, tx_rx->sniff_context); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| ReturnCode furi_hal_nfc_exchange_full( | ||||
|     uint8_t* tx_buff, | ||||
|     uint16_t tx_len, | ||||
|     uint8_t* rx_buff, | ||||
|     uint16_t rx_cap, | ||||
|     uint16_t* rx_len) { | ||||
|     ReturnCode err; | ||||
|     uint8_t* part_buff; | ||||
|     uint16_t* part_len_bits; | ||||
| bool furi_hal_nfc_tx_rx_full(FuriHalNfcTxRxContext* tx_rx) { | ||||
|     uint16_t part_len_bytes; | ||||
| 
 | ||||
|     err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len_bits, false); | ||||
|     part_len_bytes = *part_len_bits / 8; | ||||
|     if(part_len_bytes > rx_cap) { | ||||
|         return ERR_OVERRUN; | ||||
|     if(!furi_hal_nfc_tx_rx(tx_rx, 1000)) { | ||||
|         return false; | ||||
|     } | ||||
|     memcpy(rx_buff, part_buff, part_len_bytes); | ||||
|     *rx_len = part_len_bytes; | ||||
|     while(err == ERR_NONE && rx_buff[0] == 0xAF) { | ||||
|         err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len_bits, false); | ||||
|         part_len_bytes = *part_len_bits / 8; | ||||
|         if(part_len_bytes > rx_cap - *rx_len) { | ||||
|             return ERR_OVERRUN; | ||||
|     while(tx_rx->rx_bits && tx_rx->rx_data[0] == 0xAF) { | ||||
|         FuriHalNfcTxRxContext tmp = *tx_rx; | ||||
|         tmp.tx_data[0] = 0xAF; | ||||
|         tmp.tx_bits = 8; | ||||
|         if(!furi_hal_nfc_tx_rx(&tmp, 1000)) { | ||||
|             return false; | ||||
|         } | ||||
|         part_len_bytes = tmp.rx_bits / 8; | ||||
|         if(part_len_bytes > FURI_HAL_NFC_DATA_BUFF_SIZE - tx_rx->rx_bits / 8) { | ||||
|             FURI_LOG_W(TAG, "Overrun rx buf"); | ||||
|             return false; | ||||
|         } | ||||
|         if(part_len_bytes == 0) { | ||||
|             return ERR_PROTO; | ||||
|             FURI_LOG_W(TAG, "Empty 0xAF response"); | ||||
|             return false; | ||||
|         } | ||||
|         memcpy(rx_buff + *rx_len, part_buff + 1, part_len_bytes - 1); | ||||
|         *rx_buff = *part_buff; | ||||
|         *rx_len += part_len_bytes - 1; | ||||
|         memcpy(tx_rx->rx_data + tx_rx->rx_bits / 8, tmp.rx_data + 1, part_len_bytes - 1); | ||||
|         tx_rx->rx_data[0] = tmp.rx_data[0]; | ||||
|         tx_rx->rx_bits += 8 * (part_len_bytes - 1); | ||||
|     } | ||||
| 
 | ||||
|     return err; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_nfc_sleep() { | ||||
|  | ||||
							
								
								
									
										41
									
								
								firmware/targets/furi_hal_include/furi_hal_nfc.h
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										41
									
								
								firmware/targets/furi_hal_include/furi_hal_nfc.h
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -17,7 +17,7 @@ extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #define FURI_HAL_NFC_UID_MAX_LEN 10 | ||||
| #define FURI_HAL_NFC_DATA_BUFF_SIZE (256) | ||||
| #define FURI_HAL_NFC_DATA_BUFF_SIZE (512) | ||||
| #define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8) | ||||
| 
 | ||||
| #define FURI_HAL_NFC_TXRX_DEFAULT                                                    \ | ||||
| @ -80,6 +80,9 @@ typedef struct { | ||||
|     uint8_t sak; | ||||
| } FuriHalNfcDevData; | ||||
| 
 | ||||
| typedef void ( | ||||
|     *FuriHalNfcTxRxSniffCallback)(uint8_t* data, uint16_t bits, bool crc_dropped, void* context); | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE]; | ||||
|     uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE]; | ||||
| @ -89,6 +92,10 @@ typedef struct { | ||||
|     uint16_t rx_bits; | ||||
|     FuriHalNfcTxRxType tx_rx_type; | ||||
|     NfcaSignal* nfca_signal; | ||||
| 
 | ||||
|     FuriHalNfcTxRxSniffCallback sniff_tx; | ||||
|     FuriHalNfcTxRxSniffCallback sniff_rx; | ||||
|     void* sniff_context; | ||||
| } FuriHalNfcTxRxContext; | ||||
| 
 | ||||
| /** Init nfc
 | ||||
| @ -165,23 +172,6 @@ bool furi_hal_nfc_emulate_nfca( | ||||
|     void* context, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| /** NFC data exchange
 | ||||
|  * | ||||
|  * @param      tx_buff     transmit buffer | ||||
|  * @param      tx_len      transmit buffer length | ||||
|  * @param      rx_buff     receive buffer | ||||
|  * @param      rx_len      receive buffer length | ||||
|  * @param      deactivate  deactivate flag | ||||
|  * | ||||
|  * @return     ST ReturnCode | ||||
|  */ | ||||
| ReturnCode furi_hal_nfc_data_exchange( | ||||
|     uint8_t* tx_buff, | ||||
|     uint16_t tx_len, | ||||
|     uint8_t** rx_buff, | ||||
|     uint16_t** rx_len, | ||||
|     bool deactivate); | ||||
| 
 | ||||
| /** NFC data exchange
 | ||||
|  * | ||||
|  * @param       tx_rx_ctx   FuriHalNfcTxRxContext instance | ||||
| @ -192,20 +182,11 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms); | ||||
| 
 | ||||
| /** NFC data full exhange
 | ||||
|  * | ||||
|  * @param      tx_buff     transmit buffer | ||||
|  * @param      tx_len      transmit buffer length | ||||
|  * @param      rx_buff     receive buffer | ||||
|  * @param      rx_cap      receive buffer capacity | ||||
|  * @param      rx_len      receive buffer length | ||||
|  * @param       tx_rx_ctx   FuriHalNfcTxRxContext instance | ||||
|  * | ||||
|  * @return     ST ReturnCode | ||||
|  * @return      true on success | ||||
|  */ | ||||
| ReturnCode furi_hal_nfc_exchange_full( | ||||
|     uint8_t* tx_buff, | ||||
|     uint16_t tx_len, | ||||
|     uint8_t* rx_buff, | ||||
|     uint16_t rx_cap, | ||||
|     uint16_t* rx_len); | ||||
| bool furi_hal_nfc_tx_rx_full(FuriHalNfcTxRxContext* tx_rx); | ||||
| 
 | ||||
| /** NFC deactivate and start sleep
 | ||||
|  */ | ||||
|  | ||||
| @ -397,7 +397,8 @@ bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) { | ||||
| bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) { | ||||
|     furi_assert(tx_rx); | ||||
|     bool emulation_complete = false; | ||||
|     memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); | ||||
|     tx_rx->tx_bits = 0; | ||||
|     tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; | ||||
| 
 | ||||
|     do { | ||||
|         FURI_LOG_D(TAG, "Read select PPSE command"); | ||||
|  | ||||
| @ -270,7 +270,9 @@ static bool mf_classic_auth( | ||||
|     MfClassicKey key_type, | ||||
|     Crypto1* crypto) { | ||||
|     bool auth_success = false; | ||||
|     memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); | ||||
|     memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data)); | ||||
|     memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity)); | ||||
|     tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; | ||||
| 
 | ||||
|     do { | ||||
|         if(key_type == MfClassicKeyA) { | ||||
| @ -372,7 +374,8 @@ bool mf_classic_read_block( | ||||
|     bool read_block_success = false; | ||||
|     uint8_t plain_cmd[4] = {MF_CLASSIC_READ_SECT_CMD, block_num, 0x00, 0x00}; | ||||
|     nfca_append_crc16(plain_cmd, 2); | ||||
|     memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); | ||||
|     memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data)); | ||||
|     memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity)); | ||||
| 
 | ||||
|     for(uint8_t i = 0; i < 4; i++) { | ||||
|         tx_rx->tx_data[i] = crypto1_byte(crypto, 0x00, 0) ^ plain_cmd[i]; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Kevin Wallace
						Kevin Wallace