mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-31 02:23:04 -07:00
Merge remote-tracking branch 'upstream/dev' into mrtd
This commit is contained in:
@@ -44,7 +44,10 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) {
|
||||
do {
|
||||
if(dict_type == MfClassicDictTypeFlipper) {
|
||||
if(!buffered_file_stream_open(
|
||||
dict->stream, MF_CLASSIC_DICT_FLIPPER_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
dict->stream,
|
||||
MF_CLASSIC_DICT_FLIPPER_PATH,
|
||||
FSAM_READ_WRITE,
|
||||
FSOM_OPEN_EXISTING)) {
|
||||
buffered_file_stream_close(dict->stream);
|
||||
break;
|
||||
}
|
||||
@@ -59,12 +62,24 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) {
|
||||
dict->stream,
|
||||
MF_CLASSIC_DICT_UNIT_TEST_PATH,
|
||||
FSAM_READ_WRITE,
|
||||
FSOM_CREATE_ALWAYS)) {
|
||||
FSOM_OPEN_ALWAYS)) {
|
||||
buffered_file_stream_close(dict->stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for new line ending
|
||||
if(!stream_eof(dict->stream)) {
|
||||
if(!stream_seek(dict->stream, -1, StreamOffsetFromEnd)) break;
|
||||
uint8_t last_char = 0;
|
||||
if(stream_read(dict->stream, &last_char, 1) != 1) break;
|
||||
if(last_char != '\n') {
|
||||
FURI_LOG_D(TAG, "Adding new line ending");
|
||||
if(stream_write_char(dict->stream, '\n') != 1) break;
|
||||
}
|
||||
if(!stream_rewind(dict->stream)) break;
|
||||
}
|
||||
|
||||
// Read total amount of keys
|
||||
FuriString* next_line;
|
||||
next_line = furi_string_alloc();
|
||||
@@ -73,14 +88,13 @@ MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) {
|
||||
FURI_LOG_T(TAG, "No keys left in dict");
|
||||
break;
|
||||
}
|
||||
furi_string_trim(next_line);
|
||||
FURI_LOG_T(
|
||||
TAG,
|
||||
"Read line: %s, len: %d",
|
||||
furi_string_get_cstr(next_line),
|
||||
furi_string_size(next_line));
|
||||
if(furi_string_get_char(next_line, 0) == '#') continue;
|
||||
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN - 1) continue;
|
||||
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
|
||||
dict->total_keys++;
|
||||
}
|
||||
furi_string_free(next_line);
|
||||
|
||||
+3
-33
@@ -636,35 +636,7 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
||||
bool saved = false;
|
||||
EmvData* data = &dev->dev_data.emv_data;
|
||||
uint32_t data_temp = 0;
|
||||
|
||||
do {
|
||||
// Write Bank card specific data
|
||||
if(!flipper_format_write_comment_cstr(file, "Bank card specific data")) break;
|
||||
if(!flipper_format_write_hex(file, "AID", data->aid, data->aid_len)) break;
|
||||
if(!flipper_format_write_string_cstr(file, "Name", data->name)) break;
|
||||
if(!flipper_format_write_hex(file, "Number", data->number, data->number_len)) break;
|
||||
if(data->exp_mon) {
|
||||
uint8_t exp_data[2] = {data->exp_mon, data->exp_year};
|
||||
if(!flipper_format_write_hex(file, "Exp data", exp_data, sizeof(exp_data))) break;
|
||||
}
|
||||
if(data->country_code) {
|
||||
data_temp = data->country_code;
|
||||
if(!flipper_format_write_uint32(file, "Country code", &data_temp, 1)) break;
|
||||
}
|
||||
if(data->currency_code) {
|
||||
data_temp = data->currency_code;
|
||||
if(!flipper_format_write_uint32(file, "Currency code", &data_temp, 1)) break;
|
||||
}
|
||||
saved = true;
|
||||
} while(false);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
// Leave for backward compatibility
|
||||
bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
||||
bool parsed = false;
|
||||
EmvData* data = &dev->dev_data.emv_data;
|
||||
@@ -949,7 +921,7 @@ static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) {
|
||||
file, furi_string_get_cstr(temp_str), sec_tr->key_a, 6);
|
||||
}
|
||||
if(!key_save_success) break;
|
||||
if(FURI_BIT(data->key_a_mask, i)) {
|
||||
if(FURI_BIT(data->key_b_mask, i)) {
|
||||
furi_string_printf(temp_str, "Key B sector %d", i);
|
||||
key_save_success = flipper_format_write_hex(
|
||||
file, furi_string_get_cstr(temp_str), sec_tr->key_b, 6);
|
||||
@@ -1068,7 +1040,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, Mifare Classic, Bank card"))
|
||||
file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic"))
|
||||
break;
|
||||
nfc_device_prepare_format_string(dev, temp_str);
|
||||
if(!flipper_format_write_string(file, "Device type", temp_str)) break;
|
||||
@@ -1083,8 +1055,6 @@ static bool nfc_device_save_file(
|
||||
if(!nfc_device_save_mifare_ul_data(file, dev)) break;
|
||||
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
||||
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) {
|
||||
// Save data
|
||||
if(!nfc_device_save_mifare_classic_data(file, dev)) break;
|
||||
|
||||
+92
-50
@@ -191,7 +191,7 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont
|
||||
uint8_t sectors_total =
|
||||
mf_classic_get_total_sectors_num(nfc_worker->dev_data->mf_classic_data.type);
|
||||
FURI_LOG_I(TAG, "Read %d sectors out of %d total", sectors_read, sectors_total);
|
||||
read_success = (sectors_read == sectors_total);
|
||||
read_success = mf_classic_is_card_read(&nfc_worker->dev_data->mf_classic_data);
|
||||
}
|
||||
} while(false);
|
||||
|
||||
@@ -233,31 +233,51 @@ static bool nfc_worker_read_bank_card(NfcWorker* nfc_worker, FuriHalNfcTxRxConte
|
||||
reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog);
|
||||
}
|
||||
|
||||
do {
|
||||
// Read card
|
||||
// Bank cards require strong field to start application. If we find AID, try at least several
|
||||
// times to start EMV application
|
||||
uint8_t start_application_attempts = 0;
|
||||
while(start_application_attempts < 3) {
|
||||
if(nfc_worker->state != NfcWorkerStateRead) break;
|
||||
start_application_attempts++;
|
||||
if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break;
|
||||
if(!emv_read_bank_card(tx_rx, &emv_app)) break;
|
||||
// Copy data
|
||||
// TODO Set EmvData to reader or like in mifare ultralight!
|
||||
result->number_len = emv_app.card_number_len;
|
||||
memcpy(result->number, emv_app.card_number, result->number_len);
|
||||
if(emv_read_bank_card(tx_rx, &emv_app)) {
|
||||
FURI_LOG_D(TAG, "Bank card number read from %d attempt", start_application_attempts);
|
||||
break;
|
||||
} else if(emv_app.aid_len && !emv_app.app_started) {
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"AID found but failed to start EMV app from %d attempt",
|
||||
start_application_attempts);
|
||||
furi_hal_nfc_sleep();
|
||||
continue;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Failed to find AID");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Copy data
|
||||
if(emv_app.aid_len) {
|
||||
result->aid_len = emv_app.aid_len;
|
||||
memcpy(result->aid, emv_app.aid, result->aid_len);
|
||||
if(emv_app.name_found) {
|
||||
memcpy(result->name, emv_app.name, sizeof(emv_app.name));
|
||||
}
|
||||
if(emv_app.exp_month) {
|
||||
result->exp_mon = emv_app.exp_month;
|
||||
result->exp_year = emv_app.exp_year;
|
||||
}
|
||||
if(emv_app.country_code) {
|
||||
result->country_code = emv_app.country_code;
|
||||
}
|
||||
if(emv_app.currency_code) {
|
||||
result->currency_code = emv_app.currency_code;
|
||||
}
|
||||
read_success = true;
|
||||
} while(false);
|
||||
}
|
||||
if(emv_app.card_number_len) {
|
||||
result->number_len = emv_app.card_number_len;
|
||||
memcpy(result->number, emv_app.card_number, result->number_len);
|
||||
}
|
||||
if(emv_app.name_found) {
|
||||
memcpy(result->name, emv_app.name, sizeof(emv_app.name));
|
||||
}
|
||||
if(emv_app.exp_month) {
|
||||
result->exp_mon = emv_app.exp_month;
|
||||
result->exp_year = emv_app.exp_year;
|
||||
}
|
||||
if(emv_app.country_code) {
|
||||
result->country_code = emv_app.country_code;
|
||||
}
|
||||
if(emv_app.currency_code) {
|
||||
result->currency_code = emv_app.currency_code;
|
||||
}
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
reader_analyzer_stop(nfc_worker->reader_analyzer);
|
||||
@@ -553,6 +573,9 @@ static void nfc_worker_mf_classic_key_attack(
|
||||
uint16_t start_sector) {
|
||||
furi_assert(nfc_worker);
|
||||
|
||||
bool card_found_notified = true;
|
||||
bool card_removed_notified = false;
|
||||
|
||||
MfClassicData* data = &nfc_worker->dev_data->mf_classic_data;
|
||||
uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type);
|
||||
|
||||
@@ -560,36 +583,52 @@ static void nfc_worker_mf_classic_key_attack(
|
||||
|
||||
// Check every sector's A and B keys with the given key
|
||||
for(size_t i = start_sector; i < total_sectors; i++) {
|
||||
uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i);
|
||||
if(mf_classic_is_sector_read(data, i)) continue;
|
||||
if(!mf_classic_is_key_found(data, i, MfClassicKeyA)) {
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Trying A key for sector %d, key: %04lx%08lx",
|
||||
i,
|
||||
(uint32_t)(key >> 32),
|
||||
(uint32_t)key);
|
||||
if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) {
|
||||
mf_classic_set_key_found(data, i, MfClassicKeyA, key);
|
||||
FURI_LOG_D(TAG, "Key found");
|
||||
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
|
||||
furi_hal_nfc_sleep();
|
||||
if(furi_hal_nfc_activate_nfca(200, NULL)) {
|
||||
furi_hal_nfc_sleep();
|
||||
if(!card_found_notified) {
|
||||
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
||||
card_found_notified = true;
|
||||
card_removed_notified = false;
|
||||
}
|
||||
uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i);
|
||||
if(mf_classic_is_sector_read(data, i)) continue;
|
||||
if(!mf_classic_is_key_found(data, i, MfClassicKeyA)) {
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Trying A key for sector %d, key: %04lx%08lx",
|
||||
i,
|
||||
(uint32_t)(key >> 32),
|
||||
(uint32_t)key);
|
||||
if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) {
|
||||
mf_classic_set_key_found(data, i, MfClassicKeyA, key);
|
||||
FURI_LOG_D(TAG, "Key found");
|
||||
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
|
||||
}
|
||||
}
|
||||
if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) {
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Trying B key for sector %d, key: %04lx%08lx",
|
||||
i,
|
||||
(uint32_t)(key >> 32),
|
||||
(uint32_t)key);
|
||||
if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) {
|
||||
mf_classic_set_key_found(data, i, MfClassicKeyB, key);
|
||||
FURI_LOG_D(TAG, "Key found");
|
||||
nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context);
|
||||
}
|
||||
}
|
||||
|
||||
if(mf_classic_is_sector_read(data, i)) continue;
|
||||
mf_classic_read_sector(tx_rx, data, i);
|
||||
} else {
|
||||
if(!card_removed_notified) {
|
||||
nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
|
||||
card_removed_notified = true;
|
||||
card_found_notified = false;
|
||||
}
|
||||
}
|
||||
if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) {
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Trying B key for sector %d, key: %04lx%08lx",
|
||||
i,
|
||||
(uint32_t)(key >> 32),
|
||||
(uint32_t)key);
|
||||
if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) {
|
||||
mf_classic_set_key_found(data, i, MfClassicKeyB, key);
|
||||
FURI_LOG_D(TAG, "Key found");
|
||||
nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context);
|
||||
}
|
||||
}
|
||||
if(mf_classic_is_sector_read(data, i)) continue;
|
||||
mf_classic_read_sector(tx_rx, data, i);
|
||||
if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break;
|
||||
}
|
||||
}
|
||||
@@ -603,6 +642,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
|
||||
&nfc_worker->dev_data->mf_classic_dict_attack_data;
|
||||
uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type);
|
||||
uint64_t key = 0;
|
||||
uint64_t prev_key = 0;
|
||||
FuriHalNfcTxRxContext tx_rx = {};
|
||||
bool card_found_notified = true;
|
||||
bool card_removed_notified = false;
|
||||
@@ -637,6 +677,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
|
||||
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
||||
card_found_notified = true;
|
||||
card_removed_notified = false;
|
||||
nfc_worker_mf_classic_key_attack(nfc_worker, prev_key, &tx_rx, i);
|
||||
}
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
@@ -673,6 +714,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
|
||||
}
|
||||
if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break;
|
||||
}
|
||||
memcpy(&prev_key, &key, sizeof(key));
|
||||
}
|
||||
if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break;
|
||||
mf_classic_read_sector(&tx_rx, data, i);
|
||||
|
||||
+5
-13
@@ -182,7 +182,7 @@ static bool emv_decode_response(uint8_t* buff, uint16_t len, EmvApplication* app
|
||||
return success;
|
||||
}
|
||||
|
||||
bool emv_select_ppse(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||
static bool emv_select_ppse(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||
bool app_aid_found = false;
|
||||
const uint8_t emv_select_ppse_cmd[] = {
|
||||
0x00, 0xA4, // SELECT ppse
|
||||
@@ -212,8 +212,8 @@ bool emv_select_ppse(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||
return app_aid_found;
|
||||
}
|
||||
|
||||
bool emv_select_app(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||
bool select_app_success = false;
|
||||
static bool emv_select_app(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||
app->app_started = false;
|
||||
const uint8_t emv_select_header[] = {
|
||||
0x00,
|
||||
0xA4, // SELECT application
|
||||
@@ -236,7 +236,7 @@ bool emv_select_app(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
|
||||
emv_trace(tx_rx, "Start application answer:");
|
||||
if(emv_decode_response(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
|
||||
select_app_success = true;
|
||||
app->app_started = true;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed to read PAN or PDOL");
|
||||
}
|
||||
@@ -244,7 +244,7 @@ bool emv_select_app(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||
FURI_LOG_E(TAG, "Failed to start application");
|
||||
}
|
||||
|
||||
return select_app_success;
|
||||
return app->app_started;
|
||||
}
|
||||
|
||||
static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) {
|
||||
@@ -367,14 +367,6 @@ static bool emv_read_files(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||
return card_num_read;
|
||||
}
|
||||
|
||||
bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
|
||||
furi_assert(tx_rx);
|
||||
furi_assert(emv_app);
|
||||
memset(emv_app, 0, sizeof(EmvApplication));
|
||||
|
||||
return emv_select_ppse(tx_rx, emv_app);
|
||||
}
|
||||
|
||||
bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
|
||||
furi_assert(tx_rx);
|
||||
furi_assert(emv_app);
|
||||
|
||||
@@ -45,6 +45,7 @@ typedef struct {
|
||||
uint8_t priority;
|
||||
uint8_t aid[16];
|
||||
uint8_t aid_len;
|
||||
bool app_started;
|
||||
char name[32];
|
||||
bool name_found;
|
||||
uint8_t card_number[10];
|
||||
@@ -68,15 +69,6 @@ typedef struct {
|
||||
*/
|
||||
bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app);
|
||||
|
||||
/** Search for EMV Application
|
||||
*
|
||||
* @param tx_rx FuriHalNfcTxRxContext instance
|
||||
* @param emv_app EmvApplication instance
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app);
|
||||
|
||||
/** Emulate bank card
|
||||
* @note Answer to application selection and PDOL
|
||||
*
|
||||
|
||||
@@ -155,6 +155,16 @@ void mf_classic_set_key_found(
|
||||
}
|
||||
}
|
||||
|
||||
void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) {
|
||||
furi_assert(data);
|
||||
|
||||
if(key_type == MfClassicKeyA) {
|
||||
FURI_BIT_CLEAR(data->key_a_mask, sector_num);
|
||||
} else if(key_type == MfClassicKeyB) {
|
||||
FURI_BIT_CLEAR(data->key_b_mask, sector_num);
|
||||
}
|
||||
}
|
||||
|
||||
bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) {
|
||||
furi_assert(data);
|
||||
|
||||
@@ -203,6 +213,18 @@ void mf_classic_get_read_sectors_and_keys(
|
||||
}
|
||||
}
|
||||
|
||||
bool mf_classic_is_card_read(MfClassicData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type);
|
||||
uint8_t sectors_read = 0;
|
||||
uint8_t keys_found = 0;
|
||||
mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found);
|
||||
bool card_read = (sectors_read == sectors_total) && (keys_found == sectors_total * 2);
|
||||
|
||||
return card_read;
|
||||
}
|
||||
|
||||
static bool mf_classic_is_allowed_access_sector_trailer(
|
||||
MfClassicEmulator* emulator,
|
||||
uint8_t block_num,
|
||||
@@ -612,7 +634,15 @@ static bool mf_classic_read_sector_with_reader(
|
||||
}
|
||||
|
||||
// Auth to first block in sector
|
||||
if(!mf_classic_auth(tx_rx, first_block, key, key_type, crypto)) break;
|
||||
if(!mf_classic_auth(tx_rx, first_block, key, key_type, crypto)) {
|
||||
// Set key to MF_CLASSIC_NO_KEY to prevent further attempts
|
||||
if(key_type == MfClassicKeyA) {
|
||||
sector_reader->key_a = MF_CLASSIC_NO_KEY;
|
||||
} else {
|
||||
sector_reader->key_b = MF_CLASSIC_NO_KEY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
sector->total_blocks = mf_classic_get_blocks_num_in_sector(sector_reader->sector_num);
|
||||
|
||||
// Read blocks
|
||||
@@ -711,6 +741,13 @@ uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data
|
||||
mf_classic_set_block_read(data, first_block + j, &temp_sector.block[j]);
|
||||
}
|
||||
sectors_read++;
|
||||
} else {
|
||||
// Invalid key, set it to not found
|
||||
if(key_a != MF_CLASSIC_NO_KEY) {
|
||||
mf_classic_set_key_not_found(data, i, MfClassicKeyA);
|
||||
} else {
|
||||
mf_classic_set_key_not_found(data, i, MfClassicKeyB);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,12 +98,16 @@ void mf_classic_set_key_found(
|
||||
MfClassicKey key_type,
|
||||
uint64_t key);
|
||||
|
||||
void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type);
|
||||
|
||||
bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num);
|
||||
|
||||
void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data);
|
||||
|
||||
bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num);
|
||||
|
||||
bool mf_classic_is_card_read(MfClassicData* data);
|
||||
|
||||
void mf_classic_get_read_sectors_and_keys(
|
||||
MfClassicData* data,
|
||||
uint8_t* sectors_read,
|
||||
|
||||
Reference in New Issue
Block a user