Skip to content

Commit

Permalink
[FL-1396] Mifare Classic read (flipperdevices#1034)
Browse files Browse the repository at this point in the history
* rfal: add new data exchange function
* core: add FURI_BIT to common defines
* furi_hal_nfc: add data exchange with custom patiry bits
* lib: extend nfc common API
* assets: add mf classic dictionary
* lib: introduce mifare classic library
* nfc: add dictionary reader helper
* nfc worker: add worker events, add mifare classic read
* nfc: rework scenes with worker events
* nfc: add read mifare classic GUI
* nfc device: add mifare classic save
* nfc: add dictionary open fail scene
* nfc: mention resources
* stream: fix stream read line
* subghz: rework file read with fixed stream_read_line
* furi_hal_nfc: decrease communication timeout
* nfc: rework keys load from dictionary with file_stream
* nfc: add read mifare classic suggestion
* nfc: fix mifare classic read view
* nfc: fix index size
* nfc: add switch to no dictionary found scene
* nfc: add mifare classic load
* nfc: improve read mifare classic design
* mifare_classic: add proxmark3 mention
* nfc: format sources
* nfc: fix typos, add documentation
  • Loading branch information
gornekich authored Mar 23, 2022
1 parent 46a894b commit eafeefb
Show file tree
Hide file tree
Showing 46 changed files with 3,112 additions and 110 deletions.
1 change: 1 addition & 0 deletions applications/nfc/helpers/nfc_custom_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ enum NfcCustomEvent {
NfcCustomEventWorkerExit,
NfcCustomEventByteInputDone,
NfcCustomEventTextInputDone,
NfcCustomEventDictAttackDone,
};
53 changes: 53 additions & 0 deletions applications/nfc/helpers/nfc_mf_classic_dict.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "nfc_mf_classic_dict.h"

#include <flipper_format/flipper_format.h>
#include <lib/toolbox/args.h>

#define NFC_MF_CLASSIC_DICT_PATH "/ext/nfc/assets/mf_classic_dict.nfc"

#define NFC_MF_CLASSIC_KEY_LEN (13)

bool nfc_mf_classic_dict_check_presence(Storage* storage) {
furi_assert(storage);
return storage_common_stat(storage, NFC_MF_CLASSIC_DICT_PATH, NULL) == FSE_OK;
}

bool nfc_mf_classic_dict_open_file(Stream* stream) {
furi_assert(stream);
return file_stream_open(stream, NFC_MF_CLASSIC_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
}

void nfc_mf_classic_dict_close_file(Stream* stream) {
furi_assert(stream);
file_stream_close(stream);
}

bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key) {
furi_assert(stream);
furi_assert(key);
uint8_t key_byte_tmp = 0;
string_t next_line;
string_init(next_line);
*key = 0;

bool next_key_read = false;
while(!next_key_read) {
if(stream_read_line(stream, next_line)) break;
if(string_get_char(next_line, 0) == '#') continue;
if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
for(uint8_t i = 0; i < 12; i += 2) {
args_char_to_hex(
string_get_char(next_line, i), string_get_char(next_line, i + 1), &key_byte_tmp);
*key |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2);
}
next_key_read = true;
}

string_clear(next_line);
return next_key_read;
}

void nfc_mf_classic_dict_reset(Stream* stream) {
furi_assert(stream);
stream_rewind(stream);
}
15 changes: 15 additions & 0 deletions applications/nfc/helpers/nfc_mf_classic_dict.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <stdbool.h>
#include <storage/storage.h>
#include <lib/toolbox/stream/file_stream.h>

bool nfc_mf_classic_dict_check_presence(Storage* storage);

bool nfc_mf_classic_dict_open_file(Stream* stream);

void nfc_mf_classic_dict_close_file(Stream* stream);

bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key);

void nfc_mf_classic_dict_reset(Stream* stream);
9 changes: 9 additions & 0 deletions applications/nfc/nfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ Nfc* nfc_alloc() {
view_dispatcher_add_view(
nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card));

// Dict Attack
nfc->dict_attack = dict_attack_alloc();
view_dispatcher_add_view(
nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack));

