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:
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user