Reapply "Merge remote-tracking branch 'OFW/astra/3746-mfp-detect' into dev"

This reverts commit 6bfa383cea.
This commit is contained in:
MX 2024-06-06 00:55:29 +03:00
parent 528636c814
commit bde889c338
No known key found for this signature in database
GPG key ID: 7CCC66B7DBDD1C83
20 changed files with 1344 additions and 0 deletions

View file

@ -0,0 +1,121 @@
#include "mf_plus.h"
#include "mf_plus_render.h"
#include <nfc/protocols/mf_plus/mf_plus_poller.h>
#include "nfc/nfc_app_i.h"
#include "../nfc_protocol_support_common.h"
#include "../nfc_protocol_support_gui_common.h"
#include "../iso14443_4a/iso14443_4a_i.h"
static void nfc_scene_info_on_enter_mf_plus(NfcApp* instance) {
const NfcDevice* device = instance->nfc_device;
const MfPlusData* data = nfc_device_get_data(device, NfcProtocolMfPlus);
FuriString* temp_str = furi_string_alloc();
nfc_append_filename_string_when_present(instance, temp_str);
furi_string_cat_printf(
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
furi_string_replace(temp_str, "Mifare", "MIFARE");
nfc_render_mf_plus_info(data, NfcProtocolFormatTypeFull, temp_str);
widget_add_text_scroll_element(
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
}
static NfcCommand nfc_scene_read_poller_callback_mf_plus(NfcGenericEvent event, void* context) {
furi_assert(event.protocol == NfcProtocolMfPlus);
NfcApp* instance = context;
const MfPlusPollerEvent* mf_plus_event = event.event_data;
if(mf_plus_event->type == MfPlusPollerEventTypeReadSuccess) {
nfc_device_set_data(
instance->nfc_device, NfcProtocolMfPlus, nfc_poller_get_data(instance->poller));
FURI_LOG_D(
"MFP",
"Read success: %s",
nfc_device_get_name(instance->nfc_device, NfcDeviceNameTypeFull));
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
return NfcCommandStop;
}
return NfcCommandContinue;
}
static void nfc_scene_read_on_enter_mf_plus(NfcApp* instance) {
nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_plus, instance);
}
static void nfc_scene_read_success_on_enter_mf_plus(NfcApp* instance) {
const NfcDevice* device = instance->nfc_device;
const MfPlusData* data = nfc_device_get_data(device, NfcProtocolMfPlus);
FuriString* temp_str = furi_string_alloc();
furi_string_cat_printf(
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
furi_string_replace(temp_str, "Mifare", "MIFARE");
nfc_render_mf_plus_info(data, NfcProtocolFormatTypeShort, temp_str);
widget_add_text_scroll_element(
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
}
static void nfc_scene_emulate_on_enter_mf_plus(NfcApp* instance) {
const Iso14443_4aData* iso14443_4a_data =
nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_4a);
instance->listener =
nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, iso14443_4a_data);
nfc_listener_start(
instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance);
}
const NfcProtocolSupportBase nfc_protocol_support_mf_plus = {
.features = NfcProtocolFeatureMoreInfo,
.scene_info =
{
.on_enter = nfc_scene_info_on_enter_mf_plus,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_more_info =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_read =
{
.on_enter = nfc_scene_read_on_enter_mf_plus,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_read_menu =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_read_success =
{
.on_enter = nfc_scene_read_success_on_enter_mf_plus,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_saved_menu =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_save_name =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_emulate =
{
.on_enter = nfc_scene_emulate_on_enter_mf_plus,
.on_event = nfc_protocol_support_common_on_event_empty,
},
};

View file

@ -0,0 +1,5 @@
#pragma once
#include "../nfc_protocol_support_base.h"
extern const NfcProtocolSupportBase nfc_protocol_support_mf_plus;

View file

@ -0,0 +1,67 @@
#include "mf_plus_render.h"
#include "../iso14443_4a/iso14443_4a_render.h"
void nfc_render_mf_plus_info(
const MfPlusData* data,
NfcProtocolFormatType format_type,
FuriString* str) {
nfc_render_iso14443_4a_brief(mf_plus_get_base_data(data), str);
if(format_type != NfcProtocolFormatTypeFull) return;
furi_string_cat(str, "\n\e#ISO14443-4 data");
nfc_render_iso14443_4a_extra(mf_plus_get_base_data(data), str);
}
void nfc_render_mf_plus_data(const MfPlusData* data, FuriString* str) {
nfc_render_mf_plus_version(&data->version, str);
}
void nfc_render_mf_plus_version(const MfPlusVersion* data, FuriString* str) {
furi_string_cat_printf(
str,
"%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
data->uid[0],
data->uid[1],
data->uid[2],
data->uid[3],
data->uid[4],
data->uid[5],
data->uid[6]);
furi_string_cat_printf(
str,
"hw %02x type %02x sub %02x\n"
" maj %02x min %02x\n"
" size %02x proto %02x\n",
data->hw_vendor,
data->hw_type,
data->hw_subtype,
data->hw_major,
data->hw_minor,
data->hw_storage,
data->hw_proto);
furi_string_cat_printf(
str,
"sw %02x type %02x sub %02x\n"
" maj %02x min %02x\n"
" size %02x proto %02x\n",
data->sw_vendor,
data->sw_type,
data->sw_subtype,
data->sw_major,
data->sw_minor,
data->sw_storage,
data->sw_proto);
furi_string_cat_printf(
str,
"batch %02x:%02x:%02x:%02x:%02x\n"
"week %d year %d\n",
data->batch[0],
data->batch[1],
data->batch[2],
data->batch[3],
data->batch[4],
data->prod_week,
data->prod_year);
}

View file

@ -0,0 +1,14 @@
#pragma once
#include <nfc/protocols/mf_plus/mf_plus.h>
#include "../nfc_protocol_support_render_common.h"
void nfc_render_mf_plus_info(
const MfPlusData* data,
NfcProtocolFormatType format_type,
FuriString* str);
void nfc_render_mf_plus_data(const MfPlusData* data, FuriString* str);
void nfc_render_mf_plus_version(const MfPlusVersion* data, FuriString* str);

View file

@ -17,6 +17,7 @@
#include "felica/felica.h"
#include "mf_ultralight/mf_ultralight.h"
#include "mf_classic/mf_classic.h"
#include "mf_plus/mf_plus.h"
#include "mf_desfire/mf_desfire.h"
#include "emv/emv.h"
#include "slix/slix.h"
@ -39,6 +40,7 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = {
[NfcProtocolFelica] = &nfc_protocol_support_felica,
[NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight,
[NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic,
[NfcProtocolMfPlus] = &nfc_protocol_support_mf_plus,
[NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire,
[NfcProtocolSlix] = &nfc_protocol_support_slix,
[NfcProtocolSt25tb] = &nfc_protocol_support_st25tb,

View file

@ -21,6 +21,7 @@ env.Append(
File("protocols/iso14443_4b/iso14443_4b.h"),
File("protocols/mf_ultralight/mf_ultralight.h"),
File("protocols/mf_classic/mf_classic.h"),
File("protocols/mf_plus/mf_plus.h"),
File("protocols/mf_desfire/mf_desfire.h"),
File("protocols/emv/emv.h"),
File("protocols/slix/slix.h"),
@ -33,6 +34,7 @@ env.Append(
File("protocols/iso14443_4b/iso14443_4b_poller.h"),
File("protocols/mf_ultralight/mf_ultralight_poller.h"),
File("protocols/mf_classic/mf_classic_poller.h"),
File("protocols/mf_plus/mf_plus_poller.h"),
File("protocols/mf_desfire/mf_desfire_poller.h"),
File("protocols/slix/slix_poller.h"),
File("protocols/emv/emv_poller.h"),

View file

@ -0,0 +1,189 @@
#include "mf_plus_i.h"
#include <bit_lib/bit_lib.h>
#include <furi.h>
#define MF_PLUS_PROTOCOL_NAME "Mifare Plus"
static const char* mf_plus_type_strings[] = {
[MfPlusTypeS] = "Plus S",
[MfPlusTypeX] = "Plus X",
[MfPlusTypeSE] = "Plus SE",
[MfPlusTypeEV1] = "Plus EV1",
[MfPlusTypeEV2] = "Plus EV2",
[MfPlusTypePlus] = "Plus",
[MfPlusTypeUnknown] = "Unknown",
};
static const char* mf_plus_size_strings[] = {
[MfPlusSize1K] = "1K",
[MfPlusSize2K] = "2K",
[MfPlusSize4K] = "4K",
[MfPlusSizeUnknown] = "Unknown",
};
static const char* mf_plus_security_level_strings[] = {
[MfPlusSecurityLevel0] = "SL0",
[MfPlusSecurityLevel1] = "SL1",
[MfPlusSecurityLevel2] = "SL2",
[MfPlusSecurityLevel3] = "SL3",
[MfPlusSecurityLevelUnknown] = "Unknown",
};
const NfcDeviceBase nfc_device_mf_plus = {
.protocol_name = MF_PLUS_PROTOCOL_NAME,
.alloc = (NfcDeviceAlloc)mf_plus_alloc,
.free = (NfcDeviceFree)mf_plus_free,
.reset = (NfcDeviceReset)mf_plus_reset,
.copy = (NfcDeviceCopy)mf_plus_copy,
.verify = (NfcDeviceVerify)mf_plus_verify,
.load = (NfcDeviceLoad)mf_plus_load,
.save = (NfcDeviceSave)mf_plus_save,
.is_equal = (NfcDeviceEqual)mf_plus_is_equal,
.get_name = (NfcDeviceGetName)mf_plus_get_device_name,
.get_uid = (NfcDeviceGetUid)mf_plus_get_uid,
.set_uid = (NfcDeviceSetUid)mf_plus_set_uid,
.get_base_data = (NfcDeviceGetBaseData)mf_plus_get_base_data,
};
MfPlusData* mf_plus_alloc(void) {
MfPlusData* data = malloc(sizeof(MfPlusData));
data->device_name = furi_string_alloc();
data->iso14443_4a_data = iso14443_4a_alloc();
data->type = MfPlusTypeUnknown;
data->security_level = MfPlusSecurityLevelUnknown;
data->size = MfPlusSizeUnknown;
return data;
}
void mf_plus_free(MfPlusData* data) {
furi_check(data);
furi_string_free(data->device_name);
iso14443_4a_free(data->iso14443_4a_data);
free(data);
}
void mf_plus_reset(MfPlusData* data) {
furi_check(data);
iso14443_4a_reset(data->iso14443_4a_data);
memset(&data->version, 0, sizeof(data->version));
data->type = MfPlusTypeUnknown;
data->security_level = MfPlusSecurityLevelUnknown;
data->size = MfPlusSizeUnknown;
}
void mf_plus_copy(MfPlusData* data, const MfPlusData* other) {
furi_check(data);
furi_check(other);
iso14443_4a_copy(data->iso14443_4a_data, other->iso14443_4a_data);
data->version = other->version;
data->type = other->type;
data->security_level = other->security_level;
data->size = other->size;
}
bool mf_plus_verify(MfPlusData* data, const FuriString* device_type) {
UNUSED(data);
return furi_string_equal_str(device_type, MF_PLUS_PROTOCOL_NAME);
}
bool mf_plus_load(MfPlusData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
bool success = false;
do {
if(!iso14443_4a_load(data->iso14443_4a_data, ff, version)) break;
if(!mf_plus_version_load(&data->version, ff)) break;
if(!mf_plus_type_load(&data->type, ff)) break;
if(!mf_plus_security_level_load(&data->security_level, ff)) break;
if(!mf_plus_size_load(&data->size, ff)) break;
success = true;
} while(false);
return success;
}
bool mf_plus_save(const MfPlusData* data, FlipperFormat* ff) {
furi_assert(data);
bool success = false;
do {
if(!iso14443_4a_save(data->iso14443_4a_data, ff)) break;
if(!flipper_format_write_comment_cstr(ff, MF_PLUS_PROTOCOL_NAME " specific data")) break;
if(!mf_plus_version_save(&data->version, ff)) break;
if(!mf_plus_type_save(&data->type, ff)) break;
if(!mf_plus_security_level_save(&data->security_level, ff)) break;
if(!mf_plus_size_save(&data->size, ff)) break;
success = true;
} while(false);
return success;
}
bool mf_plus_is_equal(const MfPlusData* data, const MfPlusData* other) {
furi_assert(data);
furi_assert(other);
bool equal = false;
do {
if(!iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data)) break;
if(memcmp(&data->version, &other->version, sizeof(data->version)) != 0) break;
if(data->security_level != other->security_level) break;
if(data->type != other->type) break;
if(data->size != other->size) break;
equal = true;
} while(false);
return equal;
}
const char* mf_plus_get_device_name(const MfPlusData* data, NfcDeviceNameType name_type) {
furi_check(data);
FuriString* full_name = furi_string_alloc();
const char* name = NULL;
do {
if(name_type == NfcDeviceNameTypeFull) {
furi_string_reset(data->device_name);
furi_string_cat_printf(
data->device_name,
"Mifare %s %s %s",
mf_plus_type_strings[data->type], // Includes "Plus" for regular Mifare Plus cards
mf_plus_size_strings[data->size],
mf_plus_security_level_strings[data->security_level]);
name = furi_string_get_cstr(data->device_name);
FURI_LOG_D("Mifare Plus", "Full name: %s", name);
} else if(name_type == NfcDeviceNameTypeShort) {
name = "Mifare Plus";
} else {
break;
}
} while(false);
furi_string_free(full_name);
FURI_LOG_D("Mifare Plus", "Name: %s", name);
return name;
}
const uint8_t* mf_plus_get_uid(const MfPlusData* data, size_t* uid_len) {
furi_assert(data);
return iso14443_4a_get_uid(data->iso14443_4a_data, uid_len);
}
bool mf_plus_set_uid(MfPlusData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
return iso14443_4a_set_uid(data->iso14443_4a_data, uid, uid_len);
}
Iso14443_4aData* mf_plus_get_base_data(const MfPlusData* data) {
furi_check(data);
return data->iso14443_4a_data;
}

View file

@ -0,0 +1,117 @@
#pragma once
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a.h>
#include <lib/toolbox/simple_array.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MF_PLUS_UID_SIZE (7)
#define MF_PLUS_BATCH_SIZE (5)
#define MF_PLUS_CMD_GET_VERSION (0x60)
typedef enum {
MfPlusErrorNone,
MfPlusErrorUnknown,
MfPlusErrorNotPresent,
MfPlusErrorProtocol,
MfPlusErrorAuth,
MfPlusErrorPartialRead,
MfPlusErrorTimeout,
} MfPlusError;
typedef enum {
MfPlusTypePlus,
MfPlusTypeEV1,
MfPlusTypeEV2,
MfPlusTypeS,
MfPlusTypeSE,
MfPlusTypeX,
MfPlusTypeUnknown,
MfPlusTypeNum,
} MfPlusType;
typedef enum {
MfPlusSize1K,
MfPlusSize2K,
MfPlusSize4K,
MfPlusSizeUnknown,
MfPlusSizeNum,
} MfPlusSize;
typedef enum {
MfPlusSecurityLevel0,
MfPlusSecurityLevel1,
MfPlusSecurityLevel2,
MfPlusSecurityLevel3,
MfPlusSecurityLevelUnknown,
MfPlusSecurityLevelNum,
} MfPlusSecurityLevel;
typedef struct {
uint8_t hw_vendor;
uint8_t hw_type;
uint8_t hw_subtype;
uint8_t hw_major;
uint8_t hw_minor;
uint8_t hw_storage;
uint8_t hw_proto;
uint8_t sw_vendor;
uint8_t sw_type;
uint8_t sw_subtype;
uint8_t sw_major;
uint8_t sw_minor;
uint8_t sw_storage;
uint8_t sw_proto;
uint8_t uid[MF_PLUS_UID_SIZE];
uint8_t batch[MF_PLUS_BATCH_SIZE];
uint8_t prod_week;
uint8_t prod_year;
} MfPlusVersion;
typedef struct {
Iso14443_4aData* iso14443_4a_data;
MfPlusVersion version;
MfPlusType type;
MfPlusSize size;
MfPlusSecurityLevel security_level;
FuriString* device_name;
} MfPlusData;
extern const NfcDeviceBase nfc_device_mf_plus;
MfPlusData* mf_plus_alloc(void);
void mf_plus_free(MfPlusData* data);
void mf_plus_reset(MfPlusData* data);
void mf_plus_copy(MfPlusData* data, const MfPlusData* other);
bool mf_plus_verify(MfPlusData* data, const FuriString* device_type);
bool mf_plus_load(MfPlusData* data, FlipperFormat* ff, uint32_t version);
bool mf_plus_save(const MfPlusData* data, FlipperFormat* ff);
bool mf_plus_is_equal(const MfPlusData* data, const MfPlusData* other);
const char* mf_plus_get_device_name(const MfPlusData* data, NfcDeviceNameType name_type);
const uint8_t* mf_plus_get_uid(const MfPlusData* data, size_t* uid_len);
bool mf_plus_set_uid(MfPlusData* data, const uint8_t* uid, size_t uid_len);
Iso14443_4aData* mf_plus_get_base_data(const MfPlusData* data);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,216 @@
#include "mf_plus_i.h"
#define MF_PLUS_FFF_VERSION_KEY \
MF_PLUS_FFF_PICC_PREFIX " " \
"Version"
#define MF_PLUS_FFF_SECURITY_LEVEL_KEY "Security Level"
#define MF_PLUS_FFF_CARD_TYPE_KEY "Card Type"
#define MF_PLUS_FFF_MEMORY_SIZE_KEY "Memory Size"
bool mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf) {
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion);
if(can_parse) {
bit_buffer_write_bytes(buf, data, sizeof(MfPlusVersion));
}
return can_parse;
}
bool mf_plus_security_level_parse(MfPlusSecurityLevel* data, const BitBuffer* buf) {
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusSecurityLevel);
if(can_parse) {
bit_buffer_write_bytes(buf, data, sizeof(MfPlusSecurityLevel));
}
return can_parse;
}
bool mf_plus_type_parse(MfPlusType* data, const BitBuffer* buf) {
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusType);
if(can_parse) {
bit_buffer_write_bytes(buf, data, sizeof(MfPlusType));
}
return can_parse;
}
bool mf_plus_size_parse(MfPlusSize* data, const BitBuffer* buf) {
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusSize);
if(can_parse) {
bit_buffer_write_bytes(buf, data, sizeof(MfPlusSize));
}
return can_parse;
}
bool mf_plus_version_load(MfPlusVersion* data, FlipperFormat* ff) {
return flipper_format_read_hex(
ff, MF_PLUS_FFF_VERSION_KEY, (uint8_t*)data, sizeof(MfPlusVersion));
}
bool mf_plus_security_level_load(MfPlusSecurityLevel* data, FlipperFormat* ff) {
FuriString* security_level_string = furi_string_alloc();
flipper_format_read_string(ff, MF_PLUS_FFF_SECURITY_LEVEL_KEY, security_level_string);
// Take the last character of the string
char security_level_char = furi_string_get_char(
security_level_string, furi_string_utf8_length(security_level_string) - 1);
switch(security_level_char) {
case '0':
*data = MfPlusSecurityLevel0;
break;
case '1':
*data = MfPlusSecurityLevel1;
break;
case '2':
*data = MfPlusSecurityLevel2;
break;
case '3':
*data = MfPlusSecurityLevel3;
break;
default:
*data = MfPlusSecurityLevelUnknown;
break;
}
furi_string_free(security_level_string);
return true;
}
bool mf_plus_type_load(MfPlusType* data, FlipperFormat* ff) {
FuriString* type_string = furi_string_alloc();
flipper_format_read_string(ff, MF_PLUS_FFF_CARD_TYPE_KEY, type_string);
if(furi_string_equal_str(type_string, "Mifare Plus")) {
*data = MfPlusTypePlus;
} else if(furi_string_equal_str(type_string, "Mifare Plus X")) {
*data = MfPlusTypeX;
} else if(furi_string_equal_str(type_string, "Mifare Plus S")) {
*data = MfPlusTypeS;
} else if(furi_string_equal_str(type_string, "Mifare Plus SE")) {
*data = MfPlusTypeSE;
} else if(furi_string_equal_str(type_string, "Mifare Plus EV1")) {
*data = MfPlusTypeEV1;
} else if(furi_string_equal_str(type_string, "Mifare Plus EV2")) {
*data = MfPlusTypeEV2;
} else {
*data = MfPlusTypeUnknown;
}
furi_string_free(type_string);
return true;
}
bool mf_plus_size_load(MfPlusSize* data, FlipperFormat* ff) {
FuriString* size_string = furi_string_alloc();
flipper_format_read_string(ff, MF_PLUS_FFF_MEMORY_SIZE_KEY, size_string);
if(furi_string_equal_str(size_string, "1K")) {
*data = MfPlusSize1K;
} else if(furi_string_equal_str(size_string, "2K")) {
*data = MfPlusSize2K;
} else if(furi_string_equal_str(size_string, "4K")) {
*data = MfPlusSize4K;
} else {
*data = MfPlusSizeUnknown;
}
furi_string_free(size_string);
return true;
}
bool mf_plus_version_save(const MfPlusVersion* data, FlipperFormat* ff) {
return flipper_format_write_hex(
ff, MF_PLUS_FFF_VERSION_KEY, (const uint8_t*)data, sizeof(MfPlusVersion));
}
bool mf_plus_security_level_save(const MfPlusSecurityLevel* data, FlipperFormat* ff) {
FuriString* security_level_string = furi_string_alloc();
switch(*data) {
case MfPlusSecurityLevel0:
furi_string_cat(security_level_string, "SL0");
break;
case MfPlusSecurityLevel1:
furi_string_cat(security_level_string, "SL1");
break;
case MfPlusSecurityLevel2:
furi_string_cat(security_level_string, "SL2");
break;
case MfPlusSecurityLevel3:
furi_string_cat(security_level_string, "SL3");
break;
default:
furi_string_cat(security_level_string, "Unknown");
break;
}
flipper_format_write_string(ff, MF_PLUS_FFF_SECURITY_LEVEL_KEY, security_level_string);
furi_string_free(security_level_string);
return true;
}
bool mf_plus_type_save(const MfPlusType* data, FlipperFormat* ff) {
FuriString* type_string = furi_string_alloc();
switch(*data) {
case MfPlusTypePlus:
furi_string_cat(type_string, "Mifare Plus");
break;
case MfPlusTypeX:
furi_string_cat(type_string, "Mifare Plus X");
break;
case MfPlusTypeS:
furi_string_cat(type_string, "Mifare Plus S");
break;
case MfPlusTypeSE:
furi_string_cat(type_string, "Mifare Plus SE");
break;
case MfPlusTypeEV1:
furi_string_cat(type_string, "Mifare Plus EV1");
break;
case MfPlusTypeEV2:
furi_string_cat(type_string, "Mifare Plus EV2");
break;
default:
furi_string_cat(type_string, "Unknown");
break;
}
flipper_format_write_string(ff, MF_PLUS_FFF_CARD_TYPE_KEY, type_string);
furi_string_free(type_string);
return true;
}
bool mf_plus_size_save(const MfPlusSize* data, FlipperFormat* ff) {
FuriString* size_string = furi_string_alloc();
switch(*data) {
case MfPlusSize1K:
furi_string_cat(size_string, "1K");
break;
case MfPlusSize2K:
furi_string_cat(size_string, "2K");
break;
case MfPlusSize4K:
furi_string_cat(size_string, "4K");
break;
default:
furi_string_cat(size_string, "Unknown");
break;
}
flipper_format_write_string(ff, MF_PLUS_FFF_MEMORY_SIZE_KEY, size_string);
furi_string_free(size_string);
return true;
}

View file

@ -0,0 +1,29 @@
#pragma once
#include "mf_plus.h"
#define MF_PLUS_FFF_PICC_PREFIX "PICC"
bool mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf);
bool mf_plus_security_level_parse(MfPlusSecurityLevel* data, const BitBuffer* buf);
bool mf_plus_type_parse(MfPlusType* data, const BitBuffer* buf);
bool mf_plus_size_parse(MfPlusSize* data, const BitBuffer* buf);
bool mf_plus_version_load(MfPlusVersion* data, FlipperFormat* ff);
bool mf_plus_security_level_load(MfPlusSecurityLevel* data, FlipperFormat* ff);
bool mf_plus_type_load(MfPlusType* data, FlipperFormat* ff);
bool mf_plus_size_load(MfPlusSize* data, FlipperFormat* ff);
bool mf_plus_version_save(const MfPlusVersion* data, FlipperFormat* ff);
bool mf_plus_security_level_save(const MfPlusSecurityLevel* data, FlipperFormat* ff);
bool mf_plus_type_save(const MfPlusType* data, FlipperFormat* ff);
bool mf_plus_size_save(const MfPlusSize* data, FlipperFormat* ff);

View file

@ -0,0 +1,367 @@
#include "mf_plus_poller_i.h"
#include <nfc/protocols/nfc_poller_base.h>
#include <furi.h>
#define TAG "MfPlusPoller"
#define MF_PLUS_BUF_SIZE (64U)
#define MF_PLUS_RESULT_BUF_SIZE (512U)
const char* mf_plus_ats_t1_tk_values[] = {
"\xC1\x05\x2F\x2F\x00\x35\xC7", // Mifare Plus S
"\xC1\x05\x2F\x2F\x01\xBC\xD6", // Mifare Plus X
"\xC1\x05\x2F\x2F\x00\xF6\xD1", // Mifare Plus SE
"\xC1\x05\x2F\x2F\x01\xF6\xD1", // Mifare Plus SE
};
typedef NfcCommand (*MfPlusPollerReadHandler)(MfPlusPoller* instance);
const MfPlusData* mf_plus_poller_get_data(MfPlusPoller* instance) {
furi_assert(instance);
return instance->data;
}
bool mf_plus_poller_get_type_from_iso4(const Iso14443_4aData* iso4_data, MfPlusData* mf_plus_data) {
furi_assert(iso4_data);
furi_assert(mf_plus_data);
switch(iso4_data->iso14443_3a_data->sak) {
case 0x08:
if(memcmp(
simple_array_get_data(iso4_data->ats_data.t1_tk),
mf_plus_ats_t1_tk_values[0],
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
// Mifare Plus S 2K SL1
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize2K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus S 2K SL1");
return true;
} else if(
memcmp(
simple_array_get_data(iso4_data->ats_data.t1_tk),
mf_plus_ats_t1_tk_values[1],
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
// Mifare Plus X 2K SL1
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize2K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus X 2K SL1");
return true;
} else if(
memcmp(
simple_array_get_data(iso4_data->ats_data.t1_tk),
mf_plus_ats_t1_tk_values[2],
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0 ||
memcmp(
simple_array_get_data(iso4_data->ats_data.t1_tk),
mf_plus_ats_t1_tk_values[3],
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
// Mifare Plus SE 1K SL1
mf_plus_data->type = MfPlusTypeSE;
mf_plus_data->size = MfPlusSize1K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus SE 1K SL1");
return true;
} else {
FURI_LOG_D(TAG, "Sak 08 but no known Mifare Plus type");
return false;
}
case 0x18:
if(memcmp(
simple_array_get_data(iso4_data->ats_data.t1_tk),
mf_plus_ats_t1_tk_values[0],
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
// Mifare Plus S 4K SL1
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize4K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus S 4K SL1");
return true;
} else if(
memcmp(
simple_array_get_data(iso4_data->ats_data.t1_tk),
mf_plus_ats_t1_tk_values[1],
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
// Mifare Plus X 4K SL1
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize4K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus X 4K SL1");
return true;
} else {
FURI_LOG_D(TAG, "Sak 18 but no known Mifare Plus type");
return false;
}
case 0x20:
if(memcmp(
iso4_data->ats_data.t1_tk,
mf_plus_ats_t1_tk_values[0],
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
// Mifare Plus S 2/4K SL3
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->security_level = MfPlusSecurityLevel3;
if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) {
// Mifare Plus S 2K SL3
mf_plus_data->size = MfPlusSize2K;
FURI_LOG_D(TAG, "Mifare Plus S 2K SL3");
} else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) {
// Mifare Plus S 4K SL3
mf_plus_data->size = MfPlusSize4K;
FURI_LOG_D(TAG, "Mifare Plus S 4K SL3");
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (S)");
return false;
}
return true;
} else if(
memcmp(
iso4_data->ats_data.t1_tk,
mf_plus_ats_t1_tk_values[1],
simple_array_get_count(iso4_data->ats_data.t1_tk)) == 0) {
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->security_level = MfPlusSecurityLevel3;
if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) {
mf_plus_data->size = MfPlusSize2K;
FURI_LOG_D(TAG, "Mifare Plus X 2K SL3");
} else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) {
mf_plus_data->size = MfPlusSize4K;
FURI_LOG_D(TAG, "Mifare Plus X 4K SL3");
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (X)");
return false;
}
return true;
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type");
return false;
}
}
FURI_LOG_D(TAG, "No known Mifare Plus type");
return false;
}
static bool mf_plus_poller_detect_type(MfPlusPoller* instance) {
furi_assert(instance);
bool detected = false;
const Iso14443_4aData* iso14443_4a_data =
iso14443_4a_poller_get_data(instance->iso14443_4a_poller);
const MfPlusError error = mf_plus_poller_read_version(instance, &instance->data->version);
if(error == MfPlusErrorNone) {
FURI_LOG_D(TAG, "Read version success: %d", error);
if(instance->data->version.hw_major == 0x02 || instance->data->version.hw_major == 0x82) {
detected = true;
if(iso14443_4a_data->iso14443_3a_data->sak == 0x10) {
// Mifare Plus 2K SL2
instance->data->type = MfPlusTypePlus;
instance->data->size = MfPlusSize2K;
instance->data->security_level = MfPlusSecurityLevel2;
} else if(iso14443_4a_data->iso14443_3a_data->sak == 0x11) {
// Mifare Plus 4K SL3
instance->data->type = MfPlusTypePlus;
instance->data->size = MfPlusSize4K;
instance->data->security_level = MfPlusSecurityLevel3;
} else {
// Mifare Plus EV1/EV2
// Revision
switch(instance->data->version.hw_major) {
case 0x11:
instance->data->type = MfPlusTypeEV1;
break;
case 0x22:
instance->data->type = MfPlusTypeEV2;
break;
default:
instance->data->type = MfPlusTypeUnknown;
break;
}
// Storage size
switch(instance->data->version.hw_storage) {
case 0x16:
instance->data->size = MfPlusSize2K;
break;
case 0x18:
instance->data->size = MfPlusSize4K;
break;
default:
instance->data->size = MfPlusSizeUnknown;
break;
}
// Security level
if(iso14443_4a_data->iso14443_3a_data->sak == 0x20) {
// Mifare Plus EV1/2 SL3
instance->data->security_level = MfPlusSecurityLevel3;
} else {
// Mifare Plus EV1/2 SL1
instance->data->security_level = MfPlusSecurityLevel1;
}
}
}
} else {
FURI_LOG_D(TAG, "Read version error: %d", error);
detected = mf_plus_poller_get_type_from_iso4(iso14443_4a_data, instance->data);
}
return detected;
}
MfPlusPoller* mf_plus_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) {
furi_assert(iso14443_4a_poller);
MfPlusPoller* instance = malloc(sizeof(MfPlusPoller));
furi_assert(instance);
instance->iso14443_4a_poller = iso14443_4a_poller;
instance->data = mf_plus_alloc();
instance->tx_buffer = bit_buffer_alloc(MF_PLUS_BUF_SIZE);
instance->rx_buffer = bit_buffer_alloc(MF_PLUS_BUF_SIZE);
instance->input_buffer = bit_buffer_alloc(MF_PLUS_BUF_SIZE);
instance->result_buffer = bit_buffer_alloc(MF_PLUS_RESULT_BUF_SIZE);
instance->general_event.protocol = NfcProtocolMfPlus;
instance->general_event.event_data = &instance->mfp_event;
instance->general_event.instance = instance;
instance->mfp_event.data = &instance->mfp_event_data;
return instance;
}
static NfcCommand mf_plus_poller_handler_idle(MfPlusPoller* instance) {
furi_assert(instance);
bit_buffer_reset(instance->input_buffer);
bit_buffer_reset(instance->result_buffer);
bit_buffer_reset(instance->tx_buffer);
bit_buffer_reset(instance->rx_buffer);
iso14443_4a_copy(
instance->data->iso14443_4a_data,
iso14443_4a_poller_get_data(instance->iso14443_4a_poller));
instance->state = MfPlusPollerStateReadVersion;
return NfcCommandContinue;
}
static NfcCommand mf_plus_poller_handler_read_version(MfPlusPoller* instance) {
bool success = mf_plus_poller_detect_type(instance);
if(success) {
instance->state = MfPlusPollerStateReadSuccess;
} else {
instance->state = MfPlusPollerStateReadFailed;
}
return NfcCommandContinue;
}
static NfcCommand mf_plus_poller_handler_read_failed(MfPlusPoller* instance) {
furi_assert(instance);
FURI_LOG_D(TAG, "Read failed");
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
instance->mfp_event.data->error = instance->error;
NfcCommand command = instance->callback(instance->general_event, instance->context);
instance->state = MfPlusPollerStateIdle;
return command;
}
static NfcCommand mf_plus_poller_handler_read_success(MfPlusPoller* instance) {
furi_assert(instance);
FURI_LOG_D(TAG, "Read success");
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
instance->mfp_event.type = MfPlusPollerEventTypeReadSuccess;
NfcCommand command = instance->callback(instance->general_event, instance->context);
return command;
}
static const MfPlusPollerReadHandler mf_plus_poller_read_handler[MfPlusPollerStateNum] = {
[MfPlusPollerStateIdle] = mf_plus_poller_handler_idle,
[MfPlusPollerStateReadVersion] = mf_plus_poller_handler_read_version,
[MfPlusPollerStateReadFailed] = mf_plus_poller_handler_read_failed,
[MfPlusPollerStateReadSuccess] = mf_plus_poller_handler_read_success,
};
static void mf_plus_poller_set_callback(
MfPlusPoller* instance,
NfcGenericCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
static NfcCommand mf_plus_poller_run(NfcGenericEvent event, void* context) {
furi_assert(event.protocol = NfcProtocolIso14443_4a);
MfPlusPoller* instance = context;
furi_assert(instance);
const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
furi_assert(iso14443_4a_event);
NfcCommand command = NfcCommandContinue;
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
command = mf_plus_poller_read_handler[instance->state](instance);
} else if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeError) {
instance->mfp_event.type = MfPlusPollerEventTypeReadFailed;
command = instance->callback(instance->general_event, instance->context);
}
return command;
}
void mf_plus_poller_free(MfPlusPoller* instance) {
furi_assert(instance);
furi_assert(instance->data);
bit_buffer_free(instance->tx_buffer);
bit_buffer_free(instance->rx_buffer);
bit_buffer_free(instance->input_buffer);
bit_buffer_free(instance->result_buffer);
mf_plus_free(instance->data);
free(instance);
}
static bool mf_plus_poller_detect(NfcGenericEvent event, void* context) {
furi_assert(event.protocol = NfcProtocolIso14443_4a);
MfPlusPoller* instance = context;
furi_assert(instance);
Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
furi_assert(iso14443_4a_event);
bool detected = false;
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
detected = mf_plus_poller_detect_type(instance);
}
return detected;
}
const NfcPollerBase mf_plus_poller = {
.alloc = (NfcPollerAlloc)mf_plus_poller_alloc,
.free = (NfcPollerFree)mf_plus_poller_free,
.set_callback = (NfcPollerSetCallback)mf_plus_poller_set_callback,
.run = (NfcPollerRun)mf_plus_poller_run,
.detect = (NfcPollerDetect)mf_plus_poller_detect,
.get_data = (NfcPollerGetData)mf_plus_poller_get_data,
};

View file

@ -0,0 +1,55 @@
#pragma once
#include "mf_plus.h"
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief MIFARE Plus poller opaque type definition.
*/
typedef struct MfPlusPoller MfPlusPoller;
/**
* @brief Enumeration of possible MfPlus poller event types.
*/
typedef enum {
MfPlusPollerEventTypeReadSuccess, /**< Card was read successfully. */
MfPlusPollerEventTypeReadFailed, /**< Poller failed to read the card. */
} MfPlusPollerEventType;
/**
* @brief MIFARE Plus poller event data.
*/
typedef union {
MfPlusError error; /**< Error code indicating card reading fail reason. */
} MfPlusPollerEventData;
/**
* @brief MIFARE Plus poller event structure.
*
* Upon emission of an event, an instance of this struct will be passed to the callback.
*/
typedef struct {
MfPlusPollerEventType type; /**< Type of emitted event. */
MfPlusPollerEventData* data; /**< Pointer to event specific data. */
} MfPlusPollerEvent;
/**
* @brief Read MfPlus card version.
*
* Must ONLY be used inside the callback function.
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[out] data pointer to the MfPlusVersion structure to be filled with version data.
* @return MfPlusErrorNone on success, an error code on failure.
*/
MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* data);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,5 @@
#pragma once
#include <nfc/protocols/nfc_poller_base.h>
extern const NfcPollerBase mf_plus_poller;

View file

@ -0,0 +1,73 @@
#include "mf_plus_poller_i.h"
#include <furi.h>
#include "mf_plus_i.h"
#define TAG "MfPlusPoller"
MfPlusError mf_plus_process_error(Iso14443_4aError error) {
switch(error) {
case Iso14443_4aErrorNone:
return MfPlusErrorNone;
case Iso14443_4aErrorNotPresent:
return MfPlusErrorNotPresent;
case Iso14443_4aErrorTimeout:
return MfPlusErrorTimeout;
default:
return MfPlusErrorProtocol;
}
}
MfPlusError
mf_plus_send_chunk(MfPlusPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer) {
furi_assert(instance);
furi_assert(instance->iso14443_4a_poller);
furi_assert(instance->tx_buffer);
furi_assert(instance->rx_buffer);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
MfPlusError error = MfPlusErrorNone;
do {
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
instance->iso14443_4a_poller, tx_buffer, instance->rx_buffer);
if(iso14443_4a_error != Iso14443_4aErrorNone) {
error = mf_plus_process_error(iso14443_4a_error);
break;
}
bit_buffer_reset(instance->tx_buffer);
if(bit_buffer_get_size_bytes(instance->rx_buffer) > sizeof(uint8_t)) {
bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
} else {
bit_buffer_reset(rx_buffer);
}
} while(false);
return error;
}
MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* data) {
furi_assert(instance);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_PLUS_CMD_GET_VERSION);
MfPlusError error;
do {
error = mf_plus_send_chunk(instance, instance->input_buffer, instance->result_buffer);
if(error != MfPlusErrorNone) break;
if(!mf_plus_version_parse(data, instance->result_buffer)) {
error = MfPlusErrorProtocol;
}
} while(false);
return error;
}