return nfc;
}

Expand Down Expand Up @@ -121,6 +126,10 @@ void nfc_free(Nfc* nfc) {
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard);
bank_card_free(nfc->bank_card);

// Dict Attack
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack);
dict_attack_free(nfc->dict_attack);

// Worker
nfc_worker_stop(nfc->worker);
nfc_worker_free(nfc->worker);
Expand Down
90 changes: 87 additions & 3 deletions applications/nfc/nfc_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,23 @@ void nfc_device_free(NfcDevice* nfc_dev) {
free(nfc_dev);
}

void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) {
static void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) {
if(dev->format == NfcDeviceSaveFormatUid) {
string_set_str(format_string, "UID");
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
string_set_str(format_string, "Bank card");
} else if(dev->format == NfcDeviceSaveFormatMifareUl) {
string_set_str(format_string, nfc_mf_ul_type(dev->dev_data.mf_ul_data.type, true));
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
string_set_str(format_string, "Mifare Classic");
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
string_set_str(format_string, "Mifare DESFire");
} else {
string_set_str(format_string, "Unknown");
}
}

bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
if(string_start_with_str_p(format_string, "UID")) {
dev->format = NfcDeviceSaveFormatUid;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown;
Expand All @@ -56,6 +58,11 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
return true;
}
}
if(string_start_with_str_p(format_string, "Mifare Classic")) {
dev->format = NfcDeviceSaveFormatMifareClassic;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareClassic;
return true;
}
if(string_start_with_str_p(format_string, "Mifare DESFire")) {
dev->format = NfcDeviceSaveFormatMifareDesfire;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareDesfire;
Expand Down Expand Up @@ -605,6 +612,79 @@ bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
return parsed;
}

static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) {
bool saved = false;
MfClassicData* data = &dev->dev_data.mf_classic_data;
string_t temp_str;
string_init(temp_str);
uint16_t blocks = 0;

// Save Mifare Classic specific data
do {
if(!flipper_format_write_comment_cstr(file, "Mifare Classic specific data")) break;
if(data->type == MfClassicType1k) {
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break;
blocks = 64;
} else if(data->type == MfClassicType4k) {
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "4K")) break;
blocks = 256;
}
if(!flipper_format_write_comment_cstr(file, "Mifare Classic blocks")) break;

bool block_saved = true;
for(size_t i = 0; i < blocks; i++) {
string_printf(temp_str, "Block %d", i);
if(!flipper_format_write_hex(
file, string_get_cstr(temp_str), data->block[i].value, 16)) {
block_saved = false;
break;
}
}
if(!block_saved) break;
saved = true;
} while(false);

string_clear(temp_str);
return saved;
}

static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) {
bool parsed = false;
MfClassicData* data = &dev->dev_data.mf_classic_data;
string_t temp_str;
string_init(temp_str);
uint16_t data_blocks = 0;

do {
// Read Mifare Classic type
if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break;
if(!string_cmp_str(temp_str, "1K")) {
data->type = MfClassicType1k;
data_blocks = 64;
} else if(!string_cmp_str(temp_str, "4K")) {
data->type = MfClassicType4k;
data_blocks = 256;
} else {
break;
}
// Read Mifare Classic blocks
bool block_read = true;
for(size_t i = 0; i < data_blocks; i++) {
string_printf(temp_str, "Block %d", i);
if(!flipper_format_read_hex(
file, string_get_cstr(temp_str), data->block[i].value, 16)) {
block_read = false;
break;
}
}
if(!block_read) break;
parsed = true;
} while(false);

string_clear(temp_str);
return parsed;
}

