| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- #include "picopass_i.h"
- #include "picopass_poller_i.h"
- #include "../loclass/optimized_cipher.h"
- #include <furi/furi.h>
- #include <toolbox/version.h>
- #define TAG "Picopass"
- typedef NfcCommand (*PicopassPollerStateHandler)(PicopassPoller* instance);
- static void picopass_poller_reset(PicopassPoller* instance) {
- instance->current_block = 0;
- }
- static void picopass_poller_prepare_read(PicopassPoller* instance) {
- instance->app_limit = instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[0] <
- PICOPASS_MAX_APP_LIMIT ?
- instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
- PICOPASS_MAX_APP_LIMIT;
- instance->current_block = 2;
- }
- NfcCommand picopass_poller_request_mode_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- instance->event.type = PicopassPollerEventTypeRequestMode;
- command = instance->callback(instance->event, instance->context);
- instance->mode = instance->event_data.req_mode.mode;
- instance->state = PicopassPollerStateDetect;
- return command;
- }
- NfcCommand picopass_poller_detect_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- PicopassError error = picopass_poller_actall(instance);
- if(error == PicopassErrorNone) {
- instance->state = PicopassPollerStateSelect;
- instance->event.type = PicopassPollerEventTypeCardDetected;
- command = instance->callback(instance->event, instance->context);
- } else {
- furi_delay_ms(100);
- }
- return command;
- }
- NfcCommand picopass_poller_select_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- do {
- PicopassError error = picopass_poller_identify(instance, &instance->col_res_serial_num);
- if(error != PicopassErrorNone) {
- instance->state = PicopassPollerStateFail;
- break;
- }
- error =
- picopass_poller_select(instance, &instance->col_res_serial_num, &instance->serial_num);
- if(error != PicopassErrorNone) {
- instance->state = PicopassPollerStateFail;
- break;
- }
- instance->state = PicopassPollerStatePreAuth;
- } while(false);
- return command;
- }
- void picopass_poller_print_block(char* str, PicopassBlock block) {
- FURI_LOG_D(
- TAG,
- str,
- block.data[0],
- block.data[1],
- block.data[2],
- block.data[3],
- block.data[4],
- block.data[5],
- block.data[6],
- block.data[7]);
- }
- NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- PicopassError error = PicopassErrorNone;
- // Print version information for app and firmware for later review in log
- const Version* version = version_get();
- FURI_LOG_I(
- TAG,
- "Firmware origin: %s firmware version: %s app version: %s",
- version_get_firmware_origin(version),
- version_get_version(version),
- FAP_VERSION);
- do {
- memcpy(
- instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
- instance->serial_num.data,
- sizeof(PicopassSerialNum));
- instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].valid = true;
- picopass_poller_print_block(
- "csn %02x%02x%02x%02x%02x%02x%02x%02x",
- instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX]);
- PicopassBlock block = {};
- error = picopass_poller_read_block(instance, PICOPASS_CONFIG_BLOCK_INDEX, &block);
- if(error != PicopassErrorNone) {
- instance->state = PicopassPollerStateFail;
- break;
- }
- memcpy(
- instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data,
- block.data,
- PICOPASS_BLOCK_LEN);
- instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].valid = true;
- picopass_poller_print_block(
- "config %02x%02x%02x%02x%02x%02x%02x%02x",
- instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX]);
- error = picopass_poller_read_block(instance, PICOPASS_SECURE_EPURSE_BLOCK_INDEX, &block);
- if(error != PicopassErrorNone) {
- instance->state = PicopassPollerStateFail;
- break;
- }
- memcpy(
- instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data,
- block.data,
- PICOPASS_BLOCK_LEN);
- instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].valid = true;
- picopass_poller_print_block(
- "epurse %02x%02x%02x%02x%02x%02x%02x%02x",
- instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX]);
- error = picopass_poller_read_block(instance, PICOPASS_SECURE_AIA_BLOCK_INDEX, &block);
- if(error != PicopassErrorNone) {
- instance->state = PicopassPollerStateFail;
- break;
- }
- memcpy(
- instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
- block.data,
- PICOPASS_BLOCK_LEN);
- instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].valid = true;
- picopass_poller_print_block(
- "aia %02x%02x%02x%02x%02x%02x%02x%02x",
- instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX]);
- instance->state = PicopassPollerStateCheckSecurity;
- } while(false);
- return command;
- }
- NfcCommand picopass_poller_check_security(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- instance->secured = true;
- uint8_t crypt =
- (instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[7] & PICOPASS_FUSE_CRYPT10);
- switch(crypt) {
- case 0:
- FURI_LOG_D(TAG, "Secured page - Authentication disabled");
- // Well this is awkward... We can try anyway though I guess...
- break;
- case PICOPASS_FUSE_CRYPT0:
- FURI_LOG_D(TAG, "Non-secured page, skipping auth");
- instance->secured = false;
- instance->data->auth = PicopassDeviceAuthMethodNone;
- picopass_poller_prepare_read(instance);
- instance->state = PicopassPollerStateReadBlock;
- return command;
- case PICOPASS_FUSE_CRYPT0 | PICOPASS_FUSE_CRYPT1:
- FURI_LOG_D(TAG, "Secured page - keys modifiable");
- break;
- case PICOPASS_FUSE_CRYPT1:
- FURI_LOG_D(TAG, "Secured page - keys locked");
- }
- // Thank you proxmark!
- PicopassBlock temp_block = {};
- memset(temp_block.data, 0xff, PICOPASS_BLOCK_LEN);
- instance->data->pacs.legacy =
- (memcmp(
- instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
- temp_block.data,
- PICOPASS_BLOCK_LEN) == 0);
- temp_block.data[3] = 0x00;
- temp_block.data[4] = 0x06;
- instance->data->pacs.se_enabled =
- (memcmp(
- instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
- temp_block.data,
- PICOPASS_BLOCK_LEN) == 0);
- if(instance->data->pacs.se_enabled) {
- FURI_LOG_D(TAG, "SE enabled");
- }
- // Assume failure since we must auth, correct value will be set on success
- instance->data->auth = PicopassDeviceAuthMethodFailed;
- if(instance->mode == PicopassPollerModeRead) {
- // Always try the NR-MAC auth in case we have the file.
- instance->state = PicopassPollerStateNrMacAuth;
- } else {
- // NR-MAC auth doesn't allow for writing, so don't try
- instance->state = PicopassPollerStateAuth;
- }
- return command;
- }
- NfcCommand picopass_poller_nr_mac_auth(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- Picopass* picopass = instance->context;
- PicopassDevice* dev = picopass->dev;
- uint8_t* csn = instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data;
- uint8_t* epurse = instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data;
- FuriString* temp_str = furi_string_alloc();
- FuriString* filename = furi_string_alloc();
- FlipperFormat* file = flipper_format_file_alloc(dev->storage);
- PicopassMac mac = {};
- for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
- furi_string_cat_printf(filename, "%02x", csn[i]);
- }
- furi_string_cat_printf(filename, "_");
- for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
- furi_string_cat_printf(filename, "%02x", epurse[i]);
- }
- furi_string_printf(
- temp_str, "%s/%s%s", STORAGE_APP_DATA_PATH_PREFIX, furi_string_get_cstr(filename), ".mac");
- FURI_LOG_D(TAG, "Looking for %s", furi_string_get_cstr(temp_str));
- uint8_t nr_mac[PICOPASS_BLOCK_LEN];
- // Set next state so breaking do/while will jump to it. If successful, do/while will set to ReadBlock
- if(instance->data->pacs.se_enabled) {
- instance->state = PicopassPollerStateAuthFail;
- } else {
- // For non-SE, run through normal key check
- instance->state = PicopassPollerStateAuth;
- }
- do {
- //check for file
- if(!flipper_format_file_open_existing(file, furi_string_get_cstr(temp_str))) break;
- // FURI_LOG_D(TAG, "Found %s", furi_string_get_cstr(temp_str));
- furi_string_printf(temp_str, "NR-MAC");
- if(!flipper_format_read_hex(
- file, furi_string_get_cstr(temp_str), nr_mac, PICOPASS_BLOCK_LEN))
- break;
- memcpy(mac.data, nr_mac + 4, PICOPASS_MAC_LEN);
- /*
- FURI_LOG_D(
- TAG,
- "Read nr-mac: %02x %02x %02x %02x %02x %02x %02x %02x",
- nr_mac[0],
- nr_mac[1],
- nr_mac[2],
- nr_mac[3],
- nr_mac[4],
- nr_mac[5],
- nr_mac[6],
- nr_mac[7]);
- FURI_LOG_D(
- TAG, "MAC: %02x %02x %02x %02x", mac.data[0], mac.data[1], mac.data[2], mac.data[3]);
- */
- uint8_t ccnr[12] = {};
- PicopassReadCheckResp read_check_resp = {};
- PicopassError error = picopass_poller_read_check(instance, &read_check_resp);
- if(error == PicopassErrorTimeout) {
- instance->event.type = PicopassPollerEventTypeCardLost;
- instance->callback(instance->event, instance->context);
- instance->state = PicopassPollerStateDetect;
- break;
- } else if(error != PicopassErrorNone) {
- FURI_LOG_E(TAG, "Read check failed: %d", error);
- break;
- }
- memcpy(ccnr, read_check_resp.data, sizeof(PicopassReadCheckResp)); // last 4 bytes left 0
- /*
- FURI_LOG_D(
- TAG,
- "CCNR: %02x %02x %02x %02x %02x %02x %02x %02x",
- ccnr[0],
- ccnr[1],
- ccnr[2],
- ccnr[3],
- ccnr[4],
- ccnr[5],
- ccnr[6],
- ccnr[7]);
- */
- //use mac
- PicopassCheckResp check_resp = {};
- error = picopass_poller_check(instance, nr_mac, &mac, &check_resp);
- if(error == PicopassErrorNone) {
- instance->data->auth = PicopassDeviceAuthMethodNrMac;
- memcpy(instance->mac.data, mac.data, sizeof(PicopassMac));
- if(instance->mode == PicopassPollerModeRead) {
- picopass_poller_prepare_read(instance);
- instance->state = PicopassPollerStateReadBlock;
- }
- }
- } while(false);
- furi_string_free(temp_str);
- furi_string_free(filename);
- flipper_format_free(file);
- return command;
- }
- NfcCommand picopass_poller_auth_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- do {
- // Request key
- instance->event.type = PicopassPollerEventTypeRequestKey;
- command = instance->callback(instance->event, instance->context);
- if(command != NfcCommandContinue) break;
- if(!instance->event_data.req_key.is_key_provided) {
- instance->state = PicopassPollerStateAuthFail;
- break;
- }
- FURI_LOG_D(
- TAG,
- "Try to %s auth with key %02x%02x%02x%02x%02x%02x%02x%02x",
- instance->event_data.req_key.is_elite_key ? "elite" : "standard",
- instance->event_data.req_key.key[0],
- instance->event_data.req_key.key[1],
- instance->event_data.req_key.key[2],
- instance->event_data.req_key.key[3],
- instance->event_data.req_key.key[4],
- instance->event_data.req_key.key[5],
- instance->event_data.req_key.key[6],
- instance->event_data.req_key.key[7]);
- PicopassReadCheckResp read_check_resp = {};
- uint8_t* csn = instance->serial_num.data;
- memset(instance->div_key, 0, sizeof(instance->div_key));
- uint8_t* div_key = NULL;
- if(instance->mode == PicopassPollerModeRead) {
- div_key = instance->data->card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data;
- } else {
- div_key = instance->div_key;
- }
- uint8_t ccnr[12] = {};
- PicopassMac mac = {};
- PicopassError error = picopass_poller_read_check(instance, &read_check_resp);
- if(error == PicopassErrorTimeout) {
- instance->event.type = PicopassPollerEventTypeCardLost;
- command = instance->callback(instance->event, instance->context);
- instance->state = PicopassPollerStateDetect;
- break;
- } else if(error != PicopassErrorNone) {
- FURI_LOG_E(TAG, "Read check failed: %d", error);
- break;
- }
- memcpy(ccnr, read_check_resp.data, sizeof(PicopassReadCheckResp)); // last 4 bytes left 0
- loclass_iclass_calc_div_key(
- csn,
- instance->event_data.req_key.key,
- div_key,
- instance->event_data.req_key.is_elite_key);
- loclass_opt_doReaderMAC(ccnr, div_key, mac.data);
- PicopassCheckResp check_resp = {};
- error = picopass_poller_check(instance, NULL, &mac, &check_resp);
- if(error == PicopassErrorNone) {
- FURI_LOG_I(TAG, "Found key");
- instance->data->auth = PicopassDeviceAuthMethodKey;
- memcpy(instance->mac.data, mac.data, sizeof(PicopassMac));
- if(instance->mode == PicopassPollerModeRead) {
- memcpy(
- instance->data->pacs.key, instance->event_data.req_key.key, PICOPASS_KEY_LEN);
- instance->data->card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid = true;
- instance->data->pacs.elite_kdf = instance->event_data.req_key.is_elite_key;
- picopass_poller_prepare_read(instance);
- instance->state = PicopassPollerStateReadBlock;
- } else if(instance->mode == PicopassPollerModeWrite) {
- instance->state = PicopassPollerStateWriteBlock;
- } else {
- instance->state = PicopassPollerStateWriteKey;
- }
- }
- } while(false);
- return command;
- }
- NfcCommand picopass_poller_read_block_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- do {
- if(instance->current_block == instance->app_limit) {
- if(instance->secured) {
- instance->state = PicopassPollerStateParseCredential;
- } else {
- instance->state = PicopassPollerStateSuccess;
- }
- break;
- }
- if(instance->secured && (instance->current_block == PICOPASS_SECURE_KD_BLOCK_INDEX ||
- instance->current_block == PICOPASS_SECURE_KC_BLOCK_INDEX)) {
- // Kd and Kc blocks cannot be read (card always returns FF's)
- // Key blocks we authed as would have been already set earlier
- instance->current_block++;
- continue;
- }
- PicopassBlock block = {};
- PicopassError error =
- picopass_poller_read_block(instance, instance->current_block, &block);
- if(error != PicopassErrorNone) {
- FURI_LOG_E(TAG, "Failed to read block %d: %d", instance->current_block, error);
- instance->state = PicopassPollerStateFail;
- break;
- }
- FURI_LOG_D(
- TAG,
- "Block %d: %02x%02x%02x%02x%02x%02x%02x%02x",
- instance->current_block,
- block.data[0],
- block.data[1],
- block.data[2],
- block.data[3],
- block.data[4],
- block.data[5],
- block.data[6],
- block.data[7]);
- memcpy(
- instance->data->card_data[instance->current_block].data,
- block.data,
- PICOPASS_BLOCK_LEN);
- instance->data->card_data[instance->current_block].valid = true;
- instance->current_block++;
- } while(false);
- return command;
- }
- NfcCommand picopass_poller_parse_credential_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- picopass_device_parse_credential(instance->data->card_data, &instance->data->pacs);
- instance->state = PicopassPollerStateParseWiegand;
- return command;
- }
- NfcCommand picopass_poller_parse_wiegand_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- picopass_device_parse_wiegand(&instance->data->pacs);
- instance->state = PicopassPollerStateSuccess;
- return command;
- }
- NfcCommand picopass_poller_write_block_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- PicopassError error = PicopassErrorNone;
- do {
- instance->event.type = PicopassPollerEventTypeRequestWriteBlock;
- command = instance->callback(instance->event, instance->context);
- if(command != NfcCommandContinue) break;
- PicopassPollerEventDataRequestWriteBlock* write_block = &instance->event_data.req_write;
- if(!write_block->perform_write) {
- instance->state = PicopassPollerStateSuccess;
- break;
- }
- FURI_LOG_D(TAG, "Writing %d block", write_block->block_num);
- uint8_t data[9] = {};
- data[0] = write_block->block_num;
- memcpy(&data[1], write_block->block->data, PICOPASS_BLOCK_LEN);
- loclass_doMAC_N(data, sizeof(data), instance->div_key, instance->mac.data);
- FURI_LOG_D(
- TAG,
- "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
- write_block->block_num,
- data[1],
- data[2],
- data[3],
- data[4],
- data[5],
- data[6],
- data[7],
- data[8],
- instance->mac.data[0],
- instance->mac.data[1],
- instance->mac.data[2],
- instance->mac.data[3]);
- error = picopass_poller_write_block(
- instance, write_block->block_num, write_block->block, &instance->mac);
- if(error != PicopassErrorNone) {
- FURI_LOG_E(TAG, "Failed to write block %d. Error %d", write_block->block_num, error);
- instance->state = PicopassPollerStateFail;
- break;
- }
- } while(false);
- return command;
- }
- NfcCommand picopass_poller_write_key_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- PicopassError error = PicopassErrorNone;
- do {
- instance->event.type = PicopassPollerEventTypeRequestWriteKey;
- command = instance->callback(instance->event, instance->context);
- if(command != NfcCommandContinue) break;
- const PicopassDeviceData* picopass_data = instance->event_data.req_write_key.data;
- const uint8_t* new_key = instance->event_data.req_write_key.key;
- bool is_elite_key = instance->event_data.req_write_key.is_elite_key;
- const uint8_t* csn = instance->serial_num.data;
- const uint8_t* old_key = instance->div_key;
- PicopassBlock new_block = {};
- loclass_iclass_calc_div_key(csn, new_key, new_block.data, is_elite_key);
- const uint8_t* config_block = picopass_data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data;
- uint8_t fuses = config_block[7];
- if((fuses & 0x80) == 0x80) {
- FURI_LOG_D(TAG, "Plain write for personalized mode key change");
- } else {
- FURI_LOG_D(TAG, "XOR write for application mode key change");
- // XOR when in application mode
- for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
- new_block.data[i] ^= old_key[i];
- }
- }
- FURI_LOG_D(TAG, "Writing key to %d block", PICOPASS_SECURE_KD_BLOCK_INDEX);
- uint8_t data[9] = {};
- data[0] = PICOPASS_SECURE_KD_BLOCK_INDEX;
- memcpy(&data[1], new_block.data, PICOPASS_BLOCK_LEN);
- loclass_doMAC_N(data, sizeof(data), instance->div_key, instance->mac.data);
- FURI_LOG_D(
- TAG,
- "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
- PICOPASS_SECURE_KD_BLOCK_INDEX,
- data[1],
- data[2],
- data[3],
- data[4],
- data[5],
- data[6],
- data[7],
- data[8],
- instance->mac.data[0],
- instance->mac.data[1],
- instance->mac.data[2],
- instance->mac.data[3]);
- error = picopass_poller_write_block(
- instance, PICOPASS_SECURE_KD_BLOCK_INDEX, &new_block, &instance->mac);
- if(error != PicopassErrorNone) {
- FURI_LOG_E(
- TAG, "Failed to write block %d. Error %d", PICOPASS_SECURE_KD_BLOCK_INDEX, error);
- instance->state = PicopassPollerStateFail;
- break;
- }
- instance->state = PicopassPollerStateSuccess;
- } while(false);
- return command;
- }
- NfcCommand picopass_poller_success_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandContinue;
- instance->event.type = PicopassPollerEventTypeSuccess;
- command = instance->callback(instance->event, instance->context);
- furi_delay_ms(100);
- return command;
- }
- NfcCommand picopass_poller_fail_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandReset;
- instance->event.type = PicopassPollerEventTypeFail;
- command = instance->callback(instance->event, instance->context);
- picopass_poller_reset(instance);
- instance->state = PicopassPollerStateDetect;
- return command;
- }
- NfcCommand picopass_poller_auth_fail_handler(PicopassPoller* instance) {
- NfcCommand command = NfcCommandReset;
- instance->event.type = PicopassPollerEventTypeAuthFail;
- command = instance->callback(instance->event, instance->context);
- picopass_poller_reset(instance);
- instance->state = PicopassPollerStateDetect;
- return command;
- }
- static const PicopassPollerStateHandler picopass_poller_state_handler[PicopassPollerStateNum] = {
- [PicopassPollerStateRequestMode] = picopass_poller_request_mode_handler,
- [PicopassPollerStateDetect] = picopass_poller_detect_handler,
- [PicopassPollerStateSelect] = picopass_poller_select_handler,
- [PicopassPollerStatePreAuth] = picopass_poller_pre_auth_handler,
- [PicopassPollerStateCheckSecurity] = picopass_poller_check_security,
- [PicopassPollerStateNrMacAuth] = picopass_poller_nr_mac_auth,
- [PicopassPollerStateAuth] = picopass_poller_auth_handler,
- [PicopassPollerStateReadBlock] = picopass_poller_read_block_handler,
- [PicopassPollerStateWriteBlock] = picopass_poller_write_block_handler,
- [PicopassPollerStateWriteKey] = picopass_poller_write_key_handler,
- [PicopassPollerStateParseCredential] = picopass_poller_parse_credential_handler,
- [PicopassPollerStateParseWiegand] = picopass_poller_parse_wiegand_handler,
- [PicopassPollerStateSuccess] = picopass_poller_success_handler,
- [PicopassPollerStateFail] = picopass_poller_fail_handler,
- [PicopassPollerStateAuthFail] = picopass_poller_auth_fail_handler,
- };
- static NfcCommand picopass_poller_callback(NfcEvent event, void* context) {
- furi_assert(context);
- PicopassPoller* instance = context;
- NfcCommand command = NfcCommandContinue;
- if(event.type == NfcEventTypePollerReady) {
- command = picopass_poller_state_handler[instance->state](instance);
- }
- if(instance->session_state == PicopassPollerSessionStateStopRequest) {
- command = NfcCommandStop;
- }
- return command;
- }
- void picopass_poller_start(
- PicopassPoller* instance,
- PicopassPollerCallback callback,
- void* context) {
- furi_assert(instance);
- furi_assert(instance->session_state == PicopassPollerSessionStateIdle);
- instance->callback = callback;
- instance->context = context;
- instance->session_state = PicopassPollerSessionStateActive;
- nfc_start(instance->nfc, picopass_poller_callback, instance);
- }
- void picopass_poller_stop(PicopassPoller* instance) {
- furi_assert(instance);
- instance->session_state = PicopassPollerSessionStateStopRequest;
- nfc_stop(instance->nfc);
- instance->session_state = PicopassPollerSessionStateIdle;
- }
- PicopassPoller* picopass_poller_alloc(Nfc* nfc) {
- furi_assert(nfc);
- PicopassPoller* instance = malloc(sizeof(PicopassPoller));
- instance->nfc = nfc;
- nfc_config(instance->nfc, NfcModePoller, NfcTechIso15693);
- nfc_set_guard_time_us(instance->nfc, 10000);
- nfc_set_fdt_poll_fc(instance->nfc, 5000);
- nfc_set_fdt_poll_poll_us(instance->nfc, 1000);
- instance->event.data = &instance->event_data;
- instance->data = malloc(sizeof(PicopassDeviceData));
- instance->tx_buffer = bit_buffer_alloc(PICOPASS_POLLER_BUFFER_SIZE);
- instance->rx_buffer = bit_buffer_alloc(PICOPASS_POLLER_BUFFER_SIZE);
- instance->tmp_buffer = bit_buffer_alloc(PICOPASS_POLLER_BUFFER_SIZE);
- return instance;
- }
- void picopass_poller_free(PicopassPoller* instance) {
- furi_assert(instance);
- free(instance->data);
- bit_buffer_free(instance->tx_buffer);
- bit_buffer_free(instance->rx_buffer);
- bit_buffer_free(instance->tmp_buffer);
- free(instance);
- }
- const PicopassDeviceData* picopass_poller_get_data(PicopassPoller* instance) {
- furi_assert(instance);
- return instance->data;
- }
|