View file

@ -0,0 +1,54 @@
#pragma once
#include "mf_plus_poller.h"
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MF_PLUS_FWT_FC (60000)
typedef enum {
MfPlusCardStateDetected,
MfPlusCardStateLost,
} MfPlusCardState;
typedef enum {
MfPlusPollerStateIdle,
MfPlusPollerStateReadVersion,
MfPlusPollerStateReadFailed,
MfPlusPollerStateReadSuccess,
MfPlusPollerStateNum,
} MfPlusPollerState;
struct MfPlusPoller {
Iso14443_4aPoller* iso14443_4a_poller;
MfPlusData* data;
MfPlusPollerState state;
BitBuffer* tx_buffer;
BitBuffer* rx_buffer;
BitBuffer* input_buffer;
BitBuffer* result_buffer;
MfPlusError error;
NfcGenericEvent general_event;
MfPlusPollerEvent mfp_event;
MfPlusPollerEventData mfp_event_data;
NfcGenericCallback callback;
void* context;
};
MfPlusError mf_plus_process_error(Iso14443_4aError error);
MfPlusPoller* mf_plus_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller);
void mf_plus_poller_free(MfPlusPoller* instance);
#ifdef __cplusplus
}
#endif

View file

@ -20,6 +20,7 @@
#include <nfc/protocols/felica/felica.h>
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
#include <nfc/protocols/mf_classic/mf_classic.h>
#include <nfc/protocols/mf_plus/mf_plus.h>
#include <nfc/protocols/mf_desfire/mf_desfire.h>
#include <nfc/protocols/emv/emv.h>
#include <nfc/protocols/slix/slix_device_defs.h>
@ -40,6 +41,7 @@ const NfcDeviceBase* nfc_devices[NfcProtocolNum] = {
[NfcProtocolFelica] = &nfc_device_felica,
[NfcProtocolMfUltralight] = &nfc_device_mf_ultralight,
[NfcProtocolMfClassic] = &nfc_device_mf_classic,
[NfcProtocolMfPlus] = &nfc_device_mf_plus,
[NfcProtocolMfDesfire] = &nfc_device_mf_desfire,
[NfcProtocolSlix] = &nfc_device_slix,
[NfcProtocolSt25tb] = &nfc_device_st25tb,

View file

@ -8,6 +8,7 @@
#include <nfc/protocols/felica/felica_poller_defs.h>
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h>
#include <nfc/protocols/mf_classic/mf_classic_poller_defs.h>
#include <nfc/protocols/mf_plus/mf_plus_poller_defs.h>
#include <nfc/protocols/mf_desfire/mf_desfire_poller_defs.h>
#include <nfc/protocols/emv/emv_poller_defs.h>
#include <nfc/protocols/slix/slix_poller_defs.h>
@ -22,6 +23,7 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = {
[NfcProtocolFelica] = &nfc_poller_felica,
[NfcProtocolMfUltralight] = &mf_ultralight_poller,
[NfcProtocolMfClassic] = &mf_classic_poller,
[NfcProtocolMfPlus] = &mf_plus_poller,
[NfcProtocolMfDesfire] = &mf_desfire_poller,
[NfcProtocolSlix] = &nfc_poller_slix,
[NfcProtocolSt25tb] = &nfc_poller_st25tb,

View file

@ -63,6 +63,7 @@ static const NfcProtocol nfc_protocol_iso14443_3b_children_protocol[] = {
/** List of ISO14443-4A child protocols. */
static const NfcProtocol nfc_protocol_iso14443_4a_children_protocol[] = {
NfcProtocolMfDesfire,
NfcProtocolMfPlus,
NfcProtocolEmv,
};
@ -131,6 +132,12 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = {
.children_num = 0,
.children_protocol = NULL,
},
[NfcProtocolMfPlus] =
{
.parent_protocol = NfcProtocolIso14443_4a,
.children_num = 0,
.children_protocol = NULL,
},
[NfcProtocolMfDesfire] =
{
.parent_protocol = NfcProtocolIso14443_4a,

View file

@ -184,6 +184,7 @@ typedef enum {
NfcProtocolFelica,
NfcProtocolMfUltralight,
NfcProtocolMfClassic,
NfcProtocolMfPlus,
NfcProtocolMfDesfire,
NfcProtocolSlix,
NfcProtocolSt25tb,

View file

@ -156,6 +156,8 @@ Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller.h,,
Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h,,
Header,+,lib/nfc/protocols/mf_desfire/mf_desfire.h,,
Header,+,lib/nfc/protocols/mf_desfire/mf_desfire_poller.h,,
Header,+,lib/nfc/protocols/mf_plus/mf_plus.h,,
Header,+,lib/nfc/protocols/mf_plus/mf_plus_poller.h,,
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight.h,,
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h,,
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h,,
@ -2563,6 +2565,19 @@ Function,+,mf_desfire_save,_Bool,"const MfDesfireData*, FlipperFormat*"
Function,+,mf_desfire_send_chunks,MfDesfireError,"MfDesfirePoller*, const BitBuffer*, BitBuffer*"
Function,+,mf_desfire_set_uid,_Bool,"MfDesfireData*, const uint8_t*, size_t"
Function,+,mf_desfire_verify,_Bool,"MfDesfireData*, const FuriString*"
Function,+,mf_plus_alloc,MfPlusData*,
Function,+,mf_plus_copy,void,"MfPlusData*, const MfPlusData*"
Function,+,mf_plus_free,void,MfPlusData*
Function,+,mf_plus_get_base_data,Iso14443_4aData*,const MfPlusData*
Function,+,mf_plus_get_device_name,const char*,"const MfPlusData*, NfcDeviceNameType"
Function,+,mf_plus_get_uid,const uint8_t*,"const MfPlusData*, size_t*"
Function,+,mf_plus_is_equal,_Bool,"const MfPlusData*, const MfPlusData*"
Function,+,mf_plus_load,_Bool,"MfPlusData*, FlipperFormat*, uint32_t"
Function,+,mf_plus_poller_read_version,MfPlusError,"MfPlusPoller*, MfPlusVersion*"
Function,+,mf_plus_reset,void,MfPlusData*
Function,+,mf_plus_save,_Bool,"const MfPlusData*, FlipperFormat*"
Function,+,mf_plus_set_uid,_Bool,"MfPlusData*, const uint8_t*, size_t"
Function,+,mf_plus_verify,_Bool,"MfPlusData*, const FuriString*"
Function,+,mf_ultralight_alloc,MfUltralightData*,
Function,+,mf_ultralight_copy,void,"MfUltralightData*, const MfUltralightData*"
Function,+,mf_ultralight_detect_protocol,_Bool,const Iso14443_3aData*
@ -3905,6 +3920,7 @@ Variable,-,nfc_device_emv,const NfcDeviceBase,
Variable,-,nfc_device_felica,const NfcDeviceBase,
Variable,-,nfc_device_mf_classic,const NfcDeviceBase,
Variable,-,nfc_device_mf_desfire,const NfcDeviceBase,
Variable,-,nfc_device_mf_plus,const NfcDeviceBase,
Variable,-,nfc_device_mf_ultralight,const NfcDeviceBase,
Variable,-,nfc_device_st25tb,const NfcDeviceBase,
Variable,+,sequence_audiovisual_alert,const NotificationSequence,

1 entry status name type params
156 Header + lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h
157 Header + lib/nfc/protocols/mf_desfire/mf_desfire.h
158 Header + lib/nfc/protocols/mf_desfire/mf_desfire_poller.h
159 Header + lib/nfc/protocols/mf_plus/mf_plus.h
160 Header + lib/nfc/protocols/mf_plus/mf_plus_poller.h
161 Header + lib/nfc/protocols/mf_ultralight/mf_ultralight.h
162 Header + lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h
163 Header + lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h
2565 Function + mf_desfire_send_chunks MfDesfireError MfDesfirePoller*, const BitBuffer*, BitBuffer*
2566 Function + mf_desfire_set_uid _Bool MfDesfireData*, const uint8_t*, size_t
2567 Function + mf_desfire_verify _Bool MfDesfireData*, const FuriString*
2568 Function + mf_plus_alloc MfPlusData*
2569 Function + mf_plus_copy void MfPlusData*, const MfPlusData*
2570 Function + mf_plus_free void MfPlusData*
2571 Function + mf_plus_get_base_data Iso14443_4aData* const MfPlusData*
2572 Function + mf_plus_get_device_name const char* const MfPlusData*, NfcDeviceNameType
2573 Function + mf_plus_get_uid const uint8_t* const MfPlusData*, size_t*
2574 Function + mf_plus_is_equal _Bool const MfPlusData*, const MfPlusData*
2575 Function + mf_plus_load _Bool MfPlusData*, FlipperFormat*, uint32_t
2576 Function + mf_plus_poller_read_version MfPlusError MfPlusPoller*, MfPlusVersion*
2577 Function + mf_plus_reset void MfPlusData*
2578 Function + mf_plus_save _Bool const MfPlusData*, FlipperFormat*
2579 Function + mf_plus_set_uid _Bool MfPlusData*, const uint8_t*, size_t
2580 Function + mf_plus_verify _Bool MfPlusData*, const FuriString*
2581 Function + mf_ultralight_alloc MfUltralightData*
2582 Function + mf_ultralight_copy void MfUltralightData*, const MfUltralightData*
2583 Function + mf_ultralight_detect_protocol _Bool const Iso14443_3aData*
3920 Variable - nfc_device_felica const NfcDeviceBase
3921 Variable - nfc_device_mf_classic const NfcDeviceBase
3922 Variable - nfc_device_mf_desfire const NfcDeviceBase
3923 Variable - nfc_device_mf_plus const NfcDeviceBase
3924 Variable - nfc_device_mf_ultralight const NfcDeviceBase
3925 Variable - nfc_device_st25tb const NfcDeviceBase
3926 Variable + sequence_audiovisual_alert const NotificationSequence