| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- #include "../metroflip_i.h"
- #include "keys.h"
- #include <bit_lib.h>
- #include <nfc/protocols/mf_classic/mf_classic.h>
- #include <nfc/protocols/mf_classic/mf_classic_poller.h>
- #include <nfc/nfc.h>
- #include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
- #include <string.h>
- #define TAG "keys_check"
- const MfClassicKeyPair troika_1k_keys[16] = {
- {.a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58},
- {.a = 0xa82607b01c0d, .b = 0x2910989b6880},
- {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99},
- {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99},
- {.a = 0x73068f118c13, .b = 0x2b7f3253fac5},
- {.a = 0xfbc2793d540b, .b = 0xd3a297dc2698},
- {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99},
- {.a = 0xae3d65a3dad4, .b = 0x0f1c63013dba},
- {.a = 0xa73f5dc1d333, .b = 0xe35173494a81},
- {.a = 0x69a32f1c2f19, .b = 0x6b8bd9860763},
- {.a = 0x9becdf3d9273, .b = 0xf8493407799d},
- {.a = 0x08b386463229, .b = 0x5efbaecef46b},
- {.a = 0xcd4c61c26e3d, .b = 0x31c7610de3b0},
- {.a = 0xa82607b01c0d, .b = 0x2910989b6880},
- {.a = 0x0e8f64340ba4, .b = 0x4acec1205d75},
- {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99},
- };
- const MfClassicKeyPair troika_4k_keys[40] = {
- {.a = 0xEC29806D9738, .b = 0xFBF225DC5D58}, //1
- {.a = 0xA0A1A2A3A4A5, .b = 0x7DE02A7F6025}, //2
- {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //3
- {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //4
- {.a = 0x73068F118C13, .b = 0x2B7F3253FAC5}, //5
- {.a = 0xFBC2793D540B, .b = 0xD3A297DC2698}, //6
- {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //7
- {.a = 0xAE3D65A3DAD4, .b = 0x0F1C63013DBA}, //8
- {.a = 0xA73F5DC1D333, .b = 0xE35173494A81}, //9
- {.a = 0x69A32F1C2F19, .b = 0x6B8BD9860763}, //10
- {.a = 0x9BECDF3D9273, .b = 0xF8493407799D}, //11
- {.a = 0x08B386463229, .b = 0x5EFBAECEF46B}, //12
- {.a = 0xCD4C61C26E3D, .b = 0x31C7610DE3B0}, //13
- {.a = 0xA82607B01C0D, .b = 0x2910989B6880}, //14
- {.a = 0x0E8F64340BA4, .b = 0x4ACEC1205D75}, //15
- {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //16
- {.a = 0x6B02733BB6EC, .b = 0x7038CD25C408}, //17
- {.a = 0x403D706BA880, .b = 0xB39D19A280DF}, //18
- {.a = 0xC11F4597EFB5, .b = 0x70D901648CB9}, //19
- {.a = 0x0DB520C78C1C, .b = 0x73E5B9D9D3A4}, //20
- {.a = 0x3EBCE0925B2F, .b = 0x372CC880F216}, //21
- {.a = 0x16A27AF45407, .b = 0x9868925175BA}, //22
- {.a = 0xABA208516740, .b = 0xCE26ECB95252}, //23
- {.a = 0xCD64E567ABCD, .b = 0x8F79C4FD8A01}, //24
- {.a = 0x764CD061F1E6, .b = 0xA74332F74994}, //25
- {.a = 0x1CC219E9FEC1, .b = 0xB90DE525CEB6}, //26
- {.a = 0x2FE3CB83EA43, .b = 0xFBA88F109B32}, //27
- {.a = 0x07894FFEC1D6, .b = 0xEFCB0E689DB3}, //28
- {.a = 0x04C297B91308, .b = 0xC8454C154CB5}, //29
- {.a = 0x7A38E3511A38, .b = 0xAB16584C972A}, //30
- {.a = 0x7545DF809202, .b = 0xECF751084A80}, //31
- {.a = 0x5125974CD391, .b = 0xD3EAFB5DF46D}, //32
- {.a = 0x7A86AA203788, .b = 0xE41242278CA2}, //33
- {.a = 0xAFCEF64C9913, .b = 0x9DB96DCA4324}, //34
- {.a = 0x04EAA462F70B, .b = 0xAC17B93E2FAE}, //35
- {.a = 0xE734C210F27E, .b = 0x29BA8C3E9FDA}, //36
- {.a = 0xD5524F591EED, .b = 0x5DAF42861B4D}, //37
- {.a = 0xE4821A377B75, .b = 0xE8709E486465}, //38
- {.a = 0x518DC6EEA089, .b = 0x97C64AC98CA4}, //39
- {.a = 0xBB52F8CCE07F, .b = 0x6B6119752C70}, //40
- };
- const uint8_t SMARTRIDER_STANDARD_KEYS[3][6] = {
- {0x20, 0x31, 0xD1, 0xE5, 0x7A, 0x3B},
- {0x4C, 0xA6, 0x02, 0x9F, 0x94, 0x73},
- {0x19, 0x19, 0x53, 0x98, 0xE3, 0x2F}};
- const MfClassicKeyPair charliecard_1k_keys[16] = {
- {.a = 0x3060206F5B0A, .b = 0xF1B9F5669CC8},
- {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
- {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
- {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
- {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
- {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
- {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
- {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
- {.a = 0x3A09594C8587, .b = 0x62387B8D250D},
- {.a = 0xF238D78FF48F, .b = 0x9DC282D46217},
- {.a = 0xAFD0BA94D624, .b = 0x92EE4DC87191},
- {.a = 0xB35A0E4ACC09, .b = 0x756EF55E2507},
- {.a = 0x447AB7FD5A6B, .b = 0x932B9CB730EF},
- {.a = 0x1F1A0A111B5B, .b = 0xAD9E0A1CA2F7},
- {.a = 0xD58023BA2BDC, .b = 0x62CED42A6D87},
- {.a = 0x2548A443DF28, .b = 0x2ED3B15E7C0F},
- };
- const MfClassicKeyPair bip_1k_keys[16] = {
- {.a = 0x3a42f33af429, .b = 0x1fc235ac1309},
- {.a = 0x6338a371c0ed, .b = 0x243f160918d1},
- {.a = 0xf124c2578ad0, .b = 0x9afc42372af1},
- {.a = 0x32ac3b90ac13, .b = 0x682d401abb09},
- {.a = 0x4ad1e273eaf1, .b = 0x067db45454a9},
- {.a = 0xe2c42591368a, .b = 0x15fc4c7613fe},
- {.a = 0x2a3c347a1200, .b = 0x68d30288910a},
- {.a = 0x16f3d5ab1139, .b = 0xf59a36a2546d},
- {.a = 0x937a4fff3011, .b = 0x64e3c10394c2},
- {.a = 0x35c3d2caee88, .b = 0xb736412614af},
- {.a = 0x693143f10368, .b = 0x324f5df65310},
- {.a = 0xa3f97428dd01, .b = 0x643fb6de2217},
- {.a = 0x63f17a449af0, .b = 0x82f435dedf01},
- {.a = 0xc4652c54261c, .b = 0x0263de1278f3},
- {.a = 0xd49e2826664f, .b = 0x51284c3686a6},
- {.a = 0x3df14c8000a1, .b = 0x6a470d54127c},
- };
- const MfClassicKeyPair metromoney_1k_keys[16] = {
- {.a = 0x2803BCB0C7E1, .b = 0x4FA9EB49F75E},
- {.a = 0x9C616585E26D, .b = 0xD1C71E590D16},
- {.a = 0x9C616585E26D, .b = 0xA160FCD5EC4C},
- {.a = 0x9C616585E26D, .b = 0xA160FCD5EC4C},
- {.a = 0x9C616585E26D, .b = 0xA160FCD5EC4C},
- {.a = 0x9C616585E26D, .b = 0xA160FCD5EC4C},
- {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
- {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
- {.a = 0x112233445566, .b = 0x361A62F35BC9},
- {.a = 0x112233445566, .b = 0x361A62F35BC9},
- {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
- {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
- {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
- {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
- {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
- {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
- };
- static bool charliecard_verify(Nfc* nfc) {
- bool verified = false;
- FURI_LOG_I(TAG, "verifying charliecard..");
- 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_keys[verify_sector].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;
- } while(false);
- return verified;
- }
- bool bip_verify(Nfc* nfc) {
- 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);
- MfClassicKey key = {};
- bit_lib_num_to_bytes_be(bip_1k_keys[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);
- if(error != MfClassicErrorNone) {
- FURI_LOG_I(TAG, "Failed to read block %u: %d", block_num, error);
- break;
- }
- verified = true;
- } while(false);
- return verified;
- }
- static bool metromoney_verify(Nfc* nfc) {
- bool verified = false;
- 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_keys[ticket_sector_number].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;
- } while(false);
- return verified;
- }
- static bool smartrider_authenticate_and_read(
- Nfc* nfc,
- uint8_t sector,
- const uint8_t* key,
- MfClassicKeyType key_type,
- MfClassicBlock* block_data) {
- MfClassicKey mf_key;
- memcpy(mf_key.data, key, 6);
- uint8_t block = mf_classic_get_first_block_num_of_sector(sector);
- if(mf_classic_poller_sync_auth(nfc, block, &mf_key, key_type, NULL) != MfClassicErrorNone) {
- FURI_LOG_D(TAG, "Authentication failed for sector %d key type %d", sector, key_type);
- return false;
- }
- if(mf_classic_poller_sync_read_block(nfc, block, &mf_key, key_type, block_data) !=
- MfClassicErrorNone) {
- FURI_LOG_D(TAG, "Read failed for sector %d", sector);
- return false;
- }
- return true;
- }
- static bool smartrider_verify(Nfc* nfc) {
- furi_assert(nfc);
- MfClassicBlock block_data;
- for(int i = 0; i < 3; i++) {
- if(!smartrider_authenticate_and_read(
- nfc,
- i * 6,
- SMARTRIDER_STANDARD_KEYS[i],
- i % 2 == 0 ? MfClassicKeyTypeA : MfClassicKeyTypeB,
- &block_data) ||
- memcmp(block_data.data, SMARTRIDER_STANDARD_KEYS[i], 6) != 0) {
- FURI_LOG_D(TAG, "Authentication or key mismatch for key %d", i);
- return false;
- }
- }
- FURI_LOG_I(TAG, "SmartRider card verified");
- return true;
- }
- static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) {
- bool success = true;
- if(type == MfClassicType1k) {
- config->data_sector = 11;
- config->keys = troika_1k_keys;
- } else if(type == MfClassicType4k) {
- config->data_sector = 8; // Further testing needed
- config->keys = troika_4k_keys;
- } else {
- success = false;
- }
- return success;
- }
- static bool troika_verify_type(Nfc* nfc, 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[cfg.data_sector].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;
- } while(false);
- return verified;
- }
- static bool troika_verify(Nfc* nfc) {
- return troika_verify_type(nfc, MfClassicType1k) || troika_verify_type(nfc, MfClassicType4k);
- }
- CardType determine_card_type(Nfc* nfc) {
- FURI_LOG_I(TAG, "checking keys..");
- UNUSED(bip_verify);
- if(bip_verify(nfc)) {
- return CARD_TYPE_METROMONEY;
- } else if(metromoney_verify(nfc)) {
- return CARD_TYPE_METROMONEY;
- } else if(smartrider_verify(nfc)) {
- return CARD_TYPE_SMARTRIDER;
- } else if(troika_verify(nfc)) {
- return CARD_TYPE_TROIKA;
- } else if(charliecard_verify(nfc)) {
- return CARD_TYPE_CHARLIECARD;
- } else {
- FURI_LOG_I(TAG, "its unknown");
- return CARD_TYPE_UNKNOWN;
- }
- }
|