Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[FL-3686] Mifare Classic fixes #3221

Merged
merged 8 commits into from
Nov 26, 2023
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
41 changes: 27 additions & 14 deletions lib/nfc/helpers/nfc_data_generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,23 @@ static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) {
static void
nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) {
data->iso14443_3a_data->uid_len = uid_len;
data->iso14443_3a_data->atqa[0] = 0x44;
data->iso14443_3a_data->atqa[0] = 0x00;
data->iso14443_3a_data->atqa[1] = 0x00;
data->iso14443_3a_data->sak = 0x08;
data->iso14443_3a_data->sak = 0x00;
// Calculate the proper ATQA and SAK
if(uid_len == 7) {
data->iso14443_3a_data->atqa[0] |= 0x40;
}
if(type == MfClassicType1k) {
data->iso14443_3a_data->atqa[0] |= 0x04;
data->iso14443_3a_data->sak = 0x08;
} else if(type == MfClassicType4k) {
data->iso14443_3a_data->atqa[0] |= 0x02;
data->iso14443_3a_data->sak = 0x18;
} else if(type == MfClassicTypeMini) {
data->iso14443_3a_data->atqa[0] |= 0x08;
data->iso14443_3a_data->sak = 0x09;
}
data->type = type;
}

Expand All @@ -343,6 +357,11 @@ static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t
sec_tr->access_bits.data[2] = 0x80;
sec_tr->access_bits.data[3] = 0x69; // Nice

for(int i = 0; i < 6; i++) {
sec_tr->key_a.data[i] = 0xFF;
sec_tr->key_b.data[i] = 0xFF;
}

mf_classic_set_block_read(data, block, &data->block[block]);
mf_classic_set_key_found(
data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF);
Expand Down Expand Up @@ -396,41 +415,35 @@ static void nfc_generate_mf_classic(NfcDevice* nfc_device, uint8_t uid_len, MfCl

uint16_t block_num = mf_classic_get_total_block_num(type);
if(type == MfClassicType4k) {
// Set every block to 0xFF
// Set every block to 0x00
for(uint16_t i = 1; i < block_num; i++) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc_data, i);
} else {
memset(&mfc_data->block[i].data, 0xFF, 16);
memset(&mfc_data->block[i].data, 0x00, 16);
}
mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]);
}
// Set SAK to 18
mfc_data->iso14443_3a_data->sak = 0x18;
} else if(type == MfClassicType1k) {
// Set every block to 0xFF
// Set every block to 0x00
for(uint16_t i = 1; i < block_num; i++) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc_data, i);
} else {
memset(&mfc_data->block[i].data, 0xFF, 16);
memset(&mfc_data->block[i].data, 0x00, 16);
}
mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]);
}
// Set SAK to 08
mfc_data->iso14443_3a_data->sak = 0x08;
} else if(type == MfClassicTypeMini) {
// Set every block to 0xFF
// Set every block to 0x00
for(uint16_t i = 1; i < block_num; i++) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc_data, i);
} else {
memset(&mfc_data->block[i].data, 0xFF, 16);
memset(&mfc_data->block[i].data, 0x00, 16);
}
mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]);
}
// Set SAK to 09
mfc_data->iso14443_3a_data->sak = 0x09;
}

