nfc: NTAG21x complete emulation (#1313)

* nfc: Refactor Mifare Ultralight feature flags
  Unify them in both reader and emulator to make handling easier
* nfc: Refactor MFUL PWD_AUTH and add AUTHLIM counter
* nfc: Add MFUL EV1 VCSL command emulation
* nfc: Enforce message size check in MFUL emulation
  Also fix READ_CNT byte order, but it's not fully working
* nfc: Add MFUL auth counter serialization
  Also fill counter on successful read from tag
* nfc: Fix MFUL INCR_CNT emulation
* nfc: Fix MFUL READ_CNT emulation
* nfc: Refactor MFUL emulation and implement full write support
* nfc: Fix Mifare Ultralight serialization
* nfc: Add MFUL OTP/CC handling
* nfc: Make sure MF0UL21 dynamic lock byte 3 also reads 0xBD
* nfc: Small MFUL refactor and fix CFGLCK behavior
* WIP: nfc: MFUL read support with ASCII mirror and auth roll-over
  This is too complex and I don't like it
* nfc: Simplify MFUL read emulation, fix mirror range check
* nfc: Implement MFUL auth and ASCII mirror for FAST_READ
* nfc: Fix MFUL read roll-over with AUTH0 set
* nfc: Implement MFUL read counter increment
* nfc: Align ASCII mirror to NTAG21x behavior
* nfc: Handle invalid command in MFUL emulation
* nfc: Fix MFUL static lock check
* nfc: Refactor MFUL emulation to use cached config pages
* nfc: Refactor MFUL auth counter to count up instead of down
* nfc: Add missing NULL check
* WIP: nfc: Various MFUL emulation behavior tweaks
* WIP: nfc: More MFUL emulation behavior adjustments
* nfc: Match AUTHLIM emulation to NTAG21x behavior
* nfc: Fix MFUL dynamic lock emulation
* nfc: Fix typo in MFUL read counters
* nfc: Fix typo in MFUL FAST_READ emulation
* nfc: Increase emulation TX buffer size
  Enough space for if someone requests FAST_READ of all pages of an NTAG
* nfc: Fix MFUL negative verification counter overflow
* nfc: Change auth counter kv name
* nfc: Fix NTAG I2C FAST_READ emulation
* nfc: Fix NTAG21x config reload behavior

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Yukai Li 2022-06-21 09:04:35 -06:00 committed by GitHub
parent 88facf20c1
commit 556af0b82b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 957 additions and 327 deletions

View File

@ -120,6 +120,12 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev)
} }
} }
if(!pages_saved) break; if(!pages_saved) break;
// Write authentication counter
uint32_t auth_counter = data->curr_authlim;
if(!flipper_format_write_uint32(file, "Failed authentication attempts", &auth_counter, 1))
break;
saved = true; saved = true;
} while(false); } while(false);
@ -169,6 +175,12 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
} }
} }
if(!pages_parsed) break; if(!pages_parsed) break;
// Read authentication counter
uint32_t auth_counter;
if(!flipper_format_read_uint32(file, "Failed authentication attempts", &auth_counter, 1))
auth_counter = 0;
parsed = true; parsed = true;
} while(false); } while(false);

View File

