diff --git a/applications/applications.c b/applications/applications.c index a4e81a88d75..e1e58c32773 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -230,6 +230,22 @@ const FlipperApplication FLIPPER_APPS[] = { .flags = FlipperApplicationFlagDefault}, #endif +#ifdef APP_UNIVERSALRF + {.app = universal_rf_remote_app, + .name = "Universal SubGHz", + .stack_size = 2048, + .icon = &A_UniversalRemote_14, + .flags = FlipperApplicationFlagDefault}, +#endif + +#ifdef APP_JUKEBOX + {.app = jukebox_app, + .name = "Jukebox", + .stack_size = 2048, + .icon = &A_TouchTunes_14, + .flags = FlipperApplicationFlagDefault}, +#endif + #ifdef APP_LF_RFID {.app = lfrfid_app, .name = "125 kHz RFID", @@ -358,14 +374,6 @@ const FlipperApplication FLIPPER_PLUGINS[] = { }, #endif -#ifdef APP_JUKEBOX - {.app = jukebox_app, - .name = "Jukebox", - .stack_size = 2048, - .icon = &A_UniversalRemote_14, - .flags = FlipperApplicationFlagDefault}, -#endif - #ifdef APP_MUSIC_PLAYER {.app = music_player_app, .name = "Music Player", @@ -394,14 +402,6 @@ const FlipperApplication FLIPPER_PLUGINS[] = { {.app = tetris_game_app, .name = "Tetris Game", .stack_size = 1024, .icon = NULL}, #endif -#ifdef APP_UNIVERSALRF - {.app = universal_rf_remote_app, - .name = "Universal SubGHz", - .stack_size = 2048, - .icon = &A_UniversalRemote_14, - .flags = FlipperApplicationFlagDefault}, -#endif - {.app = wav_player_app, .name = "Wav Player", .stack_size = 4096, diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 6b3c8f092c7..9016763dfb2 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "helpers/nfc_mf_classic_dict.h" @@ -104,6 +105,8 @@ int32_t nfc_worker_task(void* context) { nfc_worker_emulate_mifare_ul(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { nfc_worker_mifare_classic_dict_attack(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateEmulateMifareClassic) { + nfc_worker_emulate_mifare_classic(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { nfc_worker_read_mifare_desfire(nfc_worker); } @@ -474,6 +477,26 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { stream_free(nfc_worker->dict_stream); } +void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + MfClassicEmulator emulator = { + .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), + .data = nfc_worker->dev_data->mf_classic_data, + }; + NfcaSignal* nfca_signal = nfca_signal_alloc(); + tx_rx.nfca_signal = nfca_signal; + + while(nfc_worker->state == NfcWorkerStateEmulateMifareClassic) { + if(furi_hal_nfc_listen( + nfc_data->uid, nfc_data->uid_len, nfc_data->atqa, nfc_data->sak, true, 4000)) { + mf_classic_emulator(&emulator, &tx_rx); + } + } + + nfca_signal_free(nfca_signal); +} + void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { ReturnCode err; uint8_t tx_buff[64] = {}; diff --git a/applications/nfc/nfc_worker.h b/applications/nfc/nfc_worker.h index 1933a79b7fe..a68f42d72c4 100755 --- a/applications/nfc/nfc_worker.h +++ b/applications/nfc/nfc_worker.h @@ -19,6 +19,7 @@ typedef enum { NfcWorkerStateReadMifareUltralight, NfcWorkerStateEmulateMifareUltralight, NfcWorkerStateReadMifareClassic, + NfcWorkerStateEmulateMifareClassic, NfcWorkerStateReadMifareDesfire, // Transition NfcWorkerStateStop, diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index 6b5d5d10c6f..45e78aed2a4 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -34,4 +34,5 @@ ADD_SCENE(nfc, restore_original, RestoreOriginal) ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, field, Field) ADD_SCENE(nfc, read_mifare_classic, ReadMifareClassic) +ADD_SCENE(nfc, emulate_mifare_classic, EmulateMifareClassic) ADD_SCENE(nfc, dict_not_found, DictNotFound) diff --git a/applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c b/applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c new file mode 100644 index 00000000000..2b8478175b2 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c @@ -0,0 +1,64 @@ +#include "../nfc_i.h" +#include + +#define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) +#define NFC_MF_CLASSIC_DATA_CHANGED (1UL) + +void nfc_emulate_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + Nfc* nfc = context; + + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_CLASSIC_DATA_CHANGED); +} + +void nfc_scene_emulate_mifare_classic_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); + + // Setup view + Popup* popup = nfc->popup; + if(strcmp(nfc->dev->dev_name, "")) { + nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); + } + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + popup_set_header(popup, "Emulating\nMf Classic", 56, 31, AlignLeft, AlignTop); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + nfc_worker_start( + nfc->worker, + NfcWorkerStateEmulateMifareClassic, + &nfc->dev->dev_data, + nfc_emulate_mifare_classic_worker_callback, + nfc); +} + +bool nfc_scene_emulate_mifare_classic_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + notification_message(nfc->notifications, &sequence_blink_blue_10); + consumed = true; + } else if(event.type == SceneManagerEventTypeBack) { + // Stop worker + nfc_worker_stop(nfc->worker); + // Check if data changed and save in shadow file + if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareUl) == + NFC_MF_CLASSIC_DATA_CHANGED) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_CLASSIC_DATA_NOT_CHANGED); + nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); + } + consumed = false; + } + return consumed; +} + +void nfc_scene_emulate_mifare_classic_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index e0489c157df..1b435ccd1d1 100644 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -27,13 +27,11 @@ void nfc_scene_saved_menu_on_enter(void* context) { SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { + } else if( + nfc->dev->format == NfcDeviceSaveFormatMifareUl || + nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { submenu_add_item( - submenu, - "Emulate Ultralight", - SubmenuIndexEmulate, - nfc_scene_saved_menu_submenu_callback, - nfc); + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); } submenu_add_item( submenu, "Edit UID and Name", SubmenuIndexEdit, nfc_scene_saved_menu_submenu_callback, nfc); @@ -64,6 +62,8 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexEmulate) { if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 768a4bac79e..e6b27573d51 100755 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -1,9 +1,12 @@ #include "furi_hal_nfc.h" #include +#include #include #include #include -#include + +#include +#include #define TAG "FuriHalNfc" @@ -394,6 +397,80 @@ ReturnCode furi_hal_nfc_data_exchange( return ret; } +static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { + furi_assert(tx_rx->nfca_signal); + + platformDisableIrqCallback(); + + bool ret = false; + + // Start transparent mode + st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE); + // Reconfigure gpio + furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); + furi_hal_gpio_init(&gpio_spi_r_sck, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_gpio_init(&gpio_spi_r_miso, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_gpio_init(&gpio_nfc_cs, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_gpio_init(&gpio_spi_r_mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&gpio_spi_r_mosi, false); + + // Send signal + nfca_signal_encode(tx_rx->nfca_signal, tx_rx->tx_data, tx_rx->tx_bits / 8, tx_rx->tx_parity); + digital_signal_send(tx_rx->nfca_signal->tx_signal, &gpio_spi_r_mosi); + furi_hal_gpio_write(&gpio_spi_r_mosi, false); + + // Configure gpio back to SPI and exit transparent + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); + st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA); + + // Manually wait for interrupt + furi_hal_gpio_init(&gpio_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh); + st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_RXE); + + uint32_t irq = 0; + uint8_t rxe = 0; + uint32_t start = DWT->CYCCNT; + while(true) { + if(furi_hal_gpio_read(&gpio_rfid_pull) == true) { + st25r3916ReadRegister(ST25R3916_REG_IRQ_MAIN, &rxe); + if(rxe & (1 << 4)) { + irq = 1; + break; + } + } + uint32_t timeout = DWT->CYCCNT - start; + if(timeout / furi_hal_delay_instructions_per_microsecond() > timeout_ms * 1000) { + FURI_LOG_D(TAG, "Interrupt waiting timeout"); + break; + } + } + if(irq) { + uint8_t fifo_stat[2]; + st25r3916ReadMultipleRegisters( + ST25R3916_REG_FIFO_STATUS1, fifo_stat, ST25R3916_FIFO_STATUS_LEN); + uint16_t len = + ((((uint16_t)fifo_stat[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >> + ST25R3916_REG_FIFO_STATUS2_fifo_b_shift) + << RFAL_BITS_IN_BYTE); + len |= (((uint16_t)fifo_stat[0]) & 0x00FFU); + uint8_t rx[100]; + st25r3916ReadFifo(rx, len); + + tx_rx->rx_bits = len * 8; + memcpy(tx_rx->rx_data, rx, len); + + ret = true; + } else { + FURI_LOG_E(TAG, "Timeout error"); + ret = false; + } + + st25r3916ClearInterrupts(); + platformEnableIrqCallback(); + + return ret; +} + static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) { uint32_t flags = 0; @@ -405,6 +482,9 @@ static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) { } else if(type == FuriHalNfcTxRxTypeRaw) { flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP | RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE; + } else if(type == FuriHalNfcTxRxTypeRxRaw) { + flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP | + RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE; } return flags; @@ -470,6 +550,10 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { uint8_t* temp_rx_buff = NULL; uint16_t* temp_rx_bits = NULL; + if(tx_rx->tx_rx_type == FuriHalNfcTxRxTransparent) { + return furi_hal_nfc_transparent_tx_rx(tx_rx, timeout_ms); + } + // Prepare data for FIFO if necessary uint32_t flags = furi_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type); if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) { @@ -502,7 +586,8 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { osDelay(1); } - if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) { + if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw || + tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRxRaw) { tx_rx->rx_bits = 8 * furi_hal_nfc_bitstream_to_data_and_parity( temp_rx_buff, *temp_rx_bits, tx_rx->rx_data, tx_rx->rx_parity); } else { diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index 20a4690028b..860db80dea9 100755 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -10,6 +10,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -39,6 +41,8 @@ typedef enum { FuriHalNfcTxRxTypeRxNoCrc, FuriHalNfcTxRxTypeRxKeepPar, FuriHalNfcTxRxTypeRaw, + FuriHalNfcTxRxTypeRxRaw, + FuriHalNfcTxRxTransparent, } FuriHalNfcTxRxType; typedef bool (*FuriHalNfcEmulateCallback)( @@ -80,6 +84,7 @@ typedef struct { uint8_t rx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE]; uint16_t rx_bits; FuriHalNfcTxRxType tx_rx_type; + NfcaSignal* nfca_signal; } FuriHalNfcTxRxContext; /** Init nfc diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c new file mode 100644 index 00000000000..b9be3b60293 --- /dev/null +++ b/lib/digital_signal/digital_signal.c @@ -0,0 +1,173 @@ +#include "digital_signal.h" + +#include +#include +#include +#include + +#define F_TIM (64000000.0) +#define T_TIM (1.0 / F_TIM) + +#define MAX_ARR_BUFF_SIZE (10000) + +// TODO rework with dynamic allocation +static uint32_t digital_signal_arr_buff[MAX_ARR_BUFF_SIZE]; + +DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { + DigitalSignal* signal = malloc(sizeof(DigitalSignal)); + signal->start_level = true; + signal->edges_max_cnt = max_edges_cnt; + signal->edge_timings = malloc(max_edges_cnt * sizeof(float)); + signal->edge_cnt = 0; + + return signal; +} + +void digital_signal_free(DigitalSignal* signal) { + furi_assert(signal); + + free(signal->edge_timings); + free(signal); +} + +bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b) { + furi_assert(signal_a); + furi_assert(signal_b); + + if(signal_a->edges_max_cnt < signal_a->edge_cnt + signal_b->edge_cnt) { + return false; + } + + bool end_level = signal_a->start_level ^ !(signal_a->edge_cnt % 2); + uint8_t start_copy = 0; + if(end_level == signal_b->start_level) { + if(signal_a->edge_cnt) { + signal_a->edge_timings[signal_a->edge_cnt - 1] += signal_b->edge_timings[0]; + } else { + signal_a->edge_timings[signal_a->edge_cnt] += signal_b->edge_timings[0]; + } + start_copy += 1; + } + memcpy( + &signal_a->edge_timings[signal_a->edge_cnt], + &signal_b->edge_timings[start_copy], + (signal_b->edge_cnt - start_copy) * sizeof(float)); + signal_a->edge_cnt += signal_b->edge_cnt - start_copy; + + return true; +} + +bool digital_signal_get_start_level(DigitalSignal* signal) { + furi_assert(signal); + + return signal->start_level; +} + +uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal) { + furi_assert(signal); + + return signal->edge_cnt; +} + +float digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { + furi_assert(signal); + furi_assert(edge_num < signal->edge_cnt); + + return signal->edge_timings[edge_num]; +} + +static void digital_signal_prepare_arr(DigitalSignal* signal, uint32_t* arr) { + float t_signal = 0; + float t_current = 0; + float r = 0; + float r_int = 0; + float r_dec = 0; + + for(size_t i = 0; i < signal->edge_cnt - 1; i++) { + t_signal += signal->edge_timings[i]; + r = (t_signal - t_current) / T_TIM; + r_dec = modff(r, &r_int); + if(r_dec < 0.5f) { + arr[i] = (uint32_t)r_int - 1; + } else { + arr[i] = (uint32_t)r_int; + } + t_current += (arr[i] + 1) * T_TIM; + } +} + +bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { + furi_assert(signal); + furi_assert(gpio); + + // Configure gpio as output + furi_hal_gpio_init(gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + + // Init gpio buffer and DMA channel + uint16_t gpio_reg = gpio->port->ODR; + uint16_t gpio_buff[2]; + if(signal->start_level) { + gpio_buff[0] = gpio_reg | gpio->pin; + gpio_buff[1] = gpio_reg & ~(gpio->pin); + } else { + gpio_buff[0] = gpio_reg & ~(gpio->pin); + gpio_buff[1] = gpio_reg | gpio->pin; + } + LL_DMA_InitTypeDef dma_config = {}; + dma_config.MemoryOrM2MDstAddress = (uint32_t)gpio_buff; + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->ODR); + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_CIRCULAR; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; + dma_config.NbData = 2; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + + // Init timer arr register buffer and DMA channel + digital_signal_prepare_arr(signal, digital_signal_arr_buff); + dma_config.MemoryOrM2MDstAddress = (uint32_t)digital_signal_arr_buff; + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_NORMAL; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + dma_config.NbData = signal->edge_cnt - 2; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + dma_config.Priority = LL_DMA_PRIORITY_HIGH; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->edge_cnt - 2); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + + // Set up timer + LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetPrescaler(TIM2, 0); + LL_TIM_SetAutoReload(TIM2, 10); + LL_TIM_SetCounter(TIM2, 0); + LL_TIM_EnableUpdateEvent(TIM2); + LL_TIM_EnableDMAReq_UPDATE(TIM2); + + // Start transactions + LL_TIM_GenerateEvent_UPDATE(TIM2); // Do we really need it? + LL_TIM_EnableCounter(TIM2); + + while(!LL_DMA_IsActiveFlag_TC2(DMA1)) + ; + + LL_DMA_ClearFlag_TC1(DMA1); + LL_DMA_ClearFlag_TC2(DMA1); + LL_TIM_DisableCounter(TIM2); + LL_TIM_SetCounter(TIM2, 0); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + + return true; +} diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h new file mode 100644 index 00000000000..3b3ad77f7db --- /dev/null +++ b/lib/digital_signal/digital_signal.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#include + +typedef struct { + bool start_level; + uint32_t edge_cnt; + uint32_t edges_max_cnt; + float* edge_timings; +} DigitalSignal; + +DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt); + +void digital_signal_free(DigitalSignal* signal); + +bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b); + +bool digital_signal_get_start_level(DigitalSignal* signal); + +uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal); + +float digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num); + +bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio); diff --git a/lib/lib.mk b/lib/lib.mk index cb58fadeba4..43f4a1a259a 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -95,6 +95,11 @@ C_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*/*.c) CPP_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*.cpp) CPP_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*/*.cpp) +# Digital signal +CFLAGS += -I$(LIB_DIR)/digital_signal +C_SOURCES += $(wildcard $(LIB_DIR)/digital_signal/*.c) + + # USB Stack CFLAGS += -I$(LIB_DIR)/libusb_stm32/inc C_SOURCES += $(LIB_DIR)/libusb_stm32/src/usbd_stm32wb55_devfs.c diff --git a/lib/nfc_protocols/crypto1.c b/lib/nfc_protocols/crypto1.c index 469b0de09ad..f08164ba9f2 100644 --- a/lib/nfc_protocols/crypto1.c +++ b/lib/nfc_protocols/crypto1.c @@ -58,7 +58,7 @@ uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) { return out; } -uint8_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) { +uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) { furi_assert(crypto1); uint32_t out = 0; for(uint8_t i = 0; i < 32; i++) { diff --git a/lib/nfc_protocols/crypto1.h b/lib/nfc_protocols/crypto1.h index aaa2470c787..07b39c22ce7 100644 --- a/lib/nfc_protocols/crypto1.h +++ b/lib/nfc_protocols/crypto1.h @@ -16,7 +16,7 @@ uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted); uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted); -uint8_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); +uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); uint32_t crypto1_filter(uint32_t in); diff --git a/lib/nfc_protocols/mifare_classic.c b/lib/nfc_protocols/mifare_classic.c index ace37bff3c6..087fc74c956 100644 --- a/lib/nfc_protocols/mifare_classic.c +++ b/lib/nfc_protocols/mifare_classic.c @@ -311,3 +311,118 @@ uint8_t mf_classic_read_card( return sectors_read; } + +bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(emulator); + furi_assert(tx_rx); + + // Get first frame + tx_rx->tx_bits = 0; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + furi_hal_nfc_tx_rx(tx_rx, 300); + + // TODO support all commands + uint8_t cmd = tx_rx->rx_data[0]; + if(!(cmd == 0x60 || cmd == 0x61)) { + FURI_LOG_E(TAG, "Unsupported command"); + return false; + } + uint8_t block = tx_rx->rx_data[1]; + uint64_t key = 0; + // TODO Now works only for 1k!!! + uint8_t sector_trailer_block = block | 0x03; + MfClassicSectorTrailer* sector_trailer = + (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; + if(cmd & 0x01) { + key = nfc_util_bytes2num(sector_trailer->key_b, 6); + } else { + key = nfc_util_bytes2num(sector_trailer->key_a, 6); + } + + uint32_t nonce = prng_successor(DWT->CYCCNT, 32); + uint8_t nt[4]; + uint8_t nt_keystream[4]; + nfc_util_num2bytes(nonce, 4, nt); + nfc_util_num2bytes(nonce ^ emulator->cuid, 4, nt_keystream); + crypto1_init(&emulator->crypto, key); + crypto1_word(&emulator->crypto, emulator->cuid ^ nonce, 0); + + memcpy(tx_rx->tx_data, nt, sizeof(nt)); + tx_rx->tx_bits = sizeof(nt) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxRaw; + if(!furi_hal_nfc_tx_rx(tx_rx, 500)) { + FURI_LOG_E(TAG, "Error in 1st data exchange"); + return false; + } + + if(tx_rx->rx_bits != 64) { + FURI_LOG_E(TAG, "Incorrect nr + ar"); + return false; + } + + uint32_t nr = nfc_util_bytes2num(tx_rx->rx_data, 4); + uint32_t ar = nfc_util_bytes2num(&tx_rx->rx_data[4], 4); + crypto1_word(&emulator->crypto, nr, 1); + uint32_t cardRr = ar ^ crypto1_word(&emulator->crypto, 0, 0); + if(cardRr != prng_successor(nonce, 64)) { + FURI_LOG_E(TAG, "Wrong AUTH! %08X != %08X", cardRr, prng_successor(nonce, 64)); + // Don't send NACK, as tag don't send it + return false; + } + + uint32_t ans = prng_successor(nonce, 96); + uint8_t responce[4] = {}; + nfc_util_num2bytes(ans, 4, responce); + tx_rx->tx_parity[0] = 0; + for(uint8_t i = 0; i < 4; i++) { + tx_rx->tx_data[i] = crypto1_byte(&emulator->crypto, 0, 0) ^ responce[i]; + tx_rx->tx_parity[0] |= + (((crypto1_filter(emulator->crypto.odd) ^ nfc_util_odd_parity8(responce[i])) & 0x01) + << (7 - (i & 0x0007))); + } + + tx_rx->tx_bits = 8 * 4; + tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + + if(!furi_hal_nfc_tx_rx(tx_rx, 500)) { + FURI_LOG_E(TAG, "Error in 2nd data exchange"); + return false; + } + + uint8_t decrypted_cmd[4] = {}; + for(uint8_t i = 0; i < 4; i++) { + decrypted_cmd[i] = crypto1_byte(&emulator->crypto, 0, 0) ^ tx_rx->rx_data[i]; + } + + // FURI_LOG_I(TAG, "Decrypted: %02X %02X", decrypted_cmd[0], decrypted_cmd[1]); + if(decrypted_cmd[0] != 0x30) { + FURI_LOG_W(TAG, "Not read command"); + return false; + } + uint16_t block_num = decrypted_cmd[1]; + + // Send 0 block + uint8_t block_data[18] = {}; + memcpy(block_data, emulator->data.block[block_num].value, MF_CLASSIC_BLOCK_SIZE); + nfca_append_crc16(block_data, 16); + tx_rx->tx_parity[0] = 0; + tx_rx->tx_parity[1] = 0; + tx_rx->tx_parity[2] = 0; + + for(uint8_t i = 0; i < 18; i++) { + tx_rx->tx_data[i] = crypto1_byte(&emulator->crypto, 0, 0) ^ block_data[i]; + tx_rx->tx_parity[i >> 3] |= + (((crypto1_filter(emulator->crypto.odd) ^ nfc_util_odd_parity8(block_data[i])) & 0x01) + << (7 - (i & 0x0007))); + } + + tx_rx->tx_bits = 18 * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + + if(!furi_hal_nfc_tx_rx(tx_rx, 500)) { + FURI_LOG_E(TAG, "Error in Block emulation data exchange"); + return false; + } + + return false; +} diff --git a/lib/nfc_protocols/mifare_classic.h b/lib/nfc_protocols/mifare_classic.h index fa778b7719c..bfb0918c2b5 100644 --- a/lib/nfc_protocols/mifare_classic.h +++ b/lib/nfc_protocols/mifare_classic.h @@ -65,6 +65,12 @@ typedef struct { MfClassicSectorReader sector_reader[MF_CLASSIC_SECTORS_MAX]; } MfClassicReader; +typedef struct { + uint32_t cuid; + Crypto1 crypto; + MfClassicData data; +} MfClassicEmulator; + bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); bool mf_classic_get_type( @@ -100,3 +106,5 @@ uint8_t mf_classic_read_card( FuriHalNfcTxRxContext* tx_rx, MfClassicReader* reader, MfClassicData* data); + +bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx); diff --git a/lib/nfc_protocols/nfca.c b/lib/nfc_protocols/nfca.c index 81a6ddfccbe..1ee584067b4 100755 --- a/lib/nfc_protocols/nfca.c +++ b/lib/nfc_protocols/nfca.c @@ -1,11 +1,17 @@ #include "nfca.h" #include #include +#include #define NFCA_CMD_RATS (0xE0U) #define NFCA_CRC_INIT (0x6363) +#define NFCA_F_SIG (13560000.0) +#define NFCA_T_SIG (1.0 / NFCA_F_SIG) + +#define NFCA_SIGNAL_MAX_EDGES (1500) + typedef struct { uint8_t cmd; uint8_t param; @@ -53,3 +59,69 @@ bool nfca_emulation_handler( return sleep; } + +static void nfca_add_bit(DigitalSignal* signal, bool bit) { + if(bit) { + signal->start_level = true; + for(size_t i = 0; i < 7; i++) { + signal->edge_timings[i] = 8 * NFCA_T_SIG; + } + signal->edge_timings[7] = 9 * 8 * NFCA_T_SIG; + signal->edge_cnt = 8; + } else { + signal->start_level = false; + signal->edge_timings[0] = 8 * 8 * NFCA_T_SIG; + for(size_t i = 1; i < 9; i++) { + signal->edge_timings[i] = 8 * NFCA_T_SIG; + } + signal->edge_cnt = 9; + } +} + +static void nfca_add_byte(NfcaSignal* nfca_signal, uint8_t byte, bool parity) { + for(uint8_t i = 0; i < 8; i++) { + if(byte & (1 << i)) { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); + } else { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero); + } + } + if(parity) { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); + } else { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero); + } +} + +NfcaSignal* nfca_signal_alloc() { + NfcaSignal* nfca_signal = malloc(sizeof(NfcaSignal)); + nfca_signal->one = digital_signal_alloc(10); + nfca_signal->zero = digital_signal_alloc(10); + nfca_add_bit(nfca_signal->one, true); + nfca_add_bit(nfca_signal->zero, false); + nfca_signal->tx_signal = digital_signal_alloc(NFCA_SIGNAL_MAX_EDGES); + + return nfca_signal; +} + +void nfca_signal_free(NfcaSignal* nfca_signal) { + furi_assert(nfca_signal); + + digital_signal_free(nfca_signal->one); + digital_signal_free(nfca_signal->zero); + free(nfca_signal); +} + +void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t len, uint8_t* parity) { + furi_assert(nfca_signal); + furi_assert(data); + furi_assert(parity); + + nfca_signal->tx_signal->edge_cnt = 0; + nfca_signal->tx_signal->start_level = false; + // Start of frame + digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); + for(size_t i = 0; i < len; i++) { + nfca_add_byte(nfca_signal, data[i], parity[i / 8] & (1 << (7 - (i & 0x07)))); + } +} diff --git a/lib/nfc_protocols/nfca.h b/lib/nfc_protocols/nfca.h index 73e2e65e005..48d98032823 100644 --- a/lib/nfc_protocols/nfca.h +++ b/lib/nfc_protocols/nfca.h @@ -3,6 +3,14 @@ #include #include +#include + +typedef struct { + DigitalSignal* one; + DigitalSignal* zero; + DigitalSignal* tx_signal; +} NfcaSignal; + uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len); void nfca_append_crc16(uint8_t* buff, uint16_t len); @@ -12,3 +20,9 @@ bool nfca_emulation_handler( uint16_t buff_rx_len, uint8_t* buff_tx, uint16_t* buff_tx_len); + +NfcaSignal* nfca_signal_alloc(); + +void nfca_signal_free(NfcaSignal* nfca_signal); + +void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t len, uint8_t* parity);