From de006aa06aad160a1207cd4b6d414d28981da152 Mon Sep 17 00:00:00 2001 From: ghettorce <799240+ghettorce@users.noreply.github.com> Date: Wed, 15 Dec 2021 21:27:25 +0300 Subject: [PATCH] NFC: fixes & improvements (#897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: (mf_ul) fix overflow while reading * nfc: (mf_ul) fix FAST_READ command emulation * nfc: (mf_ul) implement non-strict PWD_AUTH command emulation for NTAG21x * nfc: (mf_ul) improve emulation stability by removing frequent furi_hal_console_put() calls that cause delays or something * nfc: (mf_ul) remove calls to blocking functions from emulation worker Co-authored-by: あく --- applications/nfc/nfc_worker.c | 8 ++- lib/nfc_protocols/mifare_ultralight.c | 71 +++++++++++++++++++++++++-- lib/nfc_protocols/mifare_ultralight.h | 9 ++++ 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 3f7f87e4..27eab370 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -613,6 +613,9 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { // Setup emulation parameters from mifare ultralight data structure mf_ul_prepare_emulation(&mf_ul_emulate, &data->mf_ul_data); while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { + // WARNING + // DO NOT call any blocking functions (e.g. FURI_LOG_*) in this loop, + // as any delay will negatively affect the stability of the emulation. if(furi_hal_nfc_listen( data->nfc_data.uid, data->nfc_data.uid_len, @@ -620,7 +623,6 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { data->nfc_data.sak, true, 200)) { - FURI_LOG_D(TAG, "Anticollision passed"); if(furi_hal_nfc_get_first_frame(&rx_buff, &rx_len)) { // Data exchange loop while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { @@ -632,17 +634,14 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { if(err == ERR_NONE) { continue; } else { - FURI_LOG_E(TAG, "Communication error: %d", err); break; } } else { - FURI_LOG_W(TAG, "Not valid command: %02X", rx_buff[0]); furi_hal_nfc_deactivate(); break; } } } else { - FURI_LOG_W(TAG, "Error in 1st data exchange"); furi_hal_nfc_deactivate(); } } @@ -653,7 +652,6 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { nfc_worker->callback(nfc_worker->context); } } - FURI_LOG_W(TAG, "Can't find reader"); osThreadYield(); } } diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc_protocols/mifare_ultralight.c index 962b81b0..b3678864 100644 --- a/lib/nfc_protocols/mifare_ultralight.c +++ b/lib/nfc_protocols/mifare_ultralight.c @@ -53,9 +53,14 @@ uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page) { } void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read) { - mf_ul_read->pages_readed += 4; + uint8_t pages_read = 4; + uint8_t page_read_count = mf_ul_read->pages_readed + pages_read; + if(page_read_count > mf_ul_read->pages_to_read) { + pages_read -= page_read_count - mf_ul_read->pages_to_read; + } + mf_ul_read->pages_readed += pages_read; mf_ul_read->data.data_size = mf_ul_read->pages_readed * 4; - memcpy(&mf_ul_read->data.data[page_addr * 4], buff, 16); + memcpy(&mf_ul_read->data.data[page_addr * 4], buff, pages_read * 4); } uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page) { @@ -140,6 +145,7 @@ uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data) { void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) { mf_ul_emulate->data = *data; + mf_ul_emulate->auth_data = NULL; mf_ul_emulate->data_changed = false; if(data->version.storage_size == 0) { mf_ul_emulate->type = MfUltralightTypeUnknown; @@ -150,6 +156,37 @@ void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) } else if(data->version.storage_size == 0x0E) { mf_ul_emulate->type = MfUltralightTypeUL21; mf_ul_emulate->support_fast_read = true; + } else if(data->version.storage_size == 0x0F) { + mf_ul_emulate->type = MfUltralightTypeNTAG213; + mf_ul_emulate->support_fast_read = true; + } else if(data->version.storage_size == 0x11) { + mf_ul_emulate->type = MfUltralightTypeNTAG215; + mf_ul_emulate->support_fast_read = true; + } else if(data->version.storage_size == 0x13) { + mf_ul_emulate->type = MfUltralightTypeNTAG216; + mf_ul_emulate->support_fast_read = true; + } + + if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { + uint16_t pwd_page = (data->data_size / 4) - 2; + mf_ul_emulate->auth_data = (MifareUlAuthData*)&data->data[pwd_page * 4]; + } +} + +void mf_ul_protect_auth_data_on_read_command( + uint8_t* tx_buff, + uint8_t start_page, + uint8_t end_page, + MifareUlDevice* mf_ul_emulate) { + if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { + uint8_t pwd_page = (mf_ul_emulate->data.data_size / 4) - 2; + uint8_t pack_page = pwd_page + 1; + if((start_page <= pwd_page) && (end_page >= pwd_page)) { + memset(&tx_buff[(pwd_page - start_page) * 4], 0, 4); + } + if((start_page <= pack_page) && (end_page >= pack_page)) { + memset(&tx_buff[(pack_page - start_page) * 4], 0, 2); + } } } @@ -175,16 +212,24 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin } else { memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len); } + mf_ul_protect_auth_data_on_read_command( + buff_tx, start_page, (start_page + 4), mf_ul_emulate); } } else if(cmd == MF_UL_FAST_READ_CMD) { if(mf_ul_emulate->support_fast_read) { uint8_t start_page = buff_rx[1]; uint8_t end_page = buff_rx[2]; if((start_page < page_num) && - (end_page < page_num) && (start_page < end_page)) { - tx_len = (end_page - start_page) * 4; + (end_page < page_num) && (start_page < (end_page + 1))) { + tx_len = ((end_page + 1) - start_page) * 4; memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len); - } + mf_ul_protect_auth_data_on_read_command( + buff_tx, start_page, end_page, mf_ul_emulate); + } else { + // TODO make 4-bit NAK + buff_tx[0] = 0x0; + tx_len = 1; + } } } else if(cmd == MF_UL_WRITE) { uint8_t write_page = buff_rx[1]; @@ -213,6 +258,22 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin buff_tx[0] = 0x0A; tx_len = 1; } + } else if(cmd == MF_UL_AUTH) { + if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { + if(memcmp(&buff_rx[1], mf_ul_emulate->auth_data->pwd, 4) == 0) { + buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0]; + buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1]; + tx_len = 2; + } else if(!mf_ul_emulate->auth_data->pack.value) { + buff_tx[0] = 0x80; + buff_tx[1] = 0x80; + tx_len = 2; + } else { + // TODO make 4-bit NAK + buff_tx[0] = 0x0; + tx_len = 1; + } + } } else if(cmd == MF_UL_READ_SIG) { // Check 2nd byte = 0x00 - RFU if(buff_rx[1] == 0x00) { diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc_protocols/mifare_ultralight.h index 4548ca73..386850c8 100644 --- a/lib/nfc_protocols/mifare_ultralight.h +++ b/lib/nfc_protocols/mifare_ultralight.h @@ -60,6 +60,14 @@ typedef struct { uint8_t data[MF_UL_MAX_DUMP_SIZE]; } MifareUlData; +typedef struct { + uint8_t pwd[4]; + union { + uint8_t raw[2]; + uint16_t value; + } pack; +} MifareUlAuthData; + typedef struct { MfUltralightType type; uint8_t pages_to_read; @@ -67,6 +75,7 @@ typedef struct { bool support_fast_read; bool data_changed; MifareUlData data; + MifareUlAuthData* auth_data; } MifareUlDevice; bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);