2022-07-26 18:30:49 +03:00
|
|
|
#include "nfc_supported_card.h"
|
|
|
|
|
|
|
|
#include <gui/modules/widget.h>
|
|
|
|
#include <nfc_worker_i.h>
|
|
|
|
|
2022-09-19 19:05:04 +03:00
|
|
|
static const MfClassicAuthContext troika_keys[] = {
|
2022-07-26 18:30:49 +03:00
|
|
|
{.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58},
|
|
|
|
{.sector = 1, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880},
|
|
|
|
{.sector = 2, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99},
|
|
|
|
{.sector = 3, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99},
|
|
|
|
{.sector = 4, .key_a = 0x73068f118c13, .key_b = 0x2b7f3253fac5},
|
|
|
|
{.sector = 5, .key_a = 0xfbc2793d540b, .key_b = 0xd3a297dc2698},
|
|
|
|
{.sector = 6, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99},
|
|
|
|
{.sector = 7, .key_a = 0xae3d65a3dad4, .key_b = 0x0f1c63013dba},
|
|
|
|
{.sector = 8, .key_a = 0xa73f5dc1d333, .key_b = 0xe35173494a81},
|
|
|
|
{.sector = 9, .key_a = 0x69a32f1c2f19, .key_b = 0x6b8bd9860763},
|
|
|
|
{.sector = 10, .key_a = 0x9becdf3d9273, .key_b = 0xf8493407799d},
|
|
|
|
{.sector = 11, .key_a = 0x08b386463229, .key_b = 0x5efbaecef46b},
|
|
|
|
{.sector = 12, .key_a = 0xcd4c61c26e3d, .key_b = 0x31c7610de3b0},
|
|
|
|
{.sector = 13, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880},
|
|
|
|
{.sector = 14, .key_a = 0x0e8f64340ba4, .key_b = 0x4acec1205d75},
|
|
|
|
{.sector = 15, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99},
|
|
|
|
};
|
|
|
|
|
2022-09-19 19:05:04 +03:00
|
|
|
bool troika_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
2022-07-26 18:30:49 +03:00
|
|
|
furi_assert(nfc_worker);
|
|
|
|
UNUSED(nfc_worker);
|
2022-09-19 19:05:04 +03:00
|
|
|
if(nfc_worker->dev_data->mf_classic_data.type != MfClassicType1k) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-07-26 18:30:49 +03:00
|
|
|
|
2022-09-19 19:05:04 +03:00
|
|
|
uint8_t sector = 11;
|
|
|
|
uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector);
|
|
|
|
FURI_LOG_D("Troika", "Verifying sector %d", sector);
|
|
|
|
if(mf_classic_authenticate(tx_rx, block, 0x08b386463229, MfClassicKeyA)) {
|
|
|
|
FURI_LOG_D("Troika", "Sector %d verified", sector);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2022-07-26 18:30:49 +03:00
|
|
|
}
|
|
|
|
|
2022-09-19 19:05:04 +03:00
|
|
|
bool troika_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
2022-07-26 18:30:49 +03:00
|
|
|
furi_assert(nfc_worker);
|
|
|
|
|
|
|
|
MfClassicReader reader = {};
|
|
|
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
2022-08-07 18:33:14 +03:00
|
|
|
reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak);
|
|
|
|
|
2022-09-19 19:05:04 +03:00
|
|
|
for(size_t i = 0; i < COUNT_OF(troika_keys); i++) {
|
2022-07-26 18:30:49 +03:00
|
|
|
mf_classic_reader_add_sector(
|
2022-09-19 19:05:04 +03:00
|
|
|
&reader, troika_keys[i].sector, troika_keys[i].key_a, troika_keys[i].key_b);
|
2022-07-26 18:30:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16;
|
|
|
|
}
|
|
|
|
|
2022-09-19 19:05:04 +03:00
|
|
|
bool troika_parser_parse(NfcDeviceData* dev_data) {
|
2022-08-17 18:08:13 +03:00
|
|
|
MfClassicData* data = &dev_data->mf_classic_data;
|
2022-09-19 19:05:04 +03:00
|
|
|
bool troika_parsed = false;
|
2022-08-17 18:08:13 +03:00
|
|
|
|
|
|
|
do {
|
|
|
|
// Verify key
|
|
|
|
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8);
|
|
|
|
uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6);
|
2022-09-19 19:05:04 +03:00
|
|
|
if(key != troika_keys[8].key_a) break;
|
|
|
|
|
|
|
|
// Verify card type
|
|
|
|
if(data->type != MfClassicType1k) break;
|
2022-08-17 18:08:13 +03:00
|
|
|
|
|
|
|
// Parse data
|
|
|
|
uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5];
|
|
|
|
uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25;
|
2023-04-02 01:11:05 +03:00
|
|
|
temp_ptr = &data->block[8 * 4].value[2];
|
2022-08-17 18:08:13 +03:00
|
|
|
uint32_t number = 0;
|
2023-04-02 01:11:05 +03:00
|
|
|
for(size_t i = 1; i < 5; i++) {
|
2022-08-17 18:08:13 +03:00
|
|
|
number <<= 8;
|
|
|
|
number |= temp_ptr[i];
|
|
|
|
}
|
|
|
|
number >>= 4;
|
2023-04-02 01:11:05 +03:00
|
|
|
number |= (temp_ptr[0] & 0xf) << 28;
|
2022-07-26 18:30:49 +03:00
|
|
|
|
2022-10-05 18:15:23 +03:00
|
|
|
furi_string_printf(
|
2023-03-15 15:01:33 +03:00
|
|
|
dev_data->parsed_data, "\e#Troika\nNum: %lu\nBalance: %u rur.", number, balance);
|
2022-09-19 19:05:04 +03:00
|
|
|
troika_parsed = true;
|
2022-08-17 18:08:13 +03:00
|
|
|
} while(false);
|
2022-07-26 18:30:49 +03:00
|
|
|
|
2022-09-19 19:05:04 +03:00
|
|
|
return troika_parsed;
|
2022-07-26 18:30:49 +03:00
|
|
|
}
|