| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- #include "gen2_poller_i.h"
- #include <nfc/helpers/nfc_data_generator.h>
- #include <furi/furi.h>
- #define GEN2_POLLER_THREAD_FLAG_DETECTED (1U << 0)
- #define TAG "GEN2"
- typedef NfcCommand (*Gen2PollerStateHandler)(Gen2Poller* instance);
- typedef struct {
- NfcPoller* poller;
- BitBuffer* tx_buffer;
- BitBuffer* rx_buffer;
- FuriThreadId thread_id;
- bool detected;
- Gen2PollerError error;
- } Gen2PollerDetectContext;
- // Array of known Gen2 ATS responses
- // 0978009102DABC1910F005 - flavour 2
- // 0978009102DABC1910F005 - flavour 4
- // 0D780071028849A13020150608563D - flavour 6
- // Other flavours can't be detected other than by just trying to write to block 0
- const uint8_t GEN2_ATS[3][16] = {
- {0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0xF0, 0x05},
- {0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0xF0, 0x05},
- {0x0D, 0x78, 0x00, 0x71, 0x02, 0x88, 0x49, 0xA1, 0x30, 0x20, 0x15, 0x06, 0x08, 0x56, 0x3D}};
- static const MfClassicBlock gen2_poller_default_block_0 = {
- .data =
- {0x00,
- 0x01,
- 0x02,
- 0x03,
- 0x00, // BCC - IMPORTANT
- 0x08, // SAK
- 0x04, // ATQA0
- 0x00, // ATQA1
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00},
- };
- static const MfClassicBlock gen2_poller_default_empty_block = {
- .data =
- {0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00},
- };
- static MfClassicBlock gen2_poller_default_sector_trailer_block = {
- .data =
- {0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0x07,
- 0x80,
- 0x69,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF},
- };
- const char* const gen2_problem_strings[] = {
- "UID may be non-\nrewritable. Check data after writing",
- "No data in selected file",
- "Some sectors are locked",
- "Can't find keys to some sectors",
- "The selected file is incomplete",
- };
- Gen2Poller* gen2_poller_alloc(Nfc* nfc) {
- Gen2Poller* instance = malloc(sizeof(Gen2Poller));
- instance->poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a);
- instance->data = mf_classic_alloc();
- instance->crypto = crypto1_alloc();
- instance->tx_plain_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
- instance->tx_encrypted_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
- instance->rx_plain_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
- instance->rx_encrypted_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE);
- instance->card_state = Gen2CardStateLost;
- instance->gen2_event.data = &instance->gen2_event_data;
- instance->mode_ctx.write_ctx.mfc_data_source = malloc(sizeof(MfClassicData));
- instance->mode_ctx.write_ctx.mfc_data_target = malloc(sizeof(MfClassicData));
- instance->mode_ctx.write_ctx.need_halt_before_write = true;
- return instance;
- }
- void gen2_poller_free(Gen2Poller* instance) {
- furi_assert(instance);
- furi_assert(instance->data);
- furi_assert(instance->crypto);
- furi_assert(instance->tx_plain_buffer);
- furi_assert(instance->rx_plain_buffer);
- furi_assert(instance->tx_encrypted_buffer);
- furi_assert(instance->rx_encrypted_buffer);
- nfc_poller_free(instance->poller);
- mf_classic_free(instance->data);
- crypto1_free(instance->crypto);
- bit_buffer_free(instance->tx_plain_buffer);
- bit_buffer_free(instance->rx_plain_buffer);
- bit_buffer_free(instance->tx_encrypted_buffer);
- bit_buffer_free(instance->rx_encrypted_buffer);
- free(instance->mode_ctx.write_ctx.mfc_data_source);
- free(instance->mode_ctx.write_ctx.mfc_data_target);
- free(instance);
- }
- NfcCommand gen2_poller_detect_callback(NfcGenericEvent event, void* context) {
- furi_assert(context);
- furi_assert(event.protocol == NfcProtocolIso14443_3a);
- furi_assert(event.event_data);
- furi_assert(event.instance);
- NfcCommand command = NfcCommandStop;
- Gen2PollerDetectContext* detect_ctx = context;
- Iso14443_3aPoller* iso3_poller = event.instance;
- Iso14443_3aPollerEvent* iso3_event = event.event_data;
- detect_ctx->error = Gen2PollerErrorTimeout;
- bit_buffer_reset(detect_ctx->tx_buffer);
- bit_buffer_append_byte(detect_ctx->tx_buffer, GEN2_CMD_READ_ATS);
- bit_buffer_append_byte(detect_ctx->tx_buffer, GEN2_FSDI_256 << 4);
- if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
- do {
- const Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standard_frame(
- iso3_poller, detect_ctx->tx_buffer, detect_ctx->rx_buffer, GEN2_POLLER_MAX_FWT);
- if(iso14443_3a_error != Iso14443_3aErrorNone &&
- iso14443_3a_error != Iso14443_3aErrorWrongCrc) {
- FURI_LOG_E(TAG, "ATS request failed");
- detect_ctx->error = Gen2PollerErrorProtocol;
- break;
- } else {
- FURI_LOG_D(TAG, "ATS request succeeded:");
- // Check against known ATS responses
- for(size_t i = 0; i < COUNT_OF(GEN2_ATS); i++) {
- if(memcmp(
- bit_buffer_get_data(detect_ctx->rx_buffer),
- GEN2_ATS[i],
- sizeof(GEN2_ATS[i])) == 0) {
- detect_ctx->error = Gen2PollerErrorNone;
- break;
- }
- }
- }
- } while(false);
- } else if(iso3_event->type == Iso14443_3aPollerEventTypeError) {
- detect_ctx->error = Gen2PollerErrorTimeout;
- }
- furi_thread_flags_set(detect_ctx->thread_id, GEN2_POLLER_THREAD_FLAG_DETECTED);
- return command;
- }
- Gen2PollerError gen2_poller_detect(Nfc* nfc) {
- furi_assert(nfc);
- Gen2PollerDetectContext detect_ctx = {
- .poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a),
- .tx_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE),
- .rx_buffer = bit_buffer_alloc(GEN2_POLLER_MAX_BUFFER_SIZE),
- .thread_id = furi_thread_get_current_id(),
- .detected = false,
- .error = Gen2PollerErrorNone,
- };
- nfc_poller_start(detect_ctx.poller, gen2_poller_detect_callback, &detect_ctx);
- uint32_t flags =
- furi_thread_flags_wait(GEN2_POLLER_THREAD_FLAG_DETECTED, FuriFlagWaitAny, FuriWaitForever);
- if(flags & GEN2_POLLER_THREAD_FLAG_DETECTED) {
- furi_thread_flags_clear(GEN2_POLLER_THREAD_FLAG_DETECTED);
- }
- nfc_poller_stop(detect_ctx.poller);
- bit_buffer_free(detect_ctx.tx_buffer);
- bit_buffer_free(detect_ctx.rx_buffer);
- nfc_poller_free(detect_ctx.poller);
- return detect_ctx.error;
- }
- NfcCommand gen2_poller_idle_handler(Gen2Poller* instance) {
- furi_assert(instance);
- NfcCommand command = NfcCommandContinue;
- instance->mode_ctx.write_ctx.current_block = 0;
- instance->gen2_event.type = Gen2PollerEventTypeDetected;
- command = instance->callback(instance->gen2_event, instance->context);
- instance->state = Gen2PollerStateRequestMode;
- return command;
- }
- NfcCommand gen2_poller_request_mode_handler(Gen2Poller* instance) {
- furi_assert(instance);
- NfcCommand command = NfcCommandContinue;
- instance->gen2_event.type = Gen2PollerEventTypeRequestMode;
- command = instance->callback(instance->gen2_event, instance->context);
- instance->mode = instance->gen2_event_data.poller_mode.mode;
- if(instance->gen2_event_data.poller_mode.mode == Gen2PollerModeWipe) {
- instance->state = Gen2PollerStateWriteTargetDataRequest;
- } else {
- instance->state = Gen2PollerStateWriteSourceDataRequest;
- }
- return command;
- }
- NfcCommand gen2_poller_write_source_data_request_handler(Gen2Poller* instance) {
- NfcCommand command = NfcCommandContinue;
- instance->gen2_event.type = Gen2PollerEventTypeRequestDataToWrite;
- command = instance->callback(instance->gen2_event, instance->context);
- memcpy(
- instance->mode_ctx.write_ctx.mfc_data_source,
- instance->gen2_event_data.data_to_write.mfc_data,
- sizeof(MfClassicData));
- instance->state = Gen2PollerStateWriteTargetDataRequest;
- return command;
- }
- NfcCommand gen2_poller_write_target_data_request_handler(Gen2Poller* instance) {
- NfcCommand command = NfcCommandContinue;
- instance->gen2_event.type = Gen2PollerEventTypeRequestTargetData;
- command = instance->callback(instance->gen2_event, instance->context);
- memcpy(
- instance->mode_ctx.write_ctx.mfc_data_target,
- instance->gen2_event_data.target_data.mfc_data,
- sizeof(MfClassicData));
- if(instance->mode == Gen2PollerModeWipe) {
- instance->state = Gen2PollerStateWipe;
- } else {
- instance->state = Gen2PollerStateWrite;
- }
- return command;
- }
- Gen2PollerError gen2_poller_write_block_handler(
- Gen2Poller* instance,
- uint8_t block_num,
- const MfClassicBlock* block) {
- furi_assert(instance);
- Gen2PollerError error = Gen2PollerErrorNone;
- Gen2PollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx;
- MfClassicKey auth_key = write_ctx->auth_key;
- do {
- // Compare the target and source data
- if(memcmp(block->data, write_ctx->mfc_data_target->block[block_num].data, 16) == 0) {
- FURI_LOG_D(TAG, "Block %d is the same, skipping", block_num);
- break;
- }
- // Reauth if necessary
- if(write_ctx->need_halt_before_write) {
- FURI_LOG_D(TAG, "Auth before writing block %d", write_ctx->current_block);
- error = gen2_poller_auth(
- instance, write_ctx->current_block, &auth_key, write_ctx->write_key, NULL);
- if(error != Gen2PollerErrorNone) {
- FURI_LOG_D(
- TAG, "Failed to auth to block %d for writing", write_ctx->current_block);
- break;
- }
- }
- // Write the block
- error = gen2_poller_write_block(instance, write_ctx->current_block, block);
- if(error != Gen2PollerErrorNone) {
- FURI_LOG_D(TAG, "Failed to write block %d", write_ctx->current_block);
- break;
- }
- } while(false);
- FURI_LOG_D(TAG, "Block %d finished, halting", write_ctx->current_block);
- gen2_poller_halt(instance);
- return error;
- }
- NfcCommand gen2_poller_wipe_handler(Gen2Poller* instance) {
- NfcCommand command = NfcCommandContinue;
- Gen2PollerError error = Gen2PollerErrorNone;
- Gen2PollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx;
- uint8_t block_num = write_ctx->current_block;
- do {
- // Check whether the ACs for that block are known in target data
- if(!mf_classic_is_block_read(
- write_ctx->mfc_data_target,
- mf_classic_get_sector_trailer_num_by_block(block_num))) {
- FURI_LOG_E(TAG, "Sector trailer for block %d not present in target data", block_num);
- break;
- }
- // Check whether ACs need to be reset and whether they can be reset
- if(!gen2_poller_can_write_block(write_ctx->mfc_data_target, block_num)) {
- if(!gen2_can_reset_access_conditions(write_ctx->mfc_data_target, block_num)) {
- FURI_LOG_E(TAG, "Block %d cannot be written", block_num);
- break;
- } else {
- FURI_LOG_D(TAG, "Resetting ACs for block %d", block_num);
- // Generate a block with old keys and default ACs (0xFF, 0x07, 0x80)
- MfClassicBlock block;
- memset(&block, 0, sizeof(block));
- memcpy(block.data, write_ctx->mfc_data_target->block[block_num].data, 16);
- memcpy(block.data + 6, "\xFF\x07\x80", 3);
- error = gen2_poller_write_block_handler(instance, block_num, &block);
- if(error != Gen2PollerErrorNone) {
- FURI_LOG_E(TAG, "Failed to reset ACs for block %d", block_num);
- break;
- } else {
- FURI_LOG_D(TAG, "ACs for block %d reset", block_num);
- memcpy(write_ctx->mfc_data_target->block[block_num].data, block.data, 16);
- }
- }
- }
- // Figure out which key to use for writing
- write_ctx->write_key =
- gen2_poller_get_key_type_to_write(write_ctx->mfc_data_target, block_num);
- // Get the key to use for writing from the target data
- MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(
- write_ctx->mfc_data_target, mf_classic_get_sector_by_block(block_num));
- if(write_ctx->write_key == MfClassicKeyTypeA) {
- write_ctx->auth_key = sec_tr->key_a;
- } else {
- write_ctx->auth_key = sec_tr->key_b;
- }
- // Write the default block depending on the block type
- if(block_num == 0) {
- error =
- gen2_poller_write_block_handler(instance, block_num, &gen2_poller_default_block_0);
- } else if(mf_classic_is_sector_trailer(block_num)) {
- error = gen2_poller_write_block_handler(
- instance, block_num, &gen2_poller_default_sector_trailer_block);
- } else {
- error = gen2_poller_write_block_handler(
- instance, block_num, &gen2_poller_default_empty_block);
- }
- if(error != Gen2PollerErrorNone) {
- FURI_LOG_E(TAG, "Couldn't write block %d", block_num);
- }
- } while(false);
- write_ctx->current_block++;
- if(error != Gen2PollerErrorNone) {
- FURI_LOG_D(TAG, "Error occurred: %d", error);
- }
- if(write_ctx->current_block ==
- mf_classic_get_total_block_num(write_ctx->mfc_data_target->type)) {
- instance->state = Gen2PollerStateSuccess;
- }
- return command;
- }
- NfcCommand gen2_poller_write_handler(Gen2Poller* instance) {
- NfcCommand command = NfcCommandContinue;
- Gen2PollerError error = Gen2PollerErrorNone;
- Gen2PollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx;
- uint8_t block_num = write_ctx->current_block;
- do {
- // Check whether the block is present in the source data
- if(!mf_classic_is_block_read(write_ctx->mfc_data_source, block_num)) {
- // FURI_LOG_E(TAG, "Block %d not present in source data", block_num);
- break;
- }
- // Check whether the ACs for that block are known in target data
- if(!mf_classic_is_block_read(
- write_ctx->mfc_data_target,
- mf_classic_get_sector_trailer_num_by_block(block_num))) {
- FURI_LOG_E(TAG, "Sector trailer for block %d not present in target data", block_num);
- break;
- }
- // Check whether ACs need to be reset and whether they can be reset
- if(!gen2_poller_can_write_block(write_ctx->mfc_data_target, block_num)) {
- if(!gen2_can_reset_access_conditions(write_ctx->mfc_data_target, block_num)) {
- FURI_LOG_E(TAG, "Block %d cannot be written", block_num);
- break;
- } else {
- FURI_LOG_D(TAG, "Resetting ACs for block %d", block_num);
- // Generate a block with old keys and default ACs (0xFF, 0x07, 0x80)
- MfClassicBlock block;
- memset(&block, 0, sizeof(block));
- memcpy(block.data, write_ctx->mfc_data_target->block[block_num].data, 16);
- memcpy(block.data + 6, "\xFF\x07\x80", 3);
- error = gen2_poller_write_block_handler(instance, block_num, &block);
- if(error != Gen2PollerErrorNone) {
- FURI_LOG_E(TAG, "Failed to reset ACs for block %d", block_num);
- break;
- } else {
- FURI_LOG_D(TAG, "ACs for block %d reset", block_num);
- memcpy(write_ctx->mfc_data_target->block[block_num].data, block.data, 16);
- }
- }
- }
- // Figure out which key to use for writing
- write_ctx->write_key =
- gen2_poller_get_key_type_to_write(write_ctx->mfc_data_target, block_num);
- // Get the key to use for writing from the target data
- MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(
- write_ctx->mfc_data_target, mf_classic_get_sector_by_block(block_num));
- if(write_ctx->write_key == MfClassicKeyTypeA) {
- write_ctx->auth_key = sec_tr->key_a;
- } else {
- write_ctx->auth_key = sec_tr->key_b;
- }
- // Write the block
- error = gen2_poller_write_block_handler(
- instance, block_num, &write_ctx->mfc_data_source->block[block_num]);
- if(error != Gen2PollerErrorNone) {
- FURI_LOG_E(TAG, "Couldn't write block %d", block_num);
- }
- } while(false);
- write_ctx->current_block++;
- if(error != Gen2PollerErrorNone) {
- FURI_LOG_D(TAG, "Error occurred: %d", error);
- } else if(
- write_ctx->current_block ==
- mf_classic_get_total_block_num(write_ctx->mfc_data_source->type)) {
- instance->state = Gen2PollerStateSuccess;
- }
- return command;
- }
- NfcCommand gen2_poller_success_handler(Gen2Poller* instance) {
- furi_assert(instance);
- NfcCommand command = NfcCommandContinue;
- instance->gen2_event.type = Gen2PollerEventTypeSuccess;
- command = instance->callback(instance->gen2_event, instance->context);
- instance->state = Gen2PollerStateIdle;
- return command;
- }
- NfcCommand gen2_poller_fail_handler(Gen2Poller* instance) {
- furi_assert(instance);
- NfcCommand command = NfcCommandContinue;
- instance->gen2_event.type = Gen2PollerEventTypeFail;
- command = instance->callback(instance->gen2_event, instance->context);
- instance->state = Gen2PollerStateIdle;
- return command;
- }
- static const Gen2PollerStateHandler gen2_poller_state_handlers[Gen2PollerStateNum] = {
- [Gen2PollerStateIdle] = gen2_poller_idle_handler,
- [Gen2PollerStateRequestMode] = gen2_poller_request_mode_handler,
- [Gen2PollerStateWipe] = gen2_poller_wipe_handler,
- [Gen2PollerStateWriteSourceDataRequest] = gen2_poller_write_source_data_request_handler,
- [Gen2PollerStateWriteTargetDataRequest] = gen2_poller_write_target_data_request_handler,
- [Gen2PollerStateWrite] = gen2_poller_write_handler,
- [Gen2PollerStateSuccess] = gen2_poller_success_handler,
- [Gen2PollerStateFail] = gen2_poller_fail_handler,
- };
- NfcCommand gen2_poller_callback(NfcGenericEvent event, void* context) {
- furi_assert(context);
- furi_assert(event.protocol == NfcProtocolIso14443_3a);
- furi_assert(event.event_data);
- furi_assert(event.instance);
- NfcCommand command = NfcCommandContinue;
- Gen2Poller* instance = context;
- instance->iso3_poller = event.instance;
- Iso14443_3aPollerEvent* iso3_event = event.event_data;
- if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
- command = gen2_poller_state_handlers[instance->state](instance);
- }
- return command;
- }
- void gen2_poller_start(Gen2Poller* instance, Gen2PollerCallback callback, void* context) {
- furi_assert(instance);
- furi_assert(callback);
- instance->callback = callback;
- instance->context = context;
- nfc_poller_start(instance->poller, gen2_poller_callback, instance);
- return;
- }
- void gen2_poller_stop(Gen2Poller* instance) {
- furi_assert(instance);
- FURI_LOG_D(TAG, "Stopping Gen2 poller");
- nfc_poller_stop(instance->poller);
- return;
- }
- Gen2PollerWriteProblems gen2_poller_check_target_problems(NfcDevice* target_dev) {
- furi_assert(target_dev);
- Gen2PollerWriteProblems problems = {0};
- const MfClassicData* mfc_data = nfc_device_get_data(target_dev, NfcProtocolMfClassic);
- if(mfc_data) {
- uint16_t total_block_num = mf_classic_get_total_block_num(mfc_data->type);
- for(uint16_t i = 0; i < total_block_num; i++) {
- if(mf_classic_is_sector_trailer(i)) {
- problems.all_problems |=
- gen2_poller_can_write_sector_trailer(mfc_data, i).all_problems;
- } else {
- problems.all_problems |=
- gen2_poller_can_write_data_block(mfc_data, i).all_problems;
- }
- }
- } else {
- problems.no_data = true;
- }
- return problems;
- }
- Gen2PollerWriteProblems gen2_poller_check_source_problems(NfcDevice* source_dev) {
- furi_assert(source_dev);
- Gen2PollerWriteProblems problems = {0};
- const MfClassicData* mfc_data = nfc_device_get_data(source_dev, NfcProtocolMfClassic);
- if(mfc_data) {
- uint16_t total_block_num = mf_classic_get_total_block_num(mfc_data->type);
- for(uint16_t i = 0; i < total_block_num; i++) {
- if(!mf_classic_is_block_read(mfc_data, i)) {
- problems.missing_source_data = true;
- }
- }
- }
- return problems;
- }
|