Skip to content

Commit

Permalink
Added naming for DESFire cards + fix MF3ICD40 cards unable to be read (
Browse files Browse the repository at this point in the history
…#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>
  • Loading branch information
Demae and skotopes authored Feb 13, 2025
1 parent 59fe896 commit 429c0dd
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 5 deletions.
122 changes: 118 additions & 4 deletions lib/nfc/protocols/mf_desfire/mf_desfire.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,46 @@

#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 = {
.protocol_name = MF_DESFIRE_PROTOCOL_NAME,
.alloc = (NfcDeviceAlloc)mf_desfire_alloc,
Expand All @@ -26,7 +66,7 @@ MfDesfireData* mf_desfire_alloc(void) {
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->applications = simple_array_alloc(&mf_desfire_application_array_config);

data->device_name = furi_string_alloc();
return data;
}

Expand All @@ -38,6 +78,7 @@ void mf_desfire_free(MfDesfireData* data) {
simple_array_free(data->application_ids);
simple_array_free(data->master_key_versions);
iso14443_4a_free(data->iso14443_4a_data);
furi_string_free(data->device_name);
free(data);
}

Expand Down Expand Up @@ -228,10 +269,83 @@ bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other)
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) {
UNUSED(data);
UNUSED(name_type);
return MF_DESFIRE_PROTOCOL_NAME;
furi_check(data);

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) {
Expand Down
24 changes: 24 additions & 0 deletions lib/nfc/protocols/mf_desfire/mf_desfire.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@ extern "C" {
#define MF_DESFIRE_APP_ID_SIZE (3)
#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 {
uint8_t hw_vendor;
uint8_t hw_type;
Expand Down Expand Up @@ -131,6 +153,7 @@ typedef enum {
MfDesfireErrorProtocol,
MfDesfireErrorTimeout,
MfDesfireErrorAuthentication,
MfDesfireErrorCommandNotSupported,
} MfDesfireError;

typedef struct {
Expand All @@ -141,6 +164,7 @@ typedef struct {
SimpleArray* master_key_versions;
SimpleArray* application_ids;
SimpleArray* applications;
FuriString* device_name;
} MfDesfireData;

extern const NfcDeviceBase nfc_device_mf_desfire;
Expand Down
5 changes: 4 additions & 1 deletion lib/nfc/protocols/mf_desfire/mf_desfire_poller.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* in
FURI_LOG_D(TAG, "Read free memory success");
instance->state = MfDesfirePollerStateReadMasterKeySettings;
} 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;
command = NfcCommandReset;
} else if(instance->error == MfDesfireErrorCommandNotSupported) {
FURI_LOG_D(TAG, "Read free memory is unsupported");
instance->state = MfDesfirePollerStateReadMasterKeySettings;
} else {
FURI_LOG_E(TAG, "Failed to read free memory");
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
Expand Down
2 changes: 2 additions & 0 deletions lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ MfDesfireError mf_desfire_process_status_code(uint8_t status_code) {
return MfDesfireErrorNone;
case MF_DESFIRE_STATUS_AUTHENTICATION_ERROR:
return MfDesfireErrorAuthentication;
case MF_DESFIRE_STATUS_ILLEGAL_COMMAND_CODE:
return MfDesfireErrorCommandNotSupported;
default:
return MfDesfireErrorProtocol;
}
Expand Down

0 comments on commit 429c0dd

Please sign in to comment.