@ -319,11 +319,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
MfUltralightEmulator emulator = {}; MfUltralightEmulator emulator = {};
mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data); mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data);
while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) { while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
emulator.auth_success = false; mf_ul_reset_emulation(&emulator, true);
if(emulator.data.type >= MfUltralightTypeNTAGI2C1K) {
// Sector index needs to be reset
emulator.curr_sector = 0;
}
furi_hal_nfc_emulate_nfca( furi_hal_nfc_emulate_nfca(
nfc_data->uid, nfc_data->uid,
nfc_data->uid_len, nfc_data->uid_len,

View File

@ -277,7 +277,7 @@ bool furi_hal_nfc_emulate_nfca(
uint8_t buff_rx[256]; uint8_t buff_rx[256];
uint16_t buff_rx_size = 256; uint16_t buff_rx_size = 256;
uint16_t buff_rx_len = 0; uint16_t buff_rx_len = 0;
uint8_t buff_tx[256]; uint8_t buff_tx[1040];
uint16_t buff_tx_len = 0; uint16_t buff_tx_len = 0;
uint32_t data_type = FURI_HAL_NFC_TXRX_DEFAULT; uint32_t data_type = FURI_HAL_NFC_TXRX_DEFAULT;

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,10 @@
#define MF_UL_READ_VCSL (0x4B) #define MF_UL_READ_VCSL (0x4B)
#define MF_UL_SECTOR_SELECT (0xC2) #define MF_UL_SECTOR_SELECT (0xC2)
#define MF_UL_ACK (0xa)
#define MF_UL_NAK_INVALID_ARGUMENT (0x0)
#define MF_UL_NAK_AUTHLIM_REACHED (0x4)
typedef enum { typedef enum {
MfUltralightTypeUnknown, MfUltralightTypeUnknown,
MfUltralightTypeUL11, MfUltralightTypeUL11,
@ -38,6 +42,31 @@ typedef enum {
MfUltralightTypeNum, MfUltralightTypeNum,
} MfUltralightType; } MfUltralightType;
typedef enum {
MfUltralightSupportNone = 0,
MfUltralightSupportFastRead = 1 << 0,
MfUltralightSupportTearingFlags = 1 << 1,
MfUltralightSupportReadCounter = 1 << 2,
MfUltralightSupportIncrCounter = 1 << 3,
MfUltralightSupportSignature = 1 << 4,
MfUltralightSupportFastWrite = 1 << 5,
MfUltralightSupportCompatWrite = 1 << 6,
MfUltralightSupportAuth = 1 << 7,
MfUltralightSupportVcsl = 1 << 8,
MfUltralightSupportSectorSelect = 1 << 9,
// NTAG21x only has counter 2
MfUltralightSupportSingleCounter = 1 << 10,
// ASCII mirror is not a command, but handy to have as a flag
MfUltralightSupportAsciiMirror = 1 << 11,
} MfUltralightFeatures;
typedef enum {
MfUltralightMirrorNone,
MfUltralightMirrorUid,
MfUltralightMirrorCounter,
MfUltralightMirrorUidCounter,
} MfUltralightMirrorConf;
typedef struct { typedef struct {
uint8_t header; uint8_t header;
uint8_t vendor_id; uint8_t vendor_id;
@ -65,38 +94,76 @@ typedef struct {
uint8_t signature[32]; uint8_t signature[32];
uint32_t counter[3]; uint32_t counter[3];
uint8_t tearing[3]; uint8_t tearing[3];
uint16_t curr_authlim;
uint16_t data_size; uint16_t data_size;
uint8_t data[MF_UL_MAX_DUMP_SIZE]; uint8_t data[MF_UL_MAX_DUMP_SIZE];
} MfUltralightData; } MfUltralightData;
typedef struct { typedef struct __attribute__((packed)) {
uint8_t pwd[4]; union {
uint8_t raw[4];
uint32_t value;
} pwd;
union { union {
uint8_t raw[2]; uint8_t raw[2];
uint16_t value; uint16_t value;
} pack; } pack;
} MfUltralightAuth; } MfUltralightAuth;
// Common configuration pages for MFUL EV1, NTAG21x, and NTAG I2C Plus
typedef struct __attribute__((packed)) {
union {
uint8_t value;
struct {
uint8_t rfui1 : 2;
bool strg_mod_en : 1;
bool rfui2 : 1;
uint8_t mirror_byte : 2;
MfUltralightMirrorConf mirror_conf : 2;
};
} mirror;
uint8_t rfui1;
uint8_t mirror_page;
uint8_t auth0;
union {
uint8_t value;
struct {
uint8_t authlim : 3;
bool nfc_cnt_pwd_prot : 1;
bool nfc_cnt_en : 1;
bool nfc_dis_sec1 : 1; // NTAG I2C Plus only
bool cfglck : 1;
bool prot : 1;
};
} access;
uint8_t vctid;
uint8_t rfui2[2];
MfUltralightAuth auth_data;
uint8_t rfui3[2];
} MfUltralightConfigPages;
typedef struct { typedef struct {
uint16_t pages_to_read; uint16_t pages_to_read;
int16_t pages_read; int16_t pages_read;
bool support_fast_read; MfUltralightFeatures supported_features;
bool support_tearing_flags;
bool support_counters;
bool support_signature;
} MfUltralightReader; } MfUltralightReader;
typedef struct { typedef struct {
MfUltralightData data; MfUltralightData data;
bool support_fast_read; MfUltralightConfigPages* config;
// Most config values don't apply until power cycle, so cache config pages
// for correct behavior
MfUltralightConfigPages config_cache;
MfUltralightFeatures supported_features;
uint16_t page_num;
bool data_changed; bool data_changed;
bool comp_write_cmd_started; bool comp_write_cmd_started;
uint8_t comp_write_page_addr; uint8_t comp_write_page_addr;
MfUltralightAuth* auth_data;
bool auth_success; bool auth_success;
uint8_t curr_sector; uint8_t curr_sector;
bool sector_select_cmd_started; bool sector_select_cmd_started;
bool ntag_i2c_plus_sector3_lockout; bool ntag_i2c_plus_sector3_lockout;
bool read_counter_incremented;
} MfUltralightEmulator; } MfUltralightEmulator;
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
@ -127,6 +194,8 @@ bool mf_ul_read_card(
MfUltralightReader* reader, MfUltralightReader* reader,
MfUltralightData* data); MfUltralightData* data);
void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle);
void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data); void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data);
bool mf_ul_prepare_emulation_response( bool mf_ul_prepare_emulation_response(