nfc_generate_mf_classic_block_0(
Expand Down
13 changes: 7 additions & 6 deletions lib/nfc/protocols/mf_classic/mf_classic.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ static bool mf_classic_is_allowed_access_sector_trailer(
uint8_t* access_bits_arr = sec_tr->access_bits.data;
uint8_t AC = ((access_bits_arr[1] >> 5) & 0x04) | ((access_bits_arr[2] >> 2) & 0x02) |
((access_bits_arr[2] >> 7) & 0x01);
FURI_LOG_T("NFC", "AC: %02X", AC);

switch(action) {
case MfClassicActionKeyARead: {
Expand All @@ -615,20 +616,20 @@ static bool mf_classic_is_allowed_access_sector_trailer(
case MfClassicActionKeyBWrite: {
return (
(key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x01)) ||
(key_type == MfClassicKeyTypeB && (AC == 0x04 || AC == 0x03)));
(key_type == MfClassicKeyTypeB &&
(AC == 0x00 || AC == 0x04 || AC == 0x03 || AC == 0x01)));
}
case MfClassicActionKeyBRead: {
return (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x02 || AC == 0x01));
return (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x02 || AC == 0x01)) ||
(key_type == MfClassicKeyTypeB && (AC == 0x00 || AC == 0x02 || AC == 0x01));
}
case MfClassicActionACRead: {
return (
(key_type == MfClassicKeyTypeA) ||
(key_type == MfClassicKeyTypeB && !(AC == 0x00 || AC == 0x02 || AC == 0x01)));
return ((key_type == MfClassicKeyTypeA) || (key_type == MfClassicKeyTypeB));
}
case MfClassicActionACWrite: {
return (
(key_type == MfClassicKeyTypeA && (AC == 0x01)) ||
(key_type == MfClassicKeyTypeB && (AC == 0x03 || AC == 0x05)));
(key_type == MfClassicKeyTypeB && (AC == 0x01 || AC == 0x03 || AC == 0x05)));
}
default:
return false;
Expand Down
2 changes: 2 additions & 0 deletions lib/nfc/protocols/mf_classic/mf_classic.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ extern "C" {
#define MF_CLASSIC_CMD_HALT_LSB (0x00)
#define MF_CLASSIC_CMD_ACK (0x0A)
#define MF_CLASSIC_CMD_NACK (0x00)
#define MF_CLASSIC_CMD_NACK_TRANSFER_INVALID (0x04)
#define MF_CLASSIC_CMD_NACK_TRANSFER_CRC_ERROR (0x01)

#define MF_CLASSIC_TOTAL_SECTORS_MAX (40)
#define MF_CLASSIC_TOTAL_BLOCKS_MAX (256)
Expand Down
25 changes: 23 additions & 2 deletions lib/nfc/protocols/mf_classic/mf_classic_listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ static void mf_classic_listener_reset_state(MfClassicListener* instance) {
instance->cmd_in_progress = false;
instance->current_cmd_handler_idx = 0;
instance->transfer_value = 0;
instance->transfer_valid = false;
instance->value_cmd = MfClassicValueCommandInvalid;
}

Expand Down Expand Up @@ -154,7 +155,7 @@ static MfClassicListenerCommand
uint32_t nt_num = nfc_util_bytes2num(instance->auth_context.nt.data, sizeof(MfClassicNt));
uint32_t secret_poller = ar_num ^ crypto1_word(instance->crypto, 0, 0);
if(secret_poller != prng_successor(nt_num, 64)) {
FURI_LOG_D(
FURI_LOG_T(
TAG, "Wrong reader key: %08lX != %08lX", secret_poller, prng_successor(nt_num, 64));
mf_classic_listener_reset_state(instance);
break;
Expand Down Expand Up @@ -272,6 +273,17 @@ static MfClassicListenerCommand mf_classic_listener_write_block_second_part_hand

if(mf_classic_is_sector_trailer(block_num)) {
MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)&block;

// Check if any writing is allowed
if(!mf_classic_is_allowed_access(
instance->data, block_num, key_type, MfClassicActionKeyAWrite) &&
!mf_classic_is_allowed_access(
instance->data, block_num, key_type, MfClassicActionKeyBWrite) &&
!mf_classic_is_allowed_access(
instance->data, block_num, key_type, MfClassicActionACWrite)) {
break;
}

if(mf_classic_is_allowed_access(
instance->data, block_num, key_type, MfClassicActionKeyAWrite)) {
bit_buffer_write_bytes_mid(buff, sec_tr->key_a.data, 0, sizeof(MfClassicKey));
Expand Down Expand Up @@ -338,6 +350,7 @@ static MfClassicListenerCommand
break;
}

instance->transfer_valid = true;
instance->cmd_in_progress = true;
instance->current_cmd_handler_idx++;
command = MfClassicListenerCommandAck;
Expand Down Expand Up @@ -382,6 +395,7 @@ static MfClassicListenerCommand
}

instance->transfer_value += data;
instance->transfer_valid = true;

instance->cmd_in_progress = true;
instance->current_cmd_handler_idx++;
Expand Down Expand Up @@ -411,6 +425,7 @@ static MfClassicListenerCommand
mf_classic_value_to_block(
instance->transfer_value, block_num, &instance->data->block[block_num]);
instance->transfer_value = 0;
instance->transfer_valid = false;

command = MfClassicListenerCommandAck;
} while(false);
Expand Down Expand Up @@ -581,7 +596,13 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) {
if(mfc_command == MfClassicListenerCommandAck) {
mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_ACK);
} else if(mfc_command == MfClassicListenerCommandNack) {
mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_NACK);
// Calculate nack based on the transfer buffer validity
uint8_t nack = MF_CLASSIC_CMD_NACK;
if(!instance->transfer_valid) {
nack += MF_CLASSIC_CMD_NACK_TRANSFER_INVALID;
}

mf_classic_listener_send_short_frame(instance, nack);
} else if(mfc_command == MfClassicListenerCommandSilent) {
command = NfcCommandReset;
} else if(mfc_command == MfClassicListenerCommandSleep) {
Expand Down
1 change: 1 addition & 0 deletions lib/nfc/protocols/mf_classic/mf_classic_listener_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct MfClassicListener {

// Value operation data
int32_t transfer_value;
bool transfer_valid;
MfClassicValueCommand value_cmd;

NfcGenericEvent generic_event;
Expand Down