This commit is contained in:
MX
2025-06-30 19:53:45 +03:00
parent 1382a6af46
commit fa6839d283
55 changed files with 3521 additions and 304 deletions

View File

@@ -15,8 +15,8 @@
const uint8_t mf_plus_ats_t1_tk_values[][MF_PLUS_T1_TK_VALUE_LEN] = {
{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
{0xC1, 0x05, 0x21, 0x30, 0x00, 0xF6, 0xD1}, // Mifare Plus SE
{0xC1, 0x05, 0x21, 0x30, 0x10, 0xF6, 0xD1}, // Mifare Plus SE
};
MfPlusError mf_plus_get_type_from_version(
@@ -27,7 +27,7 @@ MfPlusError mf_plus_get_type_from_version(
MfPlusError error = MfPlusErrorProtocol;
if(mf_plus_data->version.hw_type == 0x02 || mf_plus_data->version.hw_type == 0x82) {
if((mf_plus_data->version.hw_type & 0x0F) == 0x02) {
error = MfPlusErrorNone;
// Mifare Plus EV1/EV2
@@ -85,16 +85,15 @@ MfPlusError
MfPlusError error = MfPlusErrorProtocol;
if(simple_array_get_count(iso4_data->ats_data.t1_tk) != MF_PLUS_T1_TK_VALUE_LEN) {
const size_t historical_bytes_len = simple_array_get_count(iso4_data->ats_data.t1_tk);
if(historical_bytes_len != MF_PLUS_T1_TK_VALUE_LEN) {
return MfPlusErrorProtocol;
}
const uint8_t* historical_bytes = simple_array_cget_data(iso4_data->ats_data.t1_tk);
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) {
if(memcmp(historical_bytes, mf_plus_ats_t1_tk_values[0], historical_bytes_len) == 0) {
// Mifare Plus S 2K SL1
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize2K;
@@ -102,11 +101,7 @@ MfPlusError
FURI_LOG_D(TAG, "Mifare Plus S 2K SL1");
error = MfPlusErrorNone;
} 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) {
} else if(memcmp(historical_bytes, mf_plus_ats_t1_tk_values[1], historical_bytes_len) == 0) {
// Mifare Plus X 2K SL1
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize2K;
@@ -115,14 +110,8 @@ MfPlusError
FURI_LOG_D(TAG, "Mifare Plus X 2K SL1");
error = MfPlusErrorNone;
} 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) {
memcmp(historical_bytes, mf_plus_ats_t1_tk_values[2], historical_bytes_len) == 0 ||
memcmp(historical_bytes, mf_plus_ats_t1_tk_values[3], historical_bytes_len) == 0) {
// Mifare Plus SE 1K SL1
mf_plus_data->type = MfPlusTypeSE;
mf_plus_data->size = MfPlusSize1K;
@@ -154,10 +143,7 @@ MfPlusError
break;
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) {
if(memcmp(historical_bytes, mf_plus_ats_t1_tk_values[0], historical_bytes_len) == 0) {
// Mifare Plus S 4K SL1
mf_plus_data->type = MfPlusTypeS;
mf_plus_data->size = MfPlusSize4K;
@@ -165,11 +151,7 @@ MfPlusError
FURI_LOG_D(TAG, "Mifare Plus S 4K SL1");
error = MfPlusErrorNone;
} 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) {
} else if(memcmp(historical_bytes, mf_plus_ats_t1_tk_values[1], historical_bytes_len) == 0) {
// Mifare Plus X 4K SL1
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->size = MfPlusSize4K;
@@ -183,10 +165,7 @@ MfPlusError
break;
case 0x20:
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) {
if(memcmp(historical_bytes, mf_plus_ats_t1_tk_values[0], historical_bytes_len) == 0) {
// Mifare Plus S 2/4K SL3
FURI_LOG_D(TAG, "Mifare Plus S SL3");
mf_plus_data->type = MfPlusTypeS;
@@ -207,21 +186,20 @@ MfPlusError
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (S)");
}
} 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) {
} else if(memcmp(historical_bytes, mf_plus_ats_t1_tk_values[1], historical_bytes_len) == 0) {
// Mifare Plus X 2/4K SL3
mf_plus_data->type = MfPlusTypeX;
mf_plus_data->security_level = MfPlusSecurityLevel3;
FURI_LOG_D(TAG, "Mifare Plus X SL3");
if((iso4_data->iso14443_3a_data->atqa[0] & 0x0F) == 0x04) {
// Mifare Plus X 2K SL3
mf_plus_data->size = MfPlusSize2K;
FURI_LOG_D(TAG, "Mifare Plus X 2K SL3");
error = MfPlusErrorNone;
} else if((iso4_data->iso14443_3a_data->atqa[0] & 0x0F) == 0x02) {
// Mifare Plus X 4K SL3
mf_plus_data->size = MfPlusSize4K;
FURI_LOG_D(TAG, "Mifare Plus X 4K SL3");
@@ -229,6 +207,16 @@ MfPlusError
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type (X)");
}
} else if(
memcmp(historical_bytes, mf_plus_ats_t1_tk_values[2], historical_bytes_len) == 0 ||
memcmp(historical_bytes, mf_plus_ats_t1_tk_values[3], historical_bytes_len) == 0) {
// Mifare Plus SE 1K SL3
mf_plus_data->type = MfPlusTypeSE;
mf_plus_data->size = MfPlusSize1K;
mf_plus_data->security_level = MfPlusSecurityLevel3;
FURI_LOG_D(TAG, "Mifare Plus SE 1K SL3");
error = MfPlusErrorNone;
} else {
FURI_LOG_D(TAG, "Sak 20 but no known Mifare Plus type");
}
@@ -238,22 +226,12 @@ MfPlusError
}
MfPlusError mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf) {
bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion);
const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion);
if(can_parse) {
bit_buffer_write_bytes(buf, data, sizeof(MfPlusVersion));
} else if(
bit_buffer_get_size_bytes(buf) == 8 &&
bit_buffer_get_byte(buf, 0) == MF_PLUS_STATUS_ADDITIONAL_FRAME) {
// HACK(-nofl): There are supposed to be three parts to the GetVersion command,
// with the second and third parts fetched by sending the AdditionalFrame
// command. I don't know whether the entire MIFARE Plus line uses status as
// the first byte, so let's just assume we only have the first part of
// the response if it's size 8 and starts with the AF status. The second
// part of the response is the same size and status byte, but so far
// we're only reading one response.
can_parse = true;
bit_buffer_write_bytes_mid(buf, data, 1, bit_buffer_get_size_bytes(buf) - 1);
} else {
memset(data, 0, sizeof(MfPlusVersion));
}
return can_parse ? MfPlusErrorNone : MfPlusErrorProtocol;

