[FL-662] Read Mifare Ultralight (#518)
* nfc: add read mifare ultralight to menu * emv_decoder: add pragma once * nfc: add mifare ultralight reader * nfc: add mifare ultralight read draw * nfc: add mifare ultralight type checker * nfc: rework menu callback * mifare ultralight: change type names Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									0b14db4fb3
								
							
						
					
					
						commit
						a0fdc559c9
					
				| @ -22,17 +22,7 @@ uint32_t nfc_view_exit(void* context) { | ||||
| void nfc_menu_callback(void* context, uint32_t index) { | ||||
|     furi_assert(message_queue); | ||||
|     NfcMessage message; | ||||
|     if(index == 0) { | ||||
|         message.type = NfcMessageTypeDetect; | ||||
|     } else if(index == 1) { | ||||
|         message.type = NfcMessageTypeReadEMV; | ||||
|     } else if(index == 2) { | ||||
|         message.type = NfcMessageTypeEmulateEMV; | ||||
|     } else if(index == 3) { | ||||
|         message.type = NfcMessageTypeEmulate; | ||||
|     } else if(index == 4) { | ||||
|         message.type = NfcMessageTypeField; | ||||
|     } | ||||
|     message.type = index; | ||||
|     furi_check(osMessageQueuePut(message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| @ -52,11 +42,15 @@ Nfc* nfc_alloc() { | ||||
| 
 | ||||
|     // Menu
 | ||||
|     nfc->submenu = submenu_alloc(); | ||||
|     submenu_add_item(nfc->submenu, "Detect", 0, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Read EMV", 1, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Emulate EMV", 2, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Emulate", 3, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Field", 4, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Detect", NfcMessageTypeDetect, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Read EMV", NfcMessageTypeReadEMV, nfc_menu_callback, nfc); | ||||
|     submenu_add_item( | ||||
|         nfc->submenu, "Emulate EMV", NfcMessageTypeEmulateEMV, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Emulate", NfcMessageTypeEmulate, nfc_menu_callback, nfc); | ||||
|     submenu_add_item(nfc->submenu, "Field", NfcMessageTypeField, nfc_menu_callback, nfc); | ||||
|     submenu_add_item( | ||||
|         nfc->submenu, "Read MfUltralight", NfcMessageTypeReadMfUltralight, nfc_menu_callback, nfc); | ||||
| 
 | ||||
|     View* submenu_view = submenu_get_view(nfc->submenu); | ||||
|     view_set_previous_callback(submenu_view, nfc_view_exit); | ||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewMenu, submenu_view); | ||||
| @ -98,6 +92,16 @@ Nfc* nfc_alloc() { | ||||
|     view_set_previous_callback(nfc->view_field, nfc_view_stop); | ||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewField, nfc->view_field); | ||||
| 
 | ||||
|     // Read Mifare Ultralight
 | ||||
|     nfc->view_read_mf_ultralight = view_alloc(); | ||||
|     view_set_context(nfc->view_read_mf_ultralight, nfc); | ||||
|     view_set_draw_callback(nfc->view_read_mf_ultralight, nfc_view_read_mf_ultralight_draw); | ||||
|     view_set_previous_callback(nfc->view_read_mf_ultralight, nfc_view_stop); | ||||
|     view_allocate_model( | ||||
|         nfc->view_read_mf_ultralight, ViewModelTypeLocking, sizeof(NfcViewReadModel)); | ||||
|     view_dispatcher_add_view( | ||||
|         nfc->view_dispatcher, NfcViewReadMfUltralight, nfc->view_read_mf_ultralight); | ||||
| 
 | ||||
|     // Error
 | ||||
|     nfc->view_error = view_alloc(); | ||||
|     view_set_context(nfc->view_error, nfc); | ||||
| @ -144,6 +148,10 @@ void nfc_free(Nfc* nfc) { | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewField); | ||||
|     view_free(nfc->view_field); | ||||
| 
 | ||||
|     // Read Mifare Ultralight
 | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewReadMfUltralight); | ||||
|     view_free(nfc->view_read_mf_ultralight); | ||||
| 
 | ||||
|     // Error
 | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewError); | ||||
|     view_free(nfc->view_error); | ||||
| @ -180,6 +188,7 @@ int32_t nfc_task(void* p) { | ||||
|     NfcMessage message; | ||||
|     while(1) { | ||||
|         furi_check(osMessageQueueGet(message_queue, &message, NULL, osWaitForever) == osOK); | ||||
| 
 | ||||
|         if(message.type == NfcMessageTypeDetect) { | ||||
|             with_view_model( | ||||
|                 nfc->view_detect, (NfcViewReadModel * model) { | ||||
| @ -200,6 +209,8 @@ int32_t nfc_task(void* p) { | ||||
|             nfc_start(nfc, NfcViewEmulate, NfcWorkerStateEmulate); | ||||
|         } else if(message.type == NfcMessageTypeField) { | ||||
|             nfc_start(nfc, NfcViewField, NfcWorkerStateField); | ||||
|         } else if(message.type == NfcMessageTypeReadMfUltralight) { | ||||
|             nfc_start(nfc, NfcViewReadMfUltralight, NfcWorkerStateReadMfUltralight); | ||||
|         } else if(message.type == NfcMessageTypeStop) { | ||||
|             nfc_worker_stop(nfc->worker); | ||||
|         } else if(message.type == NfcMessageTypeDeviceFound) { | ||||
| @ -228,6 +239,19 @@ int32_t nfc_task(void* p) { | ||||
|                     model->found = false; | ||||
|                     return true; | ||||
|                 }); | ||||
|         } else if(message.type == NfcMessageTypeMfUlFound) { | ||||
|             with_view_model( | ||||
|                 nfc->view_read_mf_ultralight, (NfcViewReadModel * model) { | ||||
|                     model->found = true; | ||||
|                     model->device = message.device; | ||||
|                     return true; | ||||
|                 }); | ||||
|         } else if(message.type == NfcMessageTypeMfUlNotFound) { | ||||
|             with_view_model( | ||||
|                 nfc->view_read_mf_ultralight, (NfcViewReadModel * model) { | ||||
|                     model->found = false; | ||||
|                     return true; | ||||
|                 }); | ||||
|         } else if(message.type == NfcMessageTypeExit) { | ||||
|             nfc_free(nfc); | ||||
|             break; | ||||
|  | ||||
| @ -31,6 +31,7 @@ struct Nfc { | ||||
|     View* view_emulate_emv; | ||||
|     View* view_emulate; | ||||
|     View* view_field; | ||||
|     View* view_read_mf_ultralight; | ||||
|     View* view_cli; | ||||
|     View* view_error; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|  | ||||
| @ -44,8 +44,8 @@ typedef enum { | ||||
|     NfcDeviceTypeNfcb, | ||||
|     NfcDeviceTypeNfcf, | ||||
|     NfcDeviceTypeNfcv, | ||||
|     NfcDeviceTypeNfcMifare, | ||||
|     NfcDeviceTypeEMV, | ||||
|     NfcDeviceTypeMfUltralight, | ||||
| } NfcDeviceType; | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -53,6 +53,12 @@ typedef struct { | ||||
|     uint8_t number[8]; | ||||
| } EMVCard; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t uid[7]; | ||||
|     uint8_t man_block[12]; | ||||
|     uint8_t otp[4]; | ||||
| } MfUlCard; | ||||
| 
 | ||||
| typedef struct { | ||||
|     NfcDeviceType type; | ||||
|     union { | ||||
| @ -61,6 +67,7 @@ typedef struct { | ||||
|         rfalNfcfListenDevice nfcf; | ||||
|         rfalNfcvListenDevice nfcv; | ||||
|         EMVCard emv_card; | ||||
|         MfUlCard mf_ul_card; | ||||
|     }; | ||||
| } NfcDevice; | ||||
| 
 | ||||
| @ -75,16 +82,19 @@ typedef enum { | ||||
|     NfcWorkerStateEmulateEMV, | ||||
|     NfcWorkerStateEmulate, | ||||
|     NfcWorkerStateField, | ||||
|     NfcWorkerStateReadMfUltralight, | ||||
|     // Transition
 | ||||
|     NfcWorkerStateStop, | ||||
| } NfcWorkerState; | ||||
| 
 | ||||
| typedef enum { | ||||
|     // From Menu
 | ||||
|     NfcMessageTypeDetect, | ||||
|     NfcMessageTypeReadEMV, | ||||
|     NfcMessageTypeEmulateEMV, | ||||
|     NfcMessageTypeEmulate, | ||||
|     NfcMessageTypeField, | ||||
|     NfcMessageTypeReadMfUltralight, | ||||
|     NfcMessageTypeStop, | ||||
|     NfcMessageTypeExit, | ||||
|     // From Worker
 | ||||
| @ -92,6 +102,8 @@ typedef enum { | ||||
|     NfcMessageTypeDeviceNotFound, | ||||
|     NfcMessageTypeEMVFound, | ||||
|     NfcMessageTypeEMVNotFound, | ||||
|     NfcMessageTypeMfUlFound, | ||||
|     NfcMessageTypeMfUlNotFound, | ||||
| } NfcMessageType; | ||||
| 
 | ||||
| typedef struct { | ||||
|  | ||||
							
								
								
									
										53
									
								
								applications/nfc/nfc_views.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										53
									
								
								applications/nfc/nfc_views.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -150,6 +150,59 @@ void nfc_view_emulate_draw(Canvas* canvas, void* model) { | ||||
|     canvas_draw_str(canvas, 2, 52, "SAK: 20 ATQA: 00/04"); | ||||
| } | ||||
| 
 | ||||
| void nfc_view_read_mf_ultralight_draw(Canvas* canvas, void* model) { | ||||
|     NfcViewReadModel* m = model; | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     char buffer[32]; | ||||
| 
 | ||||
|     if(m->found) { | ||||
|         canvas_draw_str(canvas, 0, 12, "Found Mifare Ultralight"); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|         canvas_draw_str(canvas, 2, 22, "UID:"); | ||||
|         for(uint8_t i = 0; i < sizeof(m->device.mf_ul_card.uid); i++) { | ||||
|             snprintf( | ||||
|                 buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", m->device.mf_ul_card.uid[i]); | ||||
|         } | ||||
|         buffer[sizeof(m->device.mf_ul_card.uid) * 2] = 0; | ||||
|         canvas_draw_str(canvas, 18, 22, buffer); | ||||
| 
 | ||||
|         uint8_t man_bl_size = sizeof(m->device.mf_ul_card.man_block); | ||||
|         canvas_draw_str(canvas, 2, 32, "Manufacturer block:"); | ||||
|         for(uint8_t i = 0; i < man_bl_size / 2; i++) { | ||||
|             snprintf( | ||||
|                 buffer + (i * 2), | ||||
|                 sizeof(buffer) - (i * 2), | ||||
|                 "%02X", | ||||
|                 m->device.mf_ul_card.man_block[i]); | ||||
|         } | ||||
|         buffer[man_bl_size] = 0; | ||||
|         canvas_draw_str(canvas, 2, 42, buffer); | ||||
| 
 | ||||
|         for(uint8_t i = 0; i < man_bl_size / 2; i++) { | ||||
|             snprintf( | ||||
|                 buffer + (i * 2), | ||||
|                 sizeof(buffer) - (i * 2), | ||||
|                 "%02X", | ||||
|                 m->device.mf_ul_card.man_block[man_bl_size / 2 + i]); | ||||
|         } | ||||
|         buffer[man_bl_size] = 0; | ||||
|         canvas_draw_str(canvas, 2, 52, buffer); | ||||
| 
 | ||||
|         canvas_draw_str(canvas, 2, 62, "OTP: "); | ||||
|         for(uint8_t i = 0; i < sizeof(m->device.mf_ul_card.otp); i++) { | ||||
|             snprintf( | ||||
|                 buffer + (i * 2), sizeof(buffer) - (i * 2), "%02X", m->device.mf_ul_card.otp[i]); | ||||
|         } | ||||
|         buffer[sizeof(m->device.mf_ul_card.otp) * 2] = 0; | ||||
|         canvas_draw_str(canvas, 22, 62, buffer); | ||||
|     } else { | ||||
|         canvas_draw_str(canvas, 0, 12, "Searching"); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|         canvas_draw_str(canvas, 2, 22, "Place card to the back"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void nfc_view_field_draw(Canvas* canvas, void* model) { | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|  | ||||
| @ -14,6 +14,7 @@ typedef enum { | ||||
|     NfcViewEmulateEMV, | ||||
|     NfcViewEmulate, | ||||
|     NfcViewField, | ||||
|     NfcViewReadMfUltralight, | ||||
|     NfcViewError, | ||||
| } NfcView; | ||||
| 
 | ||||
| @ -31,6 +32,7 @@ void nfc_view_read_emv_draw(Canvas* canvas, void* model); | ||||
| 
 | ||||
| void nfc_view_emulate_emv_draw(Canvas* canvas, void* model); | ||||
| void nfc_view_emulate_draw(Canvas* canvas, void* model); | ||||
| void nfc_view_read_mf_ultralight_draw(Canvas* canvas, void* model); | ||||
| 
 | ||||
| void nfc_view_field_draw(Canvas* canvas, void* model); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										123
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										123
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,6 +1,7 @@ | ||||
| #include "nfc_worker_i.h" | ||||
| #include <api-hal.h> | ||||
| #include "nfc_protocols/emv_decoder.h" | ||||
| #include "nfc_protocols/mifare_ultralight.h" | ||||
| 
 | ||||
| #define NFC_WORKER_TAG "nfc worker" | ||||
| 
 | ||||
| @ -71,6 +72,8 @@ void nfc_worker_task(void* context) { | ||||
|         nfc_worker_emulate(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateField) { | ||||
|         nfc_worker_field(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateReadMfUltralight) { | ||||
|         nfc_worker_read_mf_ultralight(nfc_worker); | ||||
|     } | ||||
|     api_hal_nfc_deactivate(); | ||||
|     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); | ||||
| @ -306,6 +309,126 @@ void nfc_worker_poll(NfcWorker* nfc_worker) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | ||||
|     ReturnCode err; | ||||
|     rfalNfcDevice* dev_list; | ||||
|     uint8_t dev_cnt = 0; | ||||
|     uint8_t tx_buff[255] = {}; | ||||
|     uint16_t tx_len = 0; | ||||
|     uint8_t* rx_buff; | ||||
|     uint16_t* rx_len; | ||||
|     MfUltralightRead mf_ul_read; | ||||
| 
 | ||||
|     // Update screen before start searching
 | ||||
|     NfcMessage message = {.type = NfcMessageTypeMfUlNotFound}; | ||||
|     while(nfc_worker->state == NfcWorkerStateReadMfUltralight) { | ||||
|         furi_check( | ||||
|             osMessageQueuePut(nfc_worker->message_queue, &message, 0, osWaitForever) == osOK); | ||||
|         api_hal_nfc_deactivate(); | ||||
|         memset(&mf_ul_read, 0, sizeof(mf_ul_read)); | ||||
|         if(api_hal_nfc_detect(&dev_list, &dev_cnt, 100, false)) { | ||||
|             if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA && | ||||
|                mf_ul_check_card_type( | ||||
|                    dev_list[0].dev.nfca.sensRes.anticollisionInfo, | ||||
|                    dev_list[0].dev.nfca.sensRes.platformInfo, | ||||
|                    dev_list[0].dev.nfca.selRes.sak)) { | ||||
|                 // Get Mifare Ultralight version
 | ||||
|                 FURI_LOG_I( | ||||
|                     NFC_WORKER_TAG, "Found Mifare Ultralight tag. Trying to get tag version"); | ||||
|                 tx_len = mf_ul_prepare_get_version(tx_buff); | ||||
|                 err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|                 if(err == ERR_NONE) { | ||||
|                     mf_ul_parse_get_version_response(rx_buff, &mf_ul_read); | ||||
|                     FURI_LOG_I( | ||||
|                         NFC_WORKER_TAG, | ||||
|                         "Mifare Ultralight Type: %d, Pages: %d", | ||||
|                         mf_ul_read.type, | ||||
|                         mf_ul_read.pages_to_read); | ||||
|                 } else if(err == ERR_TIMEOUT) { | ||||
|                     FURI_LOG_W( | ||||
|                         NFC_WORKER_TAG, | ||||
|                         "Card doesn't respond to GET VERSION command. Reinit card and set default read parameters"); | ||||
|                     err = ERR_NONE; | ||||
|                     mf_ul_set_default_version(&mf_ul_read); | ||||
|                     // Reinit device
 | ||||
|                     api_hal_nfc_deactivate(); | ||||
|                     if(!api_hal_nfc_detect(&dev_list, &dev_cnt, 100, false)) { | ||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search"); | ||||
|                         message.type = NfcMessageTypeMfUlNotFound; | ||||
|                         continue; | ||||
|                     } | ||||
|                 } else { | ||||
|                     FURI_LOG_E( | ||||
|                         NFC_WORKER_TAG, | ||||
|                         "Error getting Mifare Ultralight version. Error code: %d", | ||||
|                         err); | ||||
|                     message.type = NfcMessageTypeMfUlNotFound; | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 // Dump Mifare Ultralight card
 | ||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Trying to read pages"); | ||||
|                 if(mf_ul_read.support_fast_read) { | ||||
|                     // Read card with FAST_READ command
 | ||||
|                     tx_len = mf_ul_prepare_fast_read(tx_buff, 0x00, mf_ul_read.pages_to_read - 1); | ||||
|                     err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|                     if(err == ERR_NONE) { | ||||
|                         FURI_LOG_I( | ||||
|                             NFC_WORKER_TAG, | ||||
|                             "Fast read pages %d - %d succeed", | ||||
|                             0, | ||||
|                             mf_ul_read.pages_to_read - 1); | ||||
|                         memcpy(mf_ul_read.dump, rx_buff, mf_ul_read.pages_to_read * 4); | ||||
|                         mf_ul_read.pages_readed = mf_ul_read.pages_to_read; | ||||
|                     } else { | ||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Fast read failed"); | ||||
|                         message.type = NfcMessageTypeMfUlNotFound; | ||||
|                         continue; | ||||
|                     } | ||||
|                 } else { | ||||
|                     // READ card with READ command (4 pages at a time)
 | ||||
|                     for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) { | ||||
|                         tx_len = mf_ul_prepare_read(tx_buff, page); | ||||
|                         err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|                         if(err == ERR_NONE) { | ||||
|                             FURI_LOG_I( | ||||
|                                 NFC_WORKER_TAG, "Read pages %d - %d succeed", page, page + 3); | ||||
|                             memcpy(&mf_ul_read.dump[page * 4], rx_buff, 4 * 4); | ||||
|                             mf_ul_read.pages_readed += 4; | ||||
|                         } else { | ||||
|                             FURI_LOG_W( | ||||
|                                 NFC_WORKER_TAG, "Read pages %d - %d failed", page, page + 3); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 // Fill message for nfc application
 | ||||
|                 message.type = NfcMessageTypeMfUlFound; | ||||
|                 memcpy( | ||||
|                     message.device.mf_ul_card.uid, | ||||
|                     dev_list[0].dev.nfca.nfcId1, | ||||
|                     sizeof(message.device.mf_ul_card.uid)); | ||||
|                 memcpy(message.device.mf_ul_card.man_block, mf_ul_read.dump, 4 * 3); | ||||
|                 memcpy(message.device.mf_ul_card.otp, &mf_ul_read.dump[4 * 3], 4); | ||||
|                 for(uint8_t i = 0; i < mf_ul_read.pages_readed * 4; i += 4) { | ||||
|                     printf("Page %2d: ", i / 4); | ||||
|                     for(uint8_t j = 0; j < 4; j++) { | ||||
|                         printf("%02X ", mf_ul_read.dump[i + j]); | ||||
|                     } | ||||
|                     printf("\r\n"); | ||||
|                 } | ||||
|             } else { | ||||
|                 message.type = NfcMessageTypeMfUlNotFound; | ||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Tag does not support Mifare Ultralight"); | ||||
|             } | ||||
|         } else { | ||||
|             message.type = NfcMessageTypeMfUlNotFound; | ||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any tags"); | ||||
|         } | ||||
|         osDelay(100); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void nfc_worker_emulate(NfcWorker* nfc_worker) { | ||||
|     while(nfc_worker->state == NfcWorkerStateEmulate) { | ||||
|         if(api_hal_nfc_listen(100)) { | ||||
|  | ||||
| @ -38,3 +38,5 @@ void nfc_worker_poll(NfcWorker* nfc_worker); | ||||
| void nfc_worker_emulate(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_field(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker); | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
|  | ||||
							
								
								
									
										59
									
								
								lib/nfc_protocols/mifare_ultralight.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								lib/nfc_protocols/mifare_ultralight.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| #include "mifare_ultralight.h" | ||||
| 
 | ||||
| bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { | ||||
|     if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) { | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| uint16_t mf_ul_prepare_get_version(uint8_t* dest) { | ||||
|     dest[0] = MF_UL_GET_VERSION_CMD; | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| void mf_ul_parse_get_version_response(uint8_t* buff, MfUltralightRead* mf_ul_read) { | ||||
|     MfUltralightVersion* version = (MfUltralightVersion*) buff; | ||||
|     if(version->storage_size == 0x0B || version->storage_size == 0x00) { | ||||
|         mf_ul_read->type = MfUltralightTypeUL11; | ||||
|         mf_ul_read->pages_to_read = 20; | ||||
|         mf_ul_read->support_fast_read = true; | ||||
|     } else if(version->storage_size == 0x0E) { | ||||
|         mf_ul_read->type = MfUltralightTypeUL21; | ||||
|         mf_ul_read->pages_to_read = 41; | ||||
|         mf_ul_read->support_fast_read = true; | ||||
|     } else if(version->storage_size == 0x0F) { | ||||
|         mf_ul_read->type = MfUltralightTypeNTAG213; | ||||
|         mf_ul_read->pages_to_read = 45; | ||||
|         mf_ul_read->support_fast_read = false; | ||||
|     } else if(version->storage_size == 0x11) { | ||||
|         mf_ul_read->type = MfUltralightTypeNTAG215; | ||||
|         mf_ul_read->pages_to_read = 135; | ||||
|         mf_ul_read->support_fast_read = false; | ||||
|     } else if(version->storage_size == 0x13) { | ||||
|         mf_ul_read->type = MfUltralightTypeNTAG216; | ||||
|         mf_ul_read->pages_to_read = 231; | ||||
|         mf_ul_read->support_fast_read = false; | ||||
|     } else { | ||||
|         mf_ul_set_default_version(mf_ul_read); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void mf_ul_set_default_version(MfUltralightRead* mf_ul_read) { | ||||
|     mf_ul_read->type = MfUltralightTypeUnknown; | ||||
|     mf_ul_read->pages_to_read = 20; | ||||
|     mf_ul_read->support_fast_read = false; | ||||
| } | ||||
| 
 | ||||
| uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page) { | ||||
|     dest[0] = MF_UL_READ_CMD; | ||||
|     dest[1] = start_page; | ||||
|     return 2; | ||||
| } | ||||
| 
 | ||||
| uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page) { | ||||
|     dest[0] = MF_UL_FAST_READ_CMD; | ||||
|     dest[1] = start_page; | ||||
|     dest[2] = end_page; | ||||
|     return 3; | ||||
| } | ||||
							
								
								
									
										56
									
								
								lib/nfc_protocols/mifare_ultralight.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								lib/nfc_protocols/mifare_ultralight.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #define MF_UL_GET_VERSION_CMD (0x60) | ||||
| #define MF_UL_READ_CMD (0x30) | ||||
| #define MF_UL_FAST_READ_CMD (0x3A) | ||||
| 
 | ||||
| typedef enum { | ||||
|     MfUltralightTypeUnknown, | ||||
|     MfUltralightTypeUL11, | ||||
|     MfUltralightTypeUL21, | ||||
|     MfUltralightTypeNTAG213, | ||||
|     MfUltralightTypeNTAG215, | ||||
|     MfUltralightTypeNTAG216, | ||||
| } MfUltralightType; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t header; | ||||
|     uint8_t vendor_id; | ||||
|     uint8_t prod_type; | ||||
|     uint8_t prod_subtype; | ||||
|     uint8_t prod_ver_major; | ||||
|     uint8_t prod_ver_minor; | ||||
|     uint8_t storage_size; | ||||
|     uint8_t protocol_type; | ||||
| } MfUltralightVersion; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t  sn0[3]; | ||||
|     uint8_t  btBCC0; | ||||
|     uint8_t  sn1[4]; | ||||
|     uint8_t  btBCC1; | ||||
|     uint8_t  internal; | ||||
|     uint8_t  lock[2]; | ||||
|     uint8_t  otp[4]; | ||||
| } MfUltralightManufacturerBlock; | ||||
| 
 | ||||
| typedef struct { | ||||
|     MfUltralightType type; | ||||
|     uint8_t pages_to_read; | ||||
|     uint8_t pages_readed; | ||||
|     bool support_fast_read; | ||||
|     uint8_t dump[255]; | ||||
| } MfUltralightRead; | ||||
| 
 | ||||
| bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); | ||||
| 
 | ||||
| uint16_t mf_ul_prepare_get_version(uint8_t* dest); | ||||
| void mf_ul_parse_get_version_response(uint8_t* buff, MfUltralightRead* mf_ul_read); | ||||
| void mf_ul_set_default_version(MfUltralightRead* mf_ul_read); | ||||
| 
 | ||||
| uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page); | ||||
| uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page); | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich