Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading