Fixes from code review

This commit is contained in:
Astra 2024-05-20 19:08:54 +09:00
parent 988b9cf155
commit 54f63e06ec
6 changed files with 258 additions and 207 deletions

View file

@ -70,6 +70,7 @@ void mf_plus_reset(MfPlusData* data) {
iso14443_4a_reset(data->iso14443_4a_data);
memset(&data->version, 0, sizeof(data->version));
furi_string_reset(data->device_name);
data->type = MfPlusTypeUnknown;
data->security_level = MfPlusSecurityLevelUnknown;
data->size = MfPlusSizeUnknown;

View file

@ -8,6 +8,202 @@
#define MF_PLUS_FFF_CARD_TYPE_KEY "Card Type"
#define MF_PLUS_FFF_MEMORY_SIZE_KEY "Memory Size"
#define TAG "MfPlus"
const uint8_t mf_plus_ats_t1_tk_values[][7] = {
{0xC1, 0x05, 0x2F, 0x2F, 0x00, 0x35, 0xC7}, // Mifare Plus S
{0xC1, 0x05, 0x2F, 0x2F, 0x01, 0xBC, 0xD6}, // Mifare Plus X
{0xC1, 0x05, 0x2F, 0x2F, 0x00, 0xF6, 0xD1}, // Mifare Plus SE
{0xC1, 0x05, 0x2F, 0x2F, 0x01, 0xF6, 0xD1}, // Mifare Plus SE
};
bool mf_plus_get_type_from_version(
const Iso14443_4aData* iso14443_4a_data,
MfPlusData* mf_plus_data) {
furi_assert(iso14443_4a_data);
furi_assert(mf_plus_data);
bool detected = false;
if(mf_plus_data->version.hw_major == 0x02 || mf_plus_data->version.hw_major == 0x82) {
detected = true;
if(iso14443_4a_data->iso14443_3a_data->sak == 0x10) {
// Mifare Plus 2K SL2
mf_plus_data->type = MfPlusTypePlus;
mf_plus_data->size = MfPlusSize2K;
mf_plus_data->security_level = MfPlusSecurityLevel2;
} else if(iso14443_4a_data->iso14443_3a_data->sak == 0x11) {
// Mifare Plus 4K SL3
mf_plus_data->type = MfPlusTypePlus;
mf_plus_data->size = MfPlusSize4K;
mf_plus_data->security_level = MfPlusSecurityLevel3;
} else {
// Mifare Plus EV1/EV2
// Revision
switch(mf_plus_data->version.hw_major) {
case 0x11:
mf_plus_data->type = MfPlusTypeEV1;
break;
case 0x22:
mf_plus_data->type = MfPlusTypeEV2;
break;
default:
mf_plus_data->type = MfPlusTypeUnknown;
break;
}
// Storage size
switch(mf_plus_data->version.hw_storage) {
case 0x16:
mf_plus_data->size = MfPlusSize2K;
break;
case 0x18:
mf_plus_data->size = MfPlusSize4K;
break;
default:
mf_plus_data->size = MfPlusSizeUnknown;
break;
}
// Security level
if(iso14443_4a_data->iso14443_3a_data->sak == 0x20) {
// Mifare Plus EV1/2 SL3
mf_plus_data->security_level = MfPlusSecurityLevel3;
} else {
// Mifare Plus EV1/2 SL1
mf_plus_data->security_level = MfPlusSecurityLevel1;
}
}
}
return detected;
}
bool mf_plus_get_type_from_iso4(const Iso14443_4aData* iso4_data, MfPlusData* mf_plus_data) {
furi_assert(iso4_data);
furi_assert(mf_plus_data);
switch(iso4_data->iso14443_3a_data->sak) {
case 0x08:
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
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize2K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus S 2K SL1");
return true;
} 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
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize2K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus X 2K SL1");
return true;
} else if(
memcmp(
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
mf_plus_data->type = MfPlusTypeSE;
mf_plus_data->size = MfPlusSize1K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus SE 1K SL1");
return true;
} else {
FURI_LOG_D(TAG, "Sak 08 but no known Mifare Plus type");
return false;
}
case 0x18:
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
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize4K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus S 4K SL1");
return true;
} 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
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize4K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus X 4K SL1");
return true;
} else {
FURI_LOG_D(TAG, "Sak 18 but no known Mifare Plus type");
return false;
}
case 0x20:
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
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->security_level = MfPlusSecurityLevel3;
if(iso4_data->iso14443_3a_data->atqa[1] & 0x04) {
// Mifare Plus S 2K SL3
mf_plus_data->size = MfPlusSize2K;
FURI_LOG_D(TAG, "Mifare Plus S 2K SL3");
} else if(iso4_data->iso14443_3a_data->atqa[1] & 0x02) {
// Mifare Plus S 4K SL3
mf_plus_data->size = MfPlusSize4K;
FURI_LOG_D(TAG, "Mifare Plus S 4K SL3");
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (S)");
return false;
}
return true;
} 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->security_level = MfPlusSecurityLevel3;
// if atqa is 0xXX 0xX4 (other digits are not important)
if(iso4_data->iso14443_3a_data->atqa[1] & 0x04) {
mf_plus_data->size = MfPlusSize2K;
FURI_LOG_D(TAG, "Mifare Plus X 2K SL3");
} else if(iso4_data->iso14443_3a_data->atqa[1] & 0x02) {
mf_plus_data->size = MfPlusSize4K;
FURI_LOG_D(TAG, "Mifare Plus X 4K SL3");
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (X)");
return false;
}
return true;
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type");
return false;
}
}
FURI_LOG_D(TAG, "No known Mifare Plus type");
return false;
}
bool mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf) {
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion);

