1
mirror of https://github.com/flipperdevices/flipperzero-firmware.git synced 2025-12-12 04:41:26 +04:00

Added naming for DESFire cards + fix MF3ICD40 cards unable to be read (#4058)

* Fixed MF3ICD40 DESFire cards soft-locking NFC application due to read free memory being an unsupported function, added naming for DESFire cards
* NFC: slightly more granular desfire card type resolution

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Demae
2025-02-13 21:19:53 +10:30
committed by GitHub
parent 59fe896ce8
commit 429c0dd387
4 changed files with 148 additions and 5 deletions

View File

@@ -4,6 +4,46 @@
#define MF_DESFIRE_PROTOCOL_NAME "Mifare DESFire" #define MF_DESFIRE_PROTOCOL_NAME "Mifare DESFire"
#define MF_DESFIRE_HW_MINOR_TYPE (0x00)
#define MF_DESFIRE_HW_MINOR_TYPE_MF3ICD40 (0x02)
#define MF_DESFIRE_HW_MAJOR_TYPE_EV1 (0x01)
#define MF_DESFIRE_HW_MAJOR_TYPE_EV2 (0x12)
#define MF_DESFIRE_HW_MAJOR_TYPE_EV2_XL (0x22)
#define MF_DESFIRE_HW_MAJOR_TYPE_EV3 (0x33)
#define MF_DESFIRE_HW_MAJOR_TYPE_MF3ICD40 (0x00)
#define MF_DESFIRE_STORAGE_SIZE_2K (0x16)
#define MF_DESFIRE_STORAGE_SIZE_4K (0x18)
#define MF_DESFIRE_STORAGE_SIZE_8K (0x1A)
#define MF_DESFIRE_STORAGE_SIZE_16K (0x1C)
#define MF_DESFIRE_STORAGE_SIZE_32K (0x1E)
#define MF_DESFIRE_STORAGE_SIZE_MF3ICD40 (0xFF)
#define MF_DESFIRE_STORAGE_SIZE_UNKNOWN (0xFF)
#define MF_DESFIRE_TEST_TYPE_MF3ICD40(major, minor, storage) \
(((major) == MF_DESFIRE_HW_MAJOR_TYPE_MF3ICD40) && \
((minor) == MF_DESFIRE_HW_MINOR_TYPE_MF3ICD40) && \
((storage) == MF_DESFIRE_STORAGE_SIZE_MF3ICD40))
static const char* mf_desfire_type_strings[] = {
[MfDesfireTypeMF3ICD40] = "(MF3ICD40)",
[MfDesfireTypeEV1] = "EV1",
[MfDesfireTypeEV2] = "EV2",
[MfDesfireTypeEV2XL] = "EV2 XL",
[MfDesfireTypeEV3] = "EV3",
[MfDesfireTypeUnknown] = "UNK",
};
static const char* mf_desfire_size_strings[] = {
[MfDesfireSize2k] = "2K",
[MfDesfireSize4k] = "4K",
[MfDesfireSize8k] = "8K",
[MfDesfireSize16k] = "16K",
[MfDesfireSize32k] = "32K",
[MfDesfireSizeUnknown] = "",
};
const NfcDeviceBase nfc_device_mf_desfire = { const NfcDeviceBase nfc_device_mf_desfire = {
.protocol_name = MF_DESFIRE_PROTOCOL_NAME, .protocol_name = MF_DESFIRE_PROTOCOL_NAME,
.alloc = (NfcDeviceAlloc)mf_desfire_alloc, .alloc = (NfcDeviceAlloc)mf_desfire_alloc,
@@ -26,7 +66,7 @@ MfDesfireData* mf_desfire_alloc(void) {
data->master_key_versions = simple_array_alloc(&mf_desfire_key_version_array_config); data->master_key_versions = simple_array_alloc(&mf_desfire_key_version_array_config);
data->application_ids = simple_array_alloc(&mf_desfire_app_id_array_config); data->application_ids = simple_array_alloc(&mf_desfire_app_id_array_config);
data->applications = simple_array_alloc(&mf_desfire_application_array_config); data->applications = simple_array_alloc(&mf_desfire_application_array_config);
data->device_name = furi_string_alloc();
return data; return data;
} }
@@ -38,6 +78,7 @@ void mf_desfire_free(MfDesfireData* data) {
simple_array_free(data->application_ids); simple_array_free(data->application_ids);
simple_array_free(data->master_key_versions); simple_array_free(data->master_key_versions);
iso14443_4a_free(data->iso14443_4a_data); iso14443_4a_free(data->iso14443_4a_data);
furi_string_free(data->device_name);
free(data); free(data);
} }
@@ -228,10 +269,83 @@ bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other)
simple_array_is_equal(data->applications, other->applications); simple_array_is_equal(data->applications, other->applications);
} }
static MfDesfireType mf_desfire_get_type_from_version(const MfDesfireVersion* const version) {
MfDesfireType type = MfDesfireTypeUnknown;
switch(version->hw_major) {
case MF_DESFIRE_HW_MAJOR_TYPE_EV1:
type = MfDesfireTypeEV1;
break;
case MF_DESFIRE_HW_MAJOR_TYPE_EV2:
type = MfDesfireTypeEV2;
break;
case MF_DESFIRE_HW_MAJOR_TYPE_EV2_XL:
type = MfDesfireTypeEV2XL;
break;
case MF_DESFIRE_HW_MAJOR_TYPE_EV3:
type = MfDesfireTypeEV3;
break;
default:
if(MF_DESFIRE_TEST_TYPE_MF3ICD40(version->hw_major, version->hw_minor, version->hw_storage))
type = MfDesfireTypeMF3ICD40;
break;
}
return type;
}
static MfDesfireSize mf_desfire_get_size_from_version(const MfDesfireVersion* const version) {
MfDesfireSize size = MfDesfireSizeUnknown;
switch(version->hw_storage) {
case MF_DESFIRE_STORAGE_SIZE_2K:
size = MfDesfireSize2k;
break;
case MF_DESFIRE_STORAGE_SIZE_4K:
size = MfDesfireSize4k;
break;
case MF_DESFIRE_STORAGE_SIZE_8K:
size = MfDesfireSize8k;
break;
case MF_DESFIRE_STORAGE_SIZE_16K:
size = MfDesfireSize16k;
break;
case MF_DESFIRE_STORAGE_SIZE_32K:
size = MfDesfireSize32k;
break;
default:
if(MF_DESFIRE_TEST_TYPE_MF3ICD40(version->hw_major, version->hw_minor, version->hw_storage))
size = MfDesfireSize4k;
break;
}
return size;
}
const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcDeviceNameType name_type) { const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcDeviceNameType name_type) {
UNUSED(data); furi_check(data);
UNUSED(name_type);
return MF_DESFIRE_PROTOCOL_NAME; const MfDesfireType type = mf_desfire_get_type_from_version(&data->version);
const MfDesfireSize size = mf_desfire_get_size_from_version(&data->version);
if(type == MfDesfireTypeUnknown) {
furi_string_printf(data->device_name, "Unknown %s", MF_DESFIRE_PROTOCOL_NAME);
} else if(name_type == NfcDeviceNameTypeFull) {
furi_string_printf(
data->device_name,
"%s %s %s",
MF_DESFIRE_PROTOCOL_NAME,
mf_desfire_type_strings[type],
mf_desfire_size_strings[size]);
} else {
furi_string_printf(
data->device_name,
"%s %s",
mf_desfire_type_strings[type],
mf_desfire_size_strings[size]);
}
return furi_string_get_cstr(data->device_name);
} }
const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) { const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) {

View File

@@ -29,6 +29,28 @@ extern "C" {
#define MF_DESFIRE_APP_ID_SIZE (3) #define MF_DESFIRE_APP_ID_SIZE (3)
#define MF_DESFIRE_VALUE_SIZE (4) #define MF_DESFIRE_VALUE_SIZE (4)
typedef enum {
MfDesfireTypeMF3ICD40,
MfDesfireTypeEV1,
MfDesfireTypeEV2,
MfDesfireTypeEV2XL,
MfDesfireTypeEV3,
MfDesfireTypeUnknown,
MfDesfireTypeNum,
} MfDesfireType;
typedef enum {
MfDesfireSize2k,
MfDesfireSize4k,
MfDesfireSize8k,
MfDesfireSize16k,
MfDesfireSize32k,
MfDesfireSizeUnknown,
MfDesfireSizeNum,
} MfDesfireSize;
typedef struct { typedef struct {
uint8_t hw_vendor; uint8_t hw_vendor;
uint8_t hw_type; uint8_t hw_type;
@@ -131,6 +153,7 @@ typedef enum {
MfDesfireErrorProtocol, MfDesfireErrorProtocol,
MfDesfireErrorTimeout, MfDesfireErrorTimeout,
MfDesfireErrorAuthentication, MfDesfireErrorAuthentication,
MfDesfireErrorCommandNotSupported,
} MfDesfireError; } MfDesfireError;
typedef struct { typedef struct {
@@ -141,6 +164,7 @@ typedef struct {
SimpleArray* master_key_versions; SimpleArray* master_key_versions;
SimpleArray* application_ids; SimpleArray* application_ids;
SimpleArray* applications; SimpleArray* applications;
FuriString* device_name;
} MfDesfireData; } MfDesfireData;
extern const NfcDeviceBase nfc_device_mf_desfire; extern const NfcDeviceBase nfc_device_mf_desfire;

View File

@@ -82,9 +82,12 @@ static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* in
FURI_LOG_D(TAG, "Read free memory success"); FURI_LOG_D(TAG, "Read free memory success");
instance->state = MfDesfirePollerStateReadMasterKeySettings; instance->state = MfDesfirePollerStateReadMasterKeySettings;
} else if(instance->error == MfDesfireErrorNotPresent) { } else if(instance->error == MfDesfireErrorNotPresent) {
FURI_LOG_D(TAG, "Read free memoty is unsupported"); FURI_LOG_D(TAG, "Read free memory is not present");
instance->state = MfDesfirePollerStateReadMasterKeySettings; instance->state = MfDesfirePollerStateReadMasterKeySettings;
command = NfcCommandReset; command = NfcCommandReset;
} else if(instance->error == MfDesfireErrorCommandNotSupported) {
FURI_LOG_D(TAG, "Read free memory is unsupported");
instance->state = MfDesfirePollerStateReadMasterKeySettings;
} else { } else {
FURI_LOG_E(TAG, "Failed to read free memory"); FURI_LOG_E(TAG, "Failed to read free memory");
iso14443_4a_poller_halt(instance->iso14443_4a_poller); iso14443_4a_poller_halt(instance->iso14443_4a_poller);

View File

@@ -25,6 +25,8 @@ MfDesfireError mf_desfire_process_status_code(uint8_t status_code) {
return MfDesfireErrorNone; return MfDesfireErrorNone;
case MF_DESFIRE_STATUS_AUTHENTICATION_ERROR: case MF_DESFIRE_STATUS_AUTHENTICATION_ERROR:
return MfDesfireErrorAuthentication; return MfDesfireErrorAuthentication;
case MF_DESFIRE_STATUS_ILLEGAL_COMMAND_CODE:
return MfDesfireErrorCommandNotSupported;
default: default:
return MfDesfireErrorProtocol; return MfDesfireErrorProtocol;
} }