Skip to content

Commit

Permalink
pre-functional stuff for mfc data loading
Browse files Browse the repository at this point in the history
  • Loading branch information
luu176 committed Feb 7, 2025
1 parent eaee873 commit e0d7044
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 114 deletions.
2 changes: 1 addition & 1 deletion metroflip_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ typedef enum {
MISSING_KEYFILE
} KeyfileManager;

CardType determine_card_type(Nfc* nfc);
CardType determine_card_type(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded);

#ifdef FW_ORIGIN_Official
#define submenu_add_lockable_item( \
Expand Down
252 changes: 157 additions & 95 deletions scenes/keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@

#define TAG "keys_check"

const MfClassicKeyPair troika_1k_key[1] = {
const MfClassicKeyPair troika_1k_key[] = {
{.a = 0x08b386463229},
};

const MfClassicKeyPair troika_4k_key[1] = {
const MfClassicKeyPair troika_4k_key[] = {
{.a = 0xA73F5DC1D333},
};

Expand All @@ -25,111 +25,157 @@ const MfClassicKeyPair charliecard_1k_verify_key[] = {
{.a = 0x5EC39B022F2B},
};

const MfClassicKeyPair bip_1k_verify_key[1] = {
const MfClassicKeyPair bip_1k_verify_key[] = {
{.a = 0x3a42f33af429},
};

const MfClassicKeyPair metromoney_1k_verify_key[1] = {
const MfClassicKeyPair metromoney_1k_verify_key[] = {
{.a = 0x9C616585E26D},
};

static bool charliecard_verify(Nfc* nfc) {
static bool charliecard_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) {
bool verified = false;
FURI_LOG_I(TAG, "verifying charliecard..");

const uint8_t verify_sector = 1;
do {
const uint8_t verify_sector = 1;
const uint8_t verify_block = mf_classic_get_first_block_num_of_sector(verify_sector) + 1;
FURI_LOG_I(TAG, "Verifying sector %u", verify_sector);

MfClassicKey key = {0};
bit_lib_num_to_bytes_be(charliecard_1k_verify_key[0].a, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_context;
MfClassicError error =
mf_classic_poller_sync_auth(nfc, verify_block, &key, MfClassicKeyTypeA, &auth_context);
if(error != MfClassicErrorNone) {
FURI_LOG_I(TAG, "Failed to read block %u: %d", verify_block, error);
break;
if(!data_loaded) {
const uint8_t verify_block =
mf_classic_get_first_block_num_of_sector(verify_sector) + 1;
FURI_LOG_I(TAG, "Verifying sector %u", verify_sector);

MfClassicKey key = {0};
bit_lib_num_to_bytes_be(charliecard_1k_verify_key[0].a, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_context;
MfClassicError error = mf_classic_poller_sync_auth(
nfc, verify_block, &key, MfClassicKeyTypeA, &auth_context);
if(error != MfClassicErrorNone) {
FURI_LOG_I(TAG, "Failed to read block %u: %d", verify_block, error);
break;
}

verified = true;
} else {
MfClassicSectorTrailer* sec_tr =
mf_classic_get_sector_trailer_by_sector(mfc_data, verify_sector);
FURI_LOG_I(TAG, "%2x", sec_tr->key_a.data[1]);
uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6);
if(key != charliecard_1k_verify_key[0].a) {
FURI_LOG_I(TAG, "not equall");
break;
}

verified = true;
}

verified = true;
} while(false);

return verified;
}

bool bip_verify(Nfc* nfc) {
bool bip_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) {
bool verified = false;

do {
const uint8_t verify_sector = 0;
uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector);
FURI_LOG_I(TAG, "Verifying sector %u", verify_sector);
if(!data_loaded) {
const uint8_t verify_sector = 0;
uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector);
FURI_LOG_I(TAG, "Verifying sector %u", verify_sector);

MfClassicKey key = {};
bit_lib_num_to_bytes_be(bip_1k_verify_key[0].a, COUNT_OF(key.data), key.data);
MfClassicKey key = {};
bit_lib_num_to_bytes_be(bip_1k_verify_key[0].a, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_ctx = {};
MfClassicError error =
mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx);
MfClassicAuthContext auth_ctx = {};
MfClassicError error =
mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx);

if(error != MfClassicErrorNone) {
FURI_LOG_I(TAG, "Failed to read block %u: %d", block_num, error);
break;
}
if(error != MfClassicErrorNone) {
FURI_LOG_I(TAG, "Failed to read block %u: %d", block_num, error);
break;
}

verified = true;
} else {
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(mfc_data, 0);

verified = true;
uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6);
if(key != bip_1k_verify_key[0].a) {
break;
}

verified = true;
}
} while(false);

return verified;
}

static bool metromoney_verify(Nfc* nfc) {
static bool metromoney_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) {
bool verified = false;

const uint8_t ticket_sector_number = 1;
do {
const uint8_t ticket_sector_number = 1;
const uint8_t ticket_block_number =
mf_classic_get_first_block_num_of_sector(ticket_sector_number) + 1;
FURI_LOG_D(TAG, "Verifying sector %u", ticket_sector_number);

MfClassicKey key = {0};
bit_lib_num_to_bytes_be(metromoney_1k_verify_key[0].a, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_context;
MfClassicError error = mf_classic_poller_sync_auth(
nfc, ticket_block_number, &key, MfClassicKeyTypeA, &auth_context);
if(error != MfClassicErrorNone) {
FURI_LOG_D(TAG, "Failed to read block %u: %d", ticket_block_number, error);
break;
if(!data_loaded) {
const uint8_t ticket_block_number =
mf_classic_get_first_block_num_of_sector(ticket_sector_number) + 1;
FURI_LOG_D(TAG, "Verifying sector %u", ticket_sector_number);

MfClassicKey key = {0};
bit_lib_num_to_bytes_be(metromoney_1k_verify_key[0].a, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_context;
MfClassicError error = mf_classic_poller_sync_auth(
nfc, ticket_block_number, &key, MfClassicKeyTypeA, &auth_context);
if(error != MfClassicErrorNone) {
FURI_LOG_D(TAG, "Failed to read block %u: %d", ticket_block_number, error);
break;
}

verified = true;
} else {
MfClassicSectorTrailer* sec_tr =
mf_classic_get_sector_trailer_by_sector(mfc_data, ticket_sector_number);

uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6);
if(key != metromoney_1k_verify_key[0].a) {
break;
}

verified = true;
}

verified = true;
} while(false);

return verified;
}

static bool smartrider_verify(Nfc* nfc) {
static bool smartrider_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) {
bool verified = false;

do {
const uint8_t block_number = mf_classic_get_first_block_num_of_sector(0) + 1;
FURI_LOG_D(TAG, "Verifying sector 0");

MfClassicKey key = {0};
bit_lib_num_to_bytes_be(smartrider_verify_key[0].a, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_context;
MfClassicError error =
mf_classic_poller_sync_auth(nfc, block_number, &key, MfClassicKeyTypeA, &auth_context);
if(error != MfClassicErrorNone) {
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_number, error);
break;
if(!data_loaded) {
const uint8_t block_number = mf_classic_get_first_block_num_of_sector(0) + 1;
FURI_LOG_D(TAG, "Verifying sector 0");

MfClassicKey key = {0};
bit_lib_num_to_bytes_be(smartrider_verify_key[0].a, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_context;
MfClassicError error = mf_classic_poller_sync_auth(
nfc, block_number, &key, MfClassicKeyTypeA, &auth_context);
if(error != MfClassicErrorNone) {
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_number, error);
break;
}

verified = true;
} else {
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(mfc_data, 0);

uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6);
if(key != smartrider_verify_key[0].a) {
break;
}

verified = true;
}

verified = true;
} while(false);

return verified;
Expand All @@ -151,50 +197,66 @@ static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type)
return success;
}

static bool troika_verify_type(Nfc* nfc, MfClassicType type) {
static bool
troika_verify_type(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded, MfClassicType type) {
bool verified = false;

do {
TroikaCardConfig cfg = {};
if(!troika_get_card_config(&cfg, type)) break;

const uint8_t block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector);
FURI_LOG_D(TAG, "Verifying sector %lu", cfg.data_sector);

MfClassicKey key = {0};
bit_lib_num_to_bytes_be(cfg.keys[0].a, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_context;
MfClassicError error =
mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context);
if(error != MfClassicErrorNone) {
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
break;
if(!data_loaded) {
TroikaCardConfig cfg = {};
if(!troika_get_card_config(&cfg, type)) break;

const uint8_t block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector);
FURI_LOG_D(TAG, "Verifying sector %lu", cfg.data_sector);

MfClassicKey key = {0};
bit_lib_num_to_bytes_be(cfg.keys[0].a, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_context;
MfClassicError error = mf_classic_poller_sync_auth(
nfc, block_num, &key, MfClassicKeyTypeA, &auth_context);
if(error != MfClassicErrorNone) {
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
break;
}
FURI_LOG_D(TAG, "Verify success!");
verified = true;
} else {
TroikaCardConfig cfg = {};
if(!troika_get_card_config(&cfg, type)) break;
MfClassicSectorTrailer* sec_tr =
mf_classic_get_sector_trailer_by_sector(mfc_data, cfg.data_sector);

uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6);
if(key != cfg.keys[0].a) {
break;
}

verified = true;
}
FURI_LOG_D(TAG, "Verify success!");
verified = true;
} while(false);

return verified;
}

static bool troika_verify(Nfc* nfc) {
return troika_verify_type(nfc, MfClassicType1k) || troika_verify_type(nfc, MfClassicType4k);
static bool troika_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) {
return troika_verify_type(nfc, mfc_data, data_loaded, MfClassicType1k) ||
troika_verify_type(nfc, mfc_data, data_loaded, MfClassicType4k);
}

CardType determine_card_type(Nfc* nfc) {
CardType determine_card_type(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) {
FURI_LOG_I(TAG, "checking keys..");
UNUSED(bip_verify);

if(bip_verify(nfc)) {
return CARD_TYPE_METROMONEY;
} else if(metromoney_verify(nfc)) {
if(bip_verify(nfc, mfc_data, data_loaded)) {
return CARD_TYPE_BIP;
} else if(metromoney_verify(nfc, mfc_data, data_loaded)) {
return CARD_TYPE_METROMONEY;
} else if(smartrider_verify(nfc)) {
} else if(smartrider_verify(nfc, mfc_data, data_loaded)) {
return CARD_TYPE_SMARTRIDER;
} else if(troika_verify(nfc)) {
} else if(troika_verify(nfc, mfc_data, data_loaded)) {
return CARD_TYPE_TROIKA;
} else if(charliecard_verify(nfc)) {
} else if(charliecard_verify(nfc, mfc_data, data_loaded)) {
return CARD_TYPE_CHARLIECARD;
} else {
FURI_LOG_I(TAG, "its unknown");
Expand Down
5 changes: 4 additions & 1 deletion scenes/metroflip_scene_auto.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@ bool metroflip_scene_auto_on_event(void* context, SceneManagerEvent event) {
app->auto_mode = true;
if(nfc_detected_protocols_get_protocol(app->detected_protocols, 0) ==
NfcProtocolMfClassic) {
CardType card_type = determine_card_type(app->nfc);
MfClassicData* mfc_data = mf_classic_alloc();
app->data_loaded = false;
CardType card_type = determine_card_type(app->nfc, mfc_data, app->data_loaded);
mf_classic_free(mfc_data);
app->mfc_card_type = card_type;
Popup* popup = app->popup;
UNUSED(popup);
Expand Down
Loading

0 comments on commit e0d7044

Please sign in to comment.