WIP OFW PR 2825: NFC: Improved MFC emulation on some readers

Not finished yet, added in current condition for more tests
by AloneLiberty
This commit is contained in:
MX 2023-07-06 02:44:28 +03:00
parent d9b95fd156
commit a6978bfd2d
No known key found for this signature in database
GPG Key ID: 7CCC66B7DBDD1C83
4 changed files with 32 additions and 27 deletions

View File

@ -1107,7 +1107,9 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) {
furi_hal_nfc_listen_start(nfc_data); furi_hal_nfc_listen_start(nfc_data);
while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { //-V1044 while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { //-V1044
if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { if(furi_hal_nfc_listen_rx(&tx_rx, 300)) {
mf_classic_emulator(&emulator, &tx_rx, false); if(!mf_classic_emulator(&emulator, &tx_rx, false)) {
furi_hal_nfc_listen_start(nfc_data);
}
} }
} }
if(emulator.data_changed) { if(emulator.data_changed) {
@ -1382,8 +1384,6 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) {
bool reader_no_data_notified = true; bool reader_no_data_notified = true;
while(nfc_worker->state == NfcWorkerStateAnalyzeReader) { while(nfc_worker->state == NfcWorkerStateAnalyzeReader) {
furi_hal_nfc_stop_cmd();
furi_delay_ms(5);
furi_hal_nfc_listen_start(nfc_data); furi_hal_nfc_listen_start(nfc_data);
if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { if(furi_hal_nfc_listen_rx(&tx_rx, 300)) {
if(reader_no_data_notified) { if(reader_no_data_notified) {
@ -1394,7 +1394,9 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) {
NfcProtocol protocol = NfcProtocol protocol =
reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8); reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8);
if(protocol == NfcDeviceProtocolMifareClassic) { if(protocol == NfcDeviceProtocolMifareClassic) {
mf_classic_emulator(&emulator, &tx_rx, true); if(!mf_classic_emulator(&emulator, &tx_rx, true)) {
furi_hal_nfc_listen_start(nfc_data);
}
} }
} else { } else {
reader_no_data_received_cnt++; reader_no_data_received_cnt++;
@ -1406,6 +1408,7 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) {
FURI_LOG_D(TAG, "No data from reader"); FURI_LOG_D(TAG, "No data from reader");
continue; continue;
} }
furi_delay_ms(1);
} }
rfal_platform_spi_release(); rfal_platform_spi_release();

View File

@ -869,7 +869,7 @@ bool mf_classic_emulator(
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) { if(!furi_hal_nfc_tx_rx(tx_rx, 300)) {
FURI_LOG_D( FURI_LOG_D(
TAG, TAG,
"Error in tx rx. Tx :%d bits, Rx: %d bits", "Error in tx rx. Tx: %d bits, Rx: %d bits",
tx_rx->tx_bits, tx_rx->tx_bits,
tx_rx->rx_bits); tx_rx->rx_bits);
break; break;
@ -883,12 +883,17 @@ bool mf_classic_emulator(
break; break;
} }
if(cmd == 0x50 && plain_data[1] == 0x00) { if(cmd == NFCA_CMD_HALT && plain_data[1] == 0x00) {
FURI_LOG_T(TAG, "Halt received"); FURI_LOG_T(TAG, "Halt received");
furi_hal_nfc_listen_sleep(); return false;
command_processed = true; }
if(cmd == NFCA_CMD_RATS && !is_encrypted) {
// Mifare Classic doesn't support ATS, NACK it and start listening again
FURI_LOG_T(TAG, "RATS received");
break; break;
} }
if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD || cmd == MF_CLASSIC_AUTH_KEY_B_CMD) { if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD || cmd == MF_CLASSIC_AUTH_KEY_B_CMD) {
uint8_t block = plain_data[1]; uint8_t block = plain_data[1];
uint64_t key = 0; uint64_t key = 0;
@ -903,8 +908,7 @@ bool mf_classic_emulator(
access_key = MfClassicKeyA; access_key = MfClassicKeyA;
} else { } else {
FURI_LOG_D(TAG, "Key not known"); FURI_LOG_D(TAG, "Key not known");
command_processed = true; return false;
break;
} }
} else { } else {
if(mf_classic_is_key_found( if(mf_classic_is_key_found(
@ -914,8 +918,7 @@ bool mf_classic_emulator(
access_key = MfClassicKeyB; access_key = MfClassicKeyB;
} else { } else {
FURI_LOG_D(TAG, "Key not known"); FURI_LOG_D(TAG, "Key not known");
command_processed = true; return false;
break;
} }
} }
@ -943,16 +946,14 @@ bool mf_classic_emulator(
tx_rx->tx_bits = sizeof(nt) * 8; tx_rx->tx_bits = sizeof(nt) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
} }
if(!furi_hal_nfc_tx_rx(tx_rx, 500)) { if(!furi_hal_nfc_tx_rx(tx_rx, 500)) {
FURI_LOG_E(TAG, "Error in NT exchange"); FURI_LOG_E(TAG, "Error in NT exchange");
command_processed = true; return false;
break;
} }
if(tx_rx->rx_bits != 64) { if(tx_rx->rx_bits != 64) {
FURI_LOG_W(TAG, "Incorrect nr + ar length: %d", tx_rx->rx_bits); return false;
command_processed = true;
break;
} }
uint32_t nr = nfc_util_bytes2num(tx_rx->rx_data, 4); uint32_t nr = nfc_util_bytes2num(tx_rx->rx_data, 4);
@ -963,8 +964,7 @@ bool mf_classic_emulator(
if(cardRr != prng_successor(nonce, 64)) { if(cardRr != prng_successor(nonce, 64)) {
FURI_LOG_T(TAG, "Wrong AUTH! %08lX != %08lX", cardRr, prng_successor(nonce, 64)); FURI_LOG_T(TAG, "Wrong AUTH! %08lX != %08lX", cardRr, prng_successor(nonce, 64));
// Don't send NACK, as the tag doesn't send it // Don't send NACK, as the tag doesn't send it
command_processed = true; return false;
break;
} }
uint32_t ans = prng_successor(nonce, 96); uint32_t ans = prng_successor(nonce, 96);
@ -1156,6 +1156,7 @@ bool mf_classic_emulator(
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
tx_rx->tx_bits = 4; tx_rx->tx_bits = 4;
furi_hal_nfc_tx_rx(tx_rx, 300); furi_hal_nfc_tx_rx(tx_rx, 300);
return false;
} }
return true; return true;
@ -1164,7 +1165,7 @@ bool mf_classic_emulator(
void mf_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto) { void mf_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto) {
furi_assert(tx_rx); furi_assert(tx_rx);
uint8_t plain_data[4] = {0x50, 0x00, 0x00, 0x00}; uint8_t plain_data[4] = {NFCA_CMD_HALT, 0x00, 0x00, 0x00};
nfca_append_crc16(plain_data, 2); nfca_append_crc16(plain_data, 2);
if(crypto) { if(crypto) {

View File

@ -3,8 +3,6 @@
#include <stdio.h> #include <stdio.h>
#include <furi.h> #include <furi.h>
#define NFCA_CMD_RATS (0xE0U)
#define NFCA_CRC_INIT (0x6363) #define NFCA_CRC_INIT (0x6363)
#define NFCA_F_SIG (13560000.0) #define NFCA_F_SIG (13560000.0)
@ -22,7 +20,7 @@ typedef struct {
static uint8_t nfca_default_ats[] = {0x05, 0x78, 0x80, 0x80, 0x00}; static uint8_t nfca_default_ats[] = {0x05, 0x78, 0x80, 0x80, 0x00};
static uint8_t nfca_sleep_req[] = {0x50, 0x00}; static uint8_t nfca_halt_req[] = {NFCA_CMD_HALT, 0x00};
uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) { uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) {
uint16_t crc = NFCA_CRC_INIT; uint16_t crc = NFCA_CRC_INIT;
@ -50,17 +48,17 @@ bool nfca_emulation_handler(
uint16_t buff_rx_len, uint16_t buff_rx_len,
uint8_t* buff_tx, uint8_t* buff_tx,
uint16_t* buff_tx_len) { uint16_t* buff_tx_len) {
bool sleep = false; bool halt = false;
uint8_t rx_bytes = buff_rx_len / 8; uint8_t rx_bytes = buff_rx_len / 8;
if(rx_bytes == sizeof(nfca_sleep_req) && !memcmp(buff_rx, nfca_sleep_req, rx_bytes)) { if(rx_bytes == sizeof(nfca_halt_req) && !memcmp(buff_rx, nfca_halt_req, rx_bytes)) {
sleep = true; halt = true;
} else if(rx_bytes == sizeof(nfca_cmd_rats) && buff_rx[0] == NFCA_CMD_RATS) { } else if(rx_bytes == sizeof(nfca_cmd_rats) && buff_rx[0] == NFCA_CMD_RATS) {
memcpy(buff_tx, nfca_default_ats, sizeof(nfca_default_ats)); memcpy(buff_tx, nfca_default_ats, sizeof(nfca_default_ats));
*buff_tx_len = sizeof(nfca_default_ats) * 8; *buff_tx_len = sizeof(nfca_default_ats) * 8;
} }
return sleep; return halt;
} }
static void nfca_add_bit(DigitalSignal* signal, bool bit) { static void nfca_add_bit(DigitalSignal* signal, bool bit) {

View File

@ -5,6 +5,9 @@
#include <lib/digital_signal/digital_signal.h> #include <lib/digital_signal/digital_signal.h>
#define NFCA_CMD_RATS (0xE0U)
#define NFCA_CMD_HALT (0x50U)
typedef struct { typedef struct {
DigitalSignal* one; DigitalSignal* one;
DigitalSignal* zero; DigitalSignal* zero;