View file

@ -4,6 +4,12 @@
#define MF_PLUS_FFF_PICC_PREFIX "PICC"
bool mf_plus_get_type_from_version(
const Iso14443_4aData* iso14443_4a_data,
MfPlusData* mf_plus_data);
bool mf_plus_get_type_from_iso4(const Iso14443_4aData* iso4_data, MfPlusData* mf_plus_data);
bool mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf);
bool mf_plus_security_level_parse(MfPlusSecurityLevel* data, const BitBuffer* buf);

View file

@ -1,4 +1,5 @@
#include "mf_plus_poller_i.h"
#include "mf_plus_i.h"
#include <nfc/protocols/nfc_poller_base.h>
@ -9,13 +10,6 @@
#define MF_PLUS_BUF_SIZE (64U)
#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);
const MfPlusData* mf_plus_poller_get_data(MfPlusPoller* instance) {
@ -24,200 +18,6 @@ const MfPlusData* mf_plus_poller_get_data(MfPlusPoller* instance) {
return instance->data;
}
bool mf_plus_poller_get_type_from_iso4(const Iso14443_4aData* iso4_data, MfPlusData* mf_plus_data) {
furi_assert(iso4_data);
furi_assert(mf_plus_data);
switch(iso4_data->iso14443_3a_data->sak) {
case 0x08:
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
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize2K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus S 2K SL1");
return true;
} 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
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize2K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus X 2K SL1");
return true;
} else if(
memcmp(
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
mf_plus_data->type = MfPlusTypeSE;
mf_plus_data->size = MfPlusSize1K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus SE 1K SL1");
return true;
} else {
FURI_LOG_D(TAG, "Sak 08 but no known Mifare Plus type");
return false;
}
case 0x18:
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
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize4K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus S 4K SL1");
return true;
} 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
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize4K;
mf_plus_data->security_level = MfPlusSecurityLevel1;
FURI_LOG_D(TAG, "Mifare Plus X 4K SL1");
return true;
} else {
FURI_LOG_D(TAG, "Sak 18 but no known Mifare Plus type");
return false;
}
case 0x20:
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
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->security_level = MfPlusSecurityLevel3;
if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) {
// Mifare Plus S 2K SL3
mf_plus_data->size = MfPlusSize2K;
FURI_LOG_D(TAG, "Mifare Plus S 2K SL3");
} else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) {
// Mifare Plus S 4K SL3
mf_plus_data->size = MfPlusSize4K;
FURI_LOG_D(TAG, "Mifare Plus S 4K SL3");
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (S)");
return false;
}
return true;
} 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->security_level = MfPlusSecurityLevel3;
if(iso4_data->iso14443_3a_data->atqa[1] == 0x04) {
mf_plus_data->size = MfPlusSize2K;
FURI_LOG_D(TAG, "Mifare Plus X 2K SL3");
} else if(iso4_data->iso14443_3a_data->atqa[1] == 0x02) {
mf_plus_data->size = MfPlusSize4K;
FURI_LOG_D(TAG, "Mifare Plus X 4K SL3");
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (X)");
return false;
}
return true;
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type");
return false;
}
}
FURI_LOG_D(TAG, "No known Mifare Plus type");
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) {
furi_assert(iso14443_4a_poller);
@ -259,10 +59,40 @@ static NfcCommand mf_plus_poller_handler_idle(MfPlusPoller* instance) {
}
static NfcCommand mf_plus_poller_handler_read_version(MfPlusPoller* instance) {
bool success = mf_plus_poller_detect_type(instance);
if(success) {
MfPlusError error = mf_plus_poller_read_version(instance, &instance->data->version);
if(error == MfPlusErrorNone) {
instance->state = MfPlusPollerStateParseVersion;
} else {
instance->state = MfPlusPollerStateParseIso4;
}
return NfcCommandContinue;
}
static NfcCommand mf_plus_poller_handler_parse_version(MfPlusPoller* instance) {
furi_assert(instance);
MfPlusError error = mf_plus_get_type_from_version(
iso14443_4a_poller_get_data(instance->iso14443_4a_poller), instance->data);
if(error == MfPlusErrorNone) {
instance->state = MfPlusPollerStateReadSuccess;
} else {
instance->error = error;
instance->state = MfPlusPollerStateReadFailed;
}
return NfcCommandContinue;
}
static NfcCommand mf_plus_poller_handler_parse_iso4(MfPlusPoller* instance) {
furi_assert(instance);
MfPlusError error = mf_plus_get_type_from_iso4(
iso14443_4a_poller_get_data(instance->iso14443_4a_poller), instance->data);
if(error == MfPlusErrorNone) {
instance->state = MfPlusPollerStateReadSuccess;
} else {
instance->error = error;
instance->state = MfPlusPollerStateReadFailed;
}
@ -291,6 +121,8 @@ static NfcCommand mf_plus_poller_handler_read_success(MfPlusPoller* instance) {
static const MfPlusPollerReadHandler mf_plus_poller_read_handler[MfPlusPollerStateNum] = {
[MfPlusPollerStateIdle] = mf_plus_poller_handler_idle,
[MfPlusPollerStateReadVersion] = mf_plus_poller_handler_read_version,
[MfPlusPollerStateParseVersion] = mf_plus_poller_handler_parse_version,
[MfPlusPollerStateParseIso4] = mf_plus_poller_handler_parse_iso4,
[MfPlusPollerStateReadFailed] = mf_plus_poller_handler_read_failed,
[MfPlusPollerStateReadSuccess] = mf_plus_poller_handler_read_success,
};
@ -351,7 +183,16 @@ static bool mf_plus_poller_detect(NfcGenericEvent event, void* context) {
bool detected = false;
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
detected = mf_plus_poller_detect_type(instance);
detected = mf_plus_poller_read_version(instance, &instance->data->version);
if(detected) {
detected = mf_plus_get_type_from_version(
iso14443_4a_poller_get_data(instance->iso14443_4a_poller),
instance->data) == MfPlusErrorNone;
} else {
detected = mf_plus_get_type_from_iso4(
iso14443_4a_poller_get_data(instance->iso14443_4a_poller),
instance->data) == MfPlusErrorNone;
}
}
return detected;

View file

@ -19,8 +19,10 @@ MfPlusError mf_plus_process_error(Iso14443_4aError error) {
}
}
MfPlusError
mf_plus_send_chunk(MfPlusPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer) {
MfPlusError mf_plus_poller_send_chunk(
MfPlusPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer) {
furi_assert(instance);
furi_assert(instance->iso14443_4a_poller);
furi_assert(instance->tx_buffer);
@ -43,8 +45,10 @@ MfPlusError
if(bit_buffer_get_size_bytes(instance->rx_buffer) > sizeof(uint8_t)) {
bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
FURI_LOG_D(TAG, "Received %d bytes", bit_buffer_get_size_bytes(rx_buffer));
} else {
bit_buffer_reset(rx_buffer);
FURI_LOG_D(TAG, "Received 0 bytes");
}
} while(false);
@ -60,7 +64,8 @@ MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* d
MfPlusError error;
do {
error = mf_plus_send_chunk(instance, instance->input_buffer, instance->result_buffer);
error =
mf_plus_poller_send_chunk(instance, instance->input_buffer, instance->result_buffer);
if(error != MfPlusErrorNone) break;

View file

@ -18,6 +18,8 @@ typedef enum {
typedef enum {
MfPlusPollerStateIdle,
MfPlusPollerStateReadVersion,
MfPlusPollerStateParseVersion,
MfPlusPollerStateParseIso4,
MfPlusPollerStateReadFailed,
MfPlusPollerStateReadSuccess,