1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 20:49:49 +04:00

Mifare Plus detection done

This commit is contained in:
Astra
2024-04-22 21:09:06 +09:00
parent 9042009b0b
commit 83ff6fb8bf
9 changed files with 464 additions and 41 deletions

View File

@@ -34,6 +34,10 @@ static NfcCommand nfc_scene_read_poller_callback_mf_plus(NfcGenericEvent event,
if(mf_plus_event->type == MfPlusPollerEventTypeReadSuccess) { if(mf_plus_event->type == MfPlusPollerEventTypeReadSuccess) {
nfc_device_set_data( nfc_device_set_data(
instance->nfc_device, NfcProtocolMfPlus, nfc_poller_get_data(instance->poller)); 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); view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
return NfcCommandStop; return NfcCommandStop;
} }
@@ -52,7 +56,8 @@ static void nfc_scene_read_success_on_enter_mf_plus(NfcApp* instance) {
FuriString* temp_str = furi_string_alloc(); FuriString* temp_str = furi_string_alloc();
furi_string_cat_printf( furi_string_cat_printf(
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
nfc_render_mf_plus_info(data, NfcProtocolFormatTypeFull, temp_str); furi_string_replace(temp_str, "Mifare", "MIFARE");
nfc_render_mf_plus_info(data, NfcProtocolFormatTypeShort, temp_str);
widget_add_text_scroll_element( widget_add_text_scroll_element(
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));

View File

@@ -1,10 +1,35 @@
#include "mf_plus.h" #include "mf_plus_i.h"
#include <bit_lib/bit_lib.h> #include <bit_lib/bit_lib.h>
#include <furi.h> #include <furi.h>
#define MF_PLUS_PROTOCOL_NAME "Mifare Plus" #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 = { const NfcDeviceBase nfc_device_mf_plus = {
.protocol_name = MF_PLUS_PROTOCOL_NAME, .protocol_name = MF_PLUS_PROTOCOL_NAME,
.alloc = (NfcDeviceAlloc)mf_plus_alloc, .alloc = (NfcDeviceAlloc)mf_plus_alloc,
@@ -23,12 +48,19 @@ const NfcDeviceBase nfc_device_mf_plus = {
MfPlusData* mf_plus_alloc() { MfPlusData* mf_plus_alloc() {
MfPlusData* data = malloc(sizeof(MfPlusData)); MfPlusData* data = malloc(sizeof(MfPlusData));
data->device_name = furi_string_alloc();
data->iso14443_4a_data = iso14443_4a_alloc(); data->iso14443_4a_data = iso14443_4a_alloc();
data->type = MfPlusTypeUnknown;
data->security_level = MfPlusSecurityLevelUnknown;
data->size = MfPlusSizeUnknown;
return data; return data;
} }
void mf_plus_free(MfPlusData* data) { void mf_plus_free(MfPlusData* data) {
furi_check(data); furi_check(data);
furi_string_free(data->device_name);
iso14443_4a_free(data->iso14443_4a_data); iso14443_4a_free(data->iso14443_4a_data);
free(data); free(data);
} }
@@ -36,12 +68,22 @@ void mf_plus_free(MfPlusData* data) {
void mf_plus_reset(MfPlusData* data) { void mf_plus_reset(MfPlusData* data) {
furi_check(data); furi_check(data);
iso14443_4a_reset(data->iso14443_4a_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) { void mf_plus_copy(MfPlusData* data, const MfPlusData* other) {
furi_check(data); furi_check(data);
furi_check(other); furi_check(other);
iso14443_4a_copy(data->iso14443_4a_data, other->iso14443_4a_data); 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) { bool mf_plus_verify(MfPlusData* data, const FuriString* device_type) {
@@ -50,29 +92,51 @@ bool mf_plus_verify(MfPlusData* data, const FuriString* device_type) {
} }
bool mf_plus_load(MfPlusData* data, FlipperFormat* ff, uint32_t version) { bool mf_plus_load(MfPlusData* data, FlipperFormat* ff, uint32_t version) {
// TODO furi_assert(data);
UNUSED(data);
UNUSED(ff); bool success = false;
UNUSED(version);
return true; 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) { bool mf_plus_save(const MfPlusData* data, FlipperFormat* ff) {
// TODO furi_assert(data);
UNUSED(data);
UNUSED(ff); bool success = false;
return true;
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) { bool mf_plus_is_equal(const MfPlusData* data, const MfPlusData* other) {
furi_check(data); furi_assert(data);
furi_check(other); furi_assert(other);
bool equal = false; bool equal = false;
do { do {
if(!iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data)) break; 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; equal = true;
} while(false); } while(false);
@@ -82,11 +146,20 @@ 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 char* mf_plus_get_device_name(const MfPlusData* data, NfcDeviceNameType name_type) {
furi_check(data); furi_check(data);
FuriString* full_name = furi_string_alloc();
const char* name = NULL; const char* name = NULL;
do { do {
if(name_type == NfcDeviceNameTypeFull) { if(name_type == NfcDeviceNameTypeFull) {
name = "Mifare Plus"; 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) { } else if(name_type == NfcDeviceNameTypeShort) {
name = "Mifare Plus"; name = "Mifare Plus";
} else { } else {
@@ -94,6 +167,8 @@ const char* mf_plus_get_device_name(const MfPlusData* data, NfcDeviceNameType na
} }
} while(false); } while(false);
furi_string_free(full_name);
FURI_LOG_D("Mifare Plus", "Name: %s", name);
return name; return name;
} }

View File

@@ -83,8 +83,11 @@ typedef struct {
MfPlusType type; MfPlusType type;
MfPlusSize size; MfPlusSize size;
MfPlusSecurityLevel security_level; MfPlusSecurityLevel security_level;
FuriString* device_name;
} MfPlusData; } MfPlusData;
extern const NfcDeviceBase nfc_device_mf_plus;
MfPlusData* mf_plus_alloc(); MfPlusData* mf_plus_alloc();
void mf_plus_free(MfPlusData* data); void mf_plus_free(MfPlusData* data);

View File

@@ -1,5 +1,13 @@
#include "mf_plus_i.h" #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) { bool mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf) {
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion); const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion);
@@ -9,3 +17,200 @@ bool mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf) {
return can_parse; 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

@@ -2,4 +2,28 @@
#include "mf_plus.h" #include "mf_plus.h"
#define MF_PLUS_FFF_PICC_PREFIX "PICC"
bool mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf); 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

@@ -9,6 +9,13 @@
#define MF_PLUS_BUF_SIZE (64U) #define MF_PLUS_BUF_SIZE (64U)
#define MF_PLUS_RESULT_BUF_SIZE (512U) #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); typedef NfcCommand (*MfPlusPollerReadHandler)(MfPlusPoller* instance);
const MfPlusData* mf_plus_poller_get_data(MfPlusPoller* instance) { const MfPlusData* mf_plus_poller_get_data(MfPlusPoller* instance) {
@@ -23,82 +30,194 @@ bool mf_plus_poller_get_type_from_iso4(const Iso14443_4aData* iso4_data, MfPlusD
switch(iso4_data->iso14443_3a_data->sak) { switch(iso4_data->iso14443_3a_data->sak) {
case 0x08: case 0x08:
if(memcmp(iso4_data->ats_data.t1_tk, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { 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 // Mifare Plus S 2K SL1
mf_plus_data->type = MfPlusTypeS; mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize2K; mf_plus_data->size = MfPlusSize2K;
mf_plus_data->security_level = MfPlusSecurityLevel1; mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus S 2K SL1");
return true; return true;
} else if(memcmp(iso4_data->ats_data.t1_tk, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { } 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 // Mifare Plus X 2K SL1
mf_plus_data->type = MfPlusTypeX; mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize2K; mf_plus_data->size = MfPlusSize2K;
mf_plus_data->security_level = MfPlusSecurityLevel1; mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus X 2K SL1");
return true; return true;
} else if( } else if(
memcmp(iso4_data->ats_data.t1_tk, "\xC1\x05\x2F\x2F\x00\xF6\xD1", 7) == 0 || memcmp(
memcmp(iso4_data->ats_data.t1_tk, "\xC1\x05\x2F\x2F\x01\xF6\xD1", 7) == 0) { 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 // Mifare Plus SE 1K SL1
mf_plus_data->type = MfPlusTypeSE; mf_plus_data->type = MfPlusTypeSE;
mf_plus_data->size = MfPlusSize1K; mf_plus_data->size = MfPlusSize1K;
mf_plus_data->security_level = MfPlusSecurityLevel1; mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus SE 1K SL1");
return true; return true;
} else { } else {
FURI_LOG_D(TAG, "Sak 08 but no known Mifare Plus type");
return false; return false;
} }
case 0x18: case 0x18:
if(memcmp(iso4_data->ats_data.t1_tk, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { 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 // Mifare Plus S 4K SL1
mf_plus_data->type = MfPlusTypeS; mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize4K; mf_plus_data->size = MfPlusSize4K;
mf_plus_data->security_level = MfPlusSecurityLevel1; mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus S 4K SL1");
return true; return true;
} else if(memcmp(iso4_data->ats_data.t1_tk, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { } 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 // Mifare Plus X 4K SL1
mf_plus_data->type = MfPlusTypeX; mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize4K; mf_plus_data->size = MfPlusSize4K;
mf_plus_data->security_level = MfPlusSecurityLevel1; mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus X 4K SL1");
return true; return true;
} else { } else {
FURI_LOG_D(TAG, "Sak 18 but no known Mifare Plus type");
return false; return false;
} }
case 0x20: case 0x20:
if(memcmp(iso4_data->ats_data.t1_tk, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { 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 // Mifare Plus S 2/4K SL3
mf_plus_data->type = MfPlusTypeS; mf_plus_data->type = MfPlusTypeS;
mf_plus_data->security_level = MfPlusSecurityLevel3; mf_plus_data->security_level = MfPlusSecurityLevel3;
if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) { if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) {
// // Mifare Plus S 2K SL3
mf_plus_data->size = MfPlusSize2K; mf_plus_data->size = MfPlusSize2K;
FURI_LOG_D(TAG, "Mifare Plus S 2K SL3");
} else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) { } else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) {
// Mifare Plus S 4K SL3
mf_plus_data->size = MfPlusSize4K; mf_plus_data->size = MfPlusSize4K;
FURI_LOG_D(TAG, "Mifare Plus S 4K SL3");
} else { } else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (S)");
return false; return false;
} }
return true; return true;
} else if(memcmp(iso4_data->ats_data.t1_tk, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { } 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->type = MfPlusTypeX;
mf_plus_data->security_level = MfPlusSecurityLevel3; mf_plus_data->security_level = MfPlusSecurityLevel3;
if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) { if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) {
mf_plus_data->size = MfPlusSize2K; mf_plus_data->size = MfPlusSize2K;
FURI_LOG_D(TAG, "Mifare Plus X 2K SL3");
} else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) { } else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) {
mf_plus_data->size = MfPlusSize4K; mf_plus_data->size = MfPlusSize4K;
FURI_LOG_D(TAG, "Mifare Plus X 4K SL3");
} else { } else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (X)");
return false; return false;
} }
return true; return true;
} else { } else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type");
return false; return false;
} }
} }
FURI_LOG_D(TAG, "No known Mifare Plus type");
return false; 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) { MfPlusPoller* mf_plus_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) {
furi_assert(iso14443_4a_poller); furi_assert(iso14443_4a_poller);
@@ -140,8 +259,8 @@ static NfcCommand mf_plus_poller_handler_idle(MfPlusPoller* instance) {
} }
static NfcCommand mf_plus_poller_handler_read_version(MfPlusPoller* instance) { static NfcCommand mf_plus_poller_handler_read_version(MfPlusPoller* instance) {
instance->error = mf_plus_poller_read_version(instance, &instance->data->version); bool success = mf_plus_poller_detect_type(instance);
if(instance->error == MfPlusErrorNone) { if(success) {
instance->state = MfPlusPollerStateReadSuccess; instance->state = MfPlusPollerStateReadSuccess;
} else { } else {
instance->state = MfPlusPollerStateReadFailed; instance->state = MfPlusPollerStateReadFailed;
@@ -166,7 +285,6 @@ static NfcCommand mf_plus_poller_handler_read_success(MfPlusPoller* instance) {
iso14443_4a_poller_halt(instance->iso14443_4a_poller); iso14443_4a_poller_halt(instance->iso14443_4a_poller);
instance->mfp_event.type = MfPlusPollerEventTypeReadSuccess; instance->mfp_event.type = MfPlusPollerEventTypeReadSuccess;
NfcCommand command = instance->callback(instance->general_event, instance->context); NfcCommand command = instance->callback(instance->general_event, instance->context);
instance->state = MfPlusPollerStateIdle;
return command; return command;
} }
@@ -233,16 +351,7 @@ static bool mf_plus_poller_detect(NfcGenericEvent event, void* context) {
bool detected = false; bool detected = false;
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
MfPlusVersion version = {}; detected = mf_plus_poller_detect_type(instance);
const MfPlusError error = mf_plus_poller_read_version(instance, &version);
if(error == MfPlusErrorNone) {
if(version.hw_major == 0x02 || version.hw_major == 0x82) {
detected = true;
}
} else {
detected = mf_plus_poller_get_type_from_iso4(
iso14443_4a_poller_get_data(instance->iso14443_4a_poller), instance->data);
}
} }
return detected; return detected;

View File

@@ -28,7 +28,6 @@ struct MfPlusPoller {
Iso14443_4aPoller* iso14443_4a_poller; Iso14443_4aPoller* iso14443_4a_poller;
MfPlusData* data; MfPlusData* data;
MfPlusCardState card_state;
MfPlusPollerState state; MfPlusPollerState state;
BitBuffer* tx_buffer; BitBuffer* tx_buffer;

View File

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

View File

@@ -3739,6 +3739,7 @@ Variable,+,message_vibro_off,const NotificationMessage,
Variable,+,message_vibro_on,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage,
Variable,-,nfc_device_mf_classic,const NfcDeviceBase, Variable,-,nfc_device_mf_classic,const NfcDeviceBase,
Variable,-,nfc_device_mf_desfire,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_mf_ultralight,const NfcDeviceBase,
Variable,-,nfc_device_st25tb,const NfcDeviceBase, Variable,-,nfc_device_st25tb,const NfcDeviceBase,
Variable,+,sequence_audiovisual_alert,const NotificationSequence, Variable,+,sequence_audiovisual_alert,const NotificationSequence,
1 entry status name type params
3739 Variable + message_vibro_on const NotificationMessage
3740 Variable - nfc_device_mf_classic const NfcDeviceBase
3741 Variable - nfc_device_mf_desfire const NfcDeviceBase
3742 Variable - nfc_device_mf_plus const NfcDeviceBase
3743 Variable - nfc_device_mf_ultralight const NfcDeviceBase
3744 Variable - nfc_device_st25tb const NfcDeviceBase
3745 Variable + sequence_audiovisual_alert const NotificationSequence