View File

@@ -2,10 +2,9 @@
#include "mf_plus.h"
#define MF_PLUS_FFF_PICC_PREFIX "PICC"
#include <nfc/helpers/nxp_native_command.h>
#define MF_PLUS_STATUS_OPERATION_OK (0x90)
#define MF_PLUS_STATUS_ADDITIONAL_FRAME (0xAF)
#define MF_PLUS_FFF_PICC_PREFIX "PICC"
MfPlusError mf_plus_get_type_from_version(
const Iso14443_4aData* iso14443_4a_data,

View File

@@ -19,28 +19,36 @@ MfPlusError mf_plus_process_error(Iso14443_4aError error) {
}
}
MfPlusError mf_plus_poller_send_chunk(
MfPlusError mf_plus_process_status_code(uint8_t status_code) {
switch(status_code) {
case NXP_NATIVE_COMMAND_STATUS_OPERATION_OK:
return MfPlusErrorNone;
default:
return MfPlusErrorProtocol;
}
}
MfPlusError mf_plus_poller_send_chunks(
MfPlusPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer) {
furi_assert(instance);
furi_assert(instance->iso14443_4a_poller);
furi_assert(instance->tx_buffer);
furi_assert(instance->rx_buffer);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
instance->iso14443_4a_poller, tx_buffer, instance->rx_buffer);
MfPlusError error = mf_plus_process_error(iso14443_4a_error);
NxpNativeCommandStatus status_code = NXP_NATIVE_COMMAND_STATUS_OPERATION_OK;
Iso14443_4aError iso14443_4a_error = nxp_native_command_iso14443_4a_poller(
instance->iso14443_4a_poller,
&status_code,
tx_buffer,
rx_buffer,
NxpNativeCommandModePlain,
instance->tx_buffer,
instance->rx_buffer);
if(error == MfPlusErrorNone) {
bit_buffer_copy(rx_buffer, instance->rx_buffer);
if(iso14443_4a_error != Iso14443_4aErrorNone) {
return mf_plus_process_error(iso14443_4a_error);
}
bit_buffer_reset(instance->tx_buffer);
return error;
return mf_plus_process_status_code(status_code);
}
MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* data) {
@@ -50,7 +58,7 @@ MfPlusError mf_plus_poller_read_version(MfPlusPoller* instance, MfPlusVersion* d
bit_buffer_append_byte(instance->input_buffer, MF_PLUS_CMD_GET_VERSION);
MfPlusError error =
mf_plus_poller_send_chunk(instance, instance->input_buffer, instance->result_buffer);
mf_plus_poller_send_chunks(instance, instance->input_buffer, instance->result_buffer);
if(error == MfPlusErrorNone) {
error = mf_plus_version_parse(data, instance->result_buffer);
}