#include "mf_classic_poller_i.h"
 
#include <nfc/protocols/nfc_poller_base.h>
 
#include <furi.h>
 
#define TAG "MfClassicPoller"
 
#define MF_CLASSIC_MAX_BUFF_SIZE (64)
 
typedef NfcCommand (*MfClassicPollerReadHandler)(MfClassicPoller* instance);
 
MfClassicPoller* mf_classic_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller) {
    furi_assert(iso14443_3a_poller);
 
    MfClassicPoller* instance = malloc(sizeof(MfClassicPoller));
    instance->iso14443_3a_poller = iso14443_3a_poller;
    instance->data = mf_classic_alloc();
    instance->crypto = crypto1_alloc();
    instance->tx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE);
    instance->tx_encrypted_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE);
    instance->rx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE);
    instance->rx_encrypted_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE);
 
    instance->mfc_event.data = &instance->mfc_event_data;
 
    instance->general_event.protocol = NfcProtocolMfClassic;
    instance->general_event.data = &instance->mfc_event;
    instance->general_event.instance = instance;
 
    return instance;
}
 
void mf_classic_poller_free(MfClassicPoller* 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);
 
    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);
}
 
NfcCommand mf_classic_poller_handler_idle(MfClassicPoller* instance) {
    iso14443_3a_copy(
        instance->data->iso14443_3a_data,
        iso14443_3a_poller_get_data(instance->iso14443_3a_poller));
    NfcCommand command = NfcCommandContinue;
 
    if(mf_classic_detect_protocol(instance->data->iso14443_3a_data, &instance->data->type)) {
        if(instance->card_state == MfClassicCardStateNotDetected) {
            instance->card_state = MfClassicCardStateDetected;
            instance->mfc_event.type = MfClassicPollerEventTypeCardDetected;
            command = instance->callback(instance->general_event, instance->context);
        }
        instance->state = instance->prev_state;
    }
 
    return command;
}
 
NfcCommand mf_classic_poller_handler_start(MfClassicPoller* instance) {
    NfcCommand command = NfcCommandContinue;
 
    instance->sectors_read = 0;
    instance->sectors_total = mf_classic_get_total_sectors_num(instance->data->type);
 
    instance->mfc_event_data.start_data.type = instance->data->type;
    command = instance->callback(instance->general_event, instance->context);
 
    instance->prev_state = MfClassicPollerStateStart;
    instance->state = MfClassicPollerStateNewSector;
 
    return command;
}
 
NfcCommand mf_classic_poller_handler_new_sector(MfClassicPoller* instance) {
    NfcCommand command = NfcCommandContinue;
 
    if(instance->read_mode == MfClassicReadModeKeyReuse) {
        instance->key_reuse_sector++;
        if(instance->key_reuse_sector == instance->sectors_total) {
            instance->read_mode = MfClassicReadModeDictAttack;
            instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStop;
            command = instance->callback(instance->general_event, instance->context);
        } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) {
            instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackNextSector;
            command = instance->callback(instance->general_event, instance->context);
        } else {
            instance->state = MfClassicPollerStateAuthKeyA;
            instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackNextSector;
            command = instance->callback(instance->general_event, instance->context);
        }
    } else {
        if(instance->sectors_read == instance->sectors_total) {
            instance->state = MfClassicPollerStateReadComplete;
        } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) {
            instance->sectors_read++;
            instance->mfc_event.type = MfClassicPollerEventTypeNewSector;
            command = instance->callback(instance->general_event, instance->context);
        } else {
            instance->state = MfClassicPollerStateRequestKey;
        }
    }
    instance->prev_state = instance->state;
 
    return command;
}
 
NfcCommand mf_classic_poller_handler_request_key(MfClassicPoller* instance) {
    NfcCommand command = NfcCommandContinue;
 
    instance->mfc_event_data.key_request_data.sector_num = instance->sectors_read;
    command = instance->callback(instance->general_event, instance->context);
    if(instance->mfc_event_data.key_request_data.key_provided) {
        instance->current_key = instance->mfc_event_data.key_request_data.key;
        instance->state = MfClassicPollerStateAuthKeyA;
    } else {
        instance->state = MfClassicPollerStateNewSector;
    }
 
    return command;
}
 
NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) {
    NfcCommand command = NfcCommandContinue;
 
    uint8_t sector = 0;
    if(instance->read_mode == MfClassicReadModeKeyReuse) {
        sector = instance->key_reuse_sector;
    } else {
        sector = instance->sectors_read;
    }
 
    if(mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeA)) {
        instance->prev_state = instance->state;
        instance->state = MfClassicPollerStateAuthKeyB;
    } else {
        uint8_t block = mf_classic_get_first_block_num_of_sector(sector);
        uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6);
        FURI_LOG_D(TAG, "Auth to block %d with key A: %06llx", block, key);
 
        MfClassicError error = mf_classic_async_auth(
            instance, block, &instance->current_key, MfClassicKeyTypeA, NULL);
        if(error == MfClassicErrorNone) {
            FURI_LOG_I(TAG, "Key A found");
            mf_classic_set_key_found(instance->data, sector, MfClassicKeyTypeA, key);
            if(instance->read_mode != MfClassicReadModeKeyReuse) {
                if(sector < instance->sectors_total - 1) {
                    instance->read_mode = MfClassicReadModeKeyReuse;
                    instance->key_reuse_sector = sector;
                    instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStart;
                    instance->mfc_event_data.key_attack_data.start_sector =
                        instance->key_reuse_sector;
                    command = instance->callback(instance->general_event, instance->context);
                }
            }
            instance->mfc_event.type = MfClassicPollerEventTypeFoundKeyA;
            command = instance->callback(instance->general_event, instance->context);
            instance->prev_state = instance->state;
            instance->state = MfClassicPollerStateReadSector;
        } else {
            if(instance->read_mode == MfClassicReadModeKeyReuse) {
                instance->state = MfClassicPollerStateAuthKeyB;
            } else {
                instance->state = MfClassicPollerStateRequestKey;
            }
        }
    }
 
    return command;
}
 
NfcCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) {
    NfcCommand command = NfcCommandContinue;
 
    uint8_t sector = 0;
    if(instance->read_mode == MfClassicReadModeKeyReuse) {
        sector = instance->key_reuse_sector;
    } else {
        sector = instance->sectors_read;
    }
 
    if(mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeB)) {
        instance->state = MfClassicPollerStateNewSector;
    } else {
        uint8_t block = mf_classic_get_first_block_num_of_sector(sector);
        uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6);
        FURI_LOG_D(TAG, "Auth to block %d with key B: %06llx", block, key);
 
        MfClassicError error = mf_classic_async_auth(
            instance, block, &instance->current_key, MfClassicKeyTypeB, NULL);
        if(error == MfClassicErrorNone) {
            FURI_LOG_D(TAG, "Key B found");
            instance->mfc_event.type = MfClassicPollerEventTypeFoundKeyB;
            mf_classic_set_key_found(instance->data, sector, MfClassicKeyTypeB, key);
            if(instance->read_mode != MfClassicReadModeKeyReuse) {
                if(sector < instance->sectors_total - 1) {
                    instance->read_mode = MfClassicReadModeKeyReuse;
                    instance->key_reuse_sector = sector;
 
                    instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStart;
                    instance->mfc_event_data.key_attack_data.start_sector =
                        instance->key_reuse_sector;
                    command = instance->callback(instance->general_event, instance->context);
                }
            }
            command = instance->callback(instance->general_event, instance->context);
            instance->state = MfClassicPollerStateReadSector;
        } else {
            if(instance->read_mode == MfClassicReadModeKeyReuse) {
                instance->state = MfClassicPollerStateNewSector;
            } else {
                instance->state = MfClassicPollerStateRequestKey;
            }
        }
    }
    instance->prev_state = instance->state;
 
    return command;
}
 
NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) {
    NfcCommand command = NfcCommandContinue;
 
    uint8_t block_start = mf_classic_get_first_block_num_of_sector(instance->sectors_read);
    uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(instance->sectors_read);
    MfClassicBlock block = {};
 
    for(size_t i = block_start; i < block_start + total_blocks; i++) {
        FURI_LOG_D(TAG, "Reding block %d", i);
        if(mf_classic_is_block_read(instance->data, i)) continue;
        MfClassicError error = mf_classic_async_read_block(instance, i, &block);
        if(error == MfClassicErrorNone) {
            mf_classic_set_block_read(instance->data, i, &block);
        } else {
            FURI_LOG_D(TAG, "Failed to read %d block", i);
            break;
        }
    }
 
    instance->prev_state = instance->state;
    if(instance->prev_state == MfClassicPollerStateAuthKeyA) {
        instance->state = MfClassicPollerStateAuthKeyB;
    } else {
        instance->state = MfClassicPollerStateNewSector;
    }
 
    return command;
}
 
NfcCommand mf_classic_poller_handler_read_complete(MfClassicPoller* instance) {
    NfcCommand command = NfcCommandContinue;
    instance->mfc_event.type = MfClassicPollerEventTypeReadComplete;
    command = instance->callback(instance->general_event, instance->context);
 
    return command;
}
 
static const MfClassicPollerReadHandler
    mf_classic_poller_dict_attack_handler[MfClassicPollerStateNum] = {
        [MfClassicPollerStateIdle] = mf_classic_poller_handler_idle,
        [MfClassicPollerStateStart] = mf_classic_poller_handler_start,
        [MfClassicPollerStateNewSector] = mf_classic_poller_handler_new_sector,
        [MfClassicPollerStateRequestKey] = mf_classic_poller_handler_request_key,
        [MfClassicPollerStateAuthKeyA] = mf_classic_poller_handler_auth_a,
        [MfClassicPollerStateAuthKeyB] = mf_classic_poller_handler_auth_b,
        [MfClassicPollerStateReadSector] = mf_classic_poller_handler_read_sector,
        [MfClassicPollerStateReadComplete] = mf_classic_poller_handler_read_complete,
};
 
NfcCommand mf_classsic_poller_run(NfcGenericEvent event, void* context) {
    furi_assert(event.data);
    furi_assert(event.protocol == NfcProtocolIso14443_3a);
    furi_assert(context);
 
    MfClassicPoller* instance = context;
    Iso14443_3aPollerEvent* iso14443_3a_event = event.data;
    NfcCommand command = NfcCommandContinue;
 
    if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
        command = mf_classic_poller_dict_attack_handler[instance->state](instance);
    } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) {
        if(iso14443_3a_event->data->error == Iso14443_3aErrorNotPresent) {
            if(instance->card_state == MfClassicCardStateDetected) {
                instance->card_state = MfClassicCardStateNotDetected;
                instance->mfc_event.type = MfClassicPollerEventTypeCardNotDetected;
                command = instance->callback(instance->general_event, instance->context);
                instance->state = MfClassicPollerStateIdle;
            }
        }
    }
 
    return command;
}
 
bool mf_classsic_poller_detect(NfcGenericEvent event, void* context) {
    furi_assert(event.data);
    furi_assert(event.protocol == NfcProtocolIso14443_3a);
    furi_assert(context);
 
    return false;
}
 
void mf_classic_poller_set_callback(
    MfClassicPoller* instance,
    NfcGenericCallback callback,
    void* context) {
    furi_assert(instance);
    furi_assert(callback);
 
    instance->callback = callback;
    instance->context = context;
}
 
const MfClassicData* mf_classic_poller_get_data(const MfClassicPoller* instance) {
    furi_assert(instance);
    furi_assert(instance->data);
 
    return instance->data;
}
 
const NfcPollerBase mf_classic_poller = {
    .alloc = (NfcPollerAlloc)mf_classic_poller_alloc,
    .free = (NfcPollerFree)mf_classic_poller_free,
    .set_callback = (NfcPollerSetCallback)mf_classic_poller_set_callback,
    .run = (NfcPollerRun)mf_classsic_poller_run,
    .detect = (NfcPollerDetect)mf_classsic_poller_detect,
    .get_data = (NfcPollerGetData)mf_classic_poller_get_data,
};

V519 The 'command' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 164, 168.

V519 The 'command' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 214, 217.