diff --git a/lib/nfc/protocols/mf_plus/mf_plus.c b/lib/nfc/protocols/mf_plus/mf_plus.c index 98b7cd82a..5e3fe1b34 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus.c +++ b/lib/nfc/protocols/mf_plus/mf_plus.c @@ -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; diff --git a/lib/nfc/protocols/mf_plus/mf_plus_i.c b/lib/nfc/protocols/mf_plus/mf_plus_i.c index c248d2568..fa7292abd 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus_i.c +++ b/lib/nfc/protocols/mf_plus/mf_plus_i.c @@ -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); diff --git a/lib/nfc/protocols/mf_plus/mf_plus_i.h b/lib/nfc/protocols/mf_plus/mf_plus_i.h index 8ced4bdd0..bf36b9060 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus_i.h +++ b/lib/nfc/protocols/mf_plus/mf_plus_i.h @@ -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); diff --git a/lib/nfc/protocols/mf_plus/mf_plus_poller.c b/lib/nfc/protocols/mf_plus/mf_plus_poller.c index a218229c5..37a4f723f 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus_poller.c +++ b/lib/nfc/protocols/mf_plus/mf_plus_poller.c @@ -1,4 +1,5 @@ #include "mf_plus_poller_i.h" +#include "mf_plus_i.h" #include @@ -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; diff --git a/lib/nfc/protocols/mf_plus/mf_plus_poller_i.c b/lib/nfc/protocols/mf_plus/mf_plus_poller_i.c index 1a4298b67..2a615460e 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus_poller_i.c +++ b/lib/nfc/protocols/mf_plus/mf_plus_poller_i.c @@ -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; diff --git a/lib/nfc/protocols/mf_plus/mf_plus_poller_i.h b/lib/nfc/protocols/mf_plus/mf_plus_poller_i.h index 79f46b8d8..c7b547a84 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus_poller_i.h +++ b/lib/nfc/protocols/mf_plus/mf_plus_poller_i.h @@ -18,6 +18,8 @@ typedef enum { typedef enum { MfPlusPollerStateIdle, MfPlusPollerStateReadVersion, + MfPlusPollerStateParseVersion, + MfPlusPollerStateParseIso4, MfPlusPollerStateReadFailed, MfPlusPollerStateReadSuccess,