void nfc_device_set_name(NfcDevice* dev, const char* name) {
furi_assert(dev);

Expand Down Expand Up @@ -635,7 +715,7 @@ static bool nfc_device_save_file(
if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break;
// Write nfc device type
if(!flipper_format_write_comment_cstr(
file, "Nfc device type can be UID, Mifare Ultralight, Bank card"))
file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic, Bank card"))
break;
nfc_device_prepare_format_string(dev, temp_str);
if(!flipper_format_write_string(file, "Device type", temp_str)) break;
Expand All @@ -652,6 +732,8 @@ static bool nfc_device_save_file(
if(!nfc_device_save_mifare_df_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
if(!nfc_device_save_bank_card_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
if(!nfc_device_save_mifare_classic_data(file, dev)) break;
}
saved = true;
} while(0);
Expand Down Expand Up @@ -714,6 +796,8 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
// Parse other data
if(dev->format == NfcDeviceSaveFormatMifareUl) {
if(!nfc_device_load_mifare_ul_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
if(!nfc_device_load_mifare_classic_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
if(!nfc_device_load_mifare_df_data(file, dev)) break;
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
Expand Down
8 changes: 6 additions & 2 deletions applications/nfc/nfc_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
#include <storage/storage.h>
#include <dialogs/dialogs.h>

#include "mifare_ultralight.h"
#include "mifare_desfire.h"
#include <lib/nfc_protocols/mifare_ultralight.h>
#include <lib/nfc_protocols/mifare_classic.h>
#include <lib/nfc_protocols/mifare_desfire.h>

#define NFC_DEV_NAME_MAX_LEN 22
#define NFC_FILE_NAME_MAX_LEN 120
Expand All @@ -27,13 +28,15 @@ typedef enum {
NfcDeviceProtocolUnknown,
NfcDeviceProtocolEMV,
NfcDeviceProtocolMifareUl,
NfcDeviceProtocolMifareClassic,
NfcDeviceProtocolMifareDesfire,
} NfcProtocol;

typedef enum {
NfcDeviceSaveFormatUid,
NfcDeviceSaveFormatBankCard,
NfcDeviceSaveFormatMifareUl,
NfcDeviceSaveFormatMifareClassic,
NfcDeviceSaveFormatMifareDesfire,
} NfcDeviceSaveFormat;

Expand Down Expand Up @@ -69,6 +72,7 @@ typedef struct {
union {
NfcEmvData emv_data;
MifareUlData mf_ul_data;
MfClassicData mf_classic_data;
MifareDesfireData mf_df_data;
};
} NfcDeviceData;
Expand Down
3 changes: 3 additions & 0 deletions applications/nfc/nfc_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <gui/modules/widget.h>

#include "views/bank_card.h"
#include "views/dict_attack.h"

#include <nfc/scenes/nfc_scene.h>
#include <nfc/helpers/nfc_custom_event.h>
Expand Down Expand Up @@ -53,6 +54,7 @@ struct Nfc {
TextBox* text_box;
Widget* widget;
BankCard* bank_card;
DictAttack* dict_attack;
};

typedef enum {
Expand All @@ -64,6 +66,7 @@ typedef enum {
NfcViewTextBox,
NfcViewWidget,
NfcViewBankCard,
NfcViewDictAttack,
} NfcView;

Nfc* nfc_alloc();
Expand Down
12 changes: 12 additions & 0 deletions applications/nfc/nfc_types.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const char* nfc_guess_protocol(NfcProtocol protocol) {
return "EMV bank card";
} else if(protocol == NfcDeviceProtocolMifareUl) {
return "Mifare Ultral/NTAG";
} else if(protocol == NfcDeviceProtocolMifareClassic) {
return "Mifare Classic";
} else if(protocol == NfcDeviceProtocolMifareDesfire) {
return "Mifare DESFire";
} else {
Expand All @@ -75,3 +77,13 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) {
return "Mifare Ultralight";
}
}

const char* nfc_mf_classic_type(MfClassicType type) {
if(type == MfClassicType1k) {
return "Mifare Classic 1K";
} else if(type == MfClassicType4k) {
return "Mifare Classic 4K";
} else {
return "Mifare Classic";
}
}
2 changes: 2 additions & 0 deletions applications/nfc/nfc_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type);
const char* nfc_guess_protocol(NfcProtocol protocol);

const char* nfc_mf_ul_type(MfUltralightType type, bool full_name);

const char* nfc_mf_classic_type(MfClassicType type);
Loading

0 comments on commit eafeefb

Please sign in to comment.