"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring. Starring: - @gornekich - NFC refactoring project lead, architect, senior developer - @gsurkov - architect, senior developer - @RebornedBrain - senior developer Supporting roles: - @skotopes, @DrZlo13, @hedger - general architecture advisors, code review - @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance Special thanks: @bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
		
			
				
	
	
		
			174 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "mfkey32_logger.h"
 | 
						|
 | 
						|
#include <m-array.h>
 | 
						|
 | 
						|
#include <nfc/helpers/nfc_util.h>
 | 
						|
#include <stream/stream.h>
 | 
						|
#include <stream/buffered_file_stream.h>
 | 
						|
 | 
						|
#define MFKEY32_LOGGER_MAX_NONCES_SAVED (100)
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    bool is_filled;
 | 
						|
    uint32_t cuid;
 | 
						|
    uint8_t sector_num;
 | 
						|
    MfClassicKeyType key_type;
 | 
						|
    uint32_t nt0;
 | 
						|
    uint32_t nr0;
 | 
						|
    uint32_t ar0;
 | 
						|
    uint32_t nt1;
 | 
						|
    uint32_t nr1;
 | 
						|
    uint32_t ar1;
 | 
						|
} Mfkey32LoggerParams;
 | 
						|
 | 
						|
ARRAY_DEF(Mfkey32LoggerParams, Mfkey32LoggerParams, M_POD_OPLIST);
 | 
						|
 | 
						|
struct Mfkey32Logger {
 | 
						|
    uint32_t cuid;
 | 
						|
    Mfkey32LoggerParams_t params_arr;
 | 
						|
    size_t nonces_saves;
 | 
						|
    size_t params_collected;
 | 
						|
};
 | 
						|
 | 
						|
Mfkey32Logger* mfkey32_logger_alloc(uint32_t cuid) {
 | 
						|
    Mfkey32Logger* instance = malloc(sizeof(Mfkey32Logger));
 | 
						|
    instance->cuid = cuid;
 | 
						|
    Mfkey32LoggerParams_init(instance->params_arr);
 | 
						|
 | 
						|
    return instance;
 | 
						|
}
 | 
						|
 | 
						|
void mfkey32_logger_free(Mfkey32Logger* instance) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(instance->params_arr);
 | 
						|
 | 
						|
    Mfkey32LoggerParams_clear(instance->params_arr);
 | 
						|
    free(instance);
 | 
						|
}
 | 
						|
 | 
						|
static bool mfkey32_logger_add_nonce_to_existing_params(
 | 
						|
    Mfkey32Logger* instance,
 | 
						|
    MfClassicAuthContext* auth_context) {
 | 
						|
    bool nonce_added = false;
 | 
						|
    do {
 | 
						|
        if(Mfkey32LoggerParams_size(instance->params_arr) == 0) break;
 | 
						|
 | 
						|
        Mfkey32LoggerParams_it_t it;
 | 
						|
        for(Mfkey32LoggerParams_it(it, instance->params_arr); !Mfkey32LoggerParams_end_p(it);
 | 
						|
            Mfkey32LoggerParams_next(it)) {
 | 
						|
            Mfkey32LoggerParams* params = Mfkey32LoggerParams_ref(it);
 | 
						|
            if(params->is_filled) continue;
 | 
						|
 | 
						|
            uint8_t sector_num = mf_classic_get_sector_by_block(auth_context->block_num);
 | 
						|
            if(params->sector_num != sector_num) continue;
 | 
						|
            if(params->key_type != auth_context->key_type) continue;
 | 
						|
 | 
						|
            params->nt1 = nfc_util_bytes2num(auth_context->nt.data, sizeof(MfClassicNt));
 | 
						|
            params->nr1 = nfc_util_bytes2num(auth_context->nr.data, sizeof(MfClassicNr));
 | 
						|
            params->ar1 = nfc_util_bytes2num(auth_context->ar.data, sizeof(MfClassicAr));
 | 
						|
            params->is_filled = true;
 | 
						|
 | 
						|
            instance->params_collected++;
 | 
						|
            nonce_added = true;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
    } while(false);
 | 
						|
 | 
						|
    return nonce_added;
 | 
						|
}
 | 
						|
 | 
						|
void mfkey32_logger_add_nonce(Mfkey32Logger* instance, MfClassicAuthContext* auth_context) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(auth_context);
 | 
						|
 | 
						|
    bool nonce_added = mfkey32_logger_add_nonce_to_existing_params(instance, auth_context);
 | 
						|
    if(!nonce_added && (instance->nonces_saves < MFKEY32_LOGGER_MAX_NONCES_SAVED)) {
 | 
						|
        uint8_t sector_num = mf_classic_get_sector_by_block(auth_context->block_num);
 | 
						|
        Mfkey32LoggerParams params = {
 | 
						|
            .is_filled = false,
 | 
						|
            .cuid = instance->cuid,
 | 
						|
            .sector_num = sector_num,
 | 
						|
            .key_type = auth_context->key_type,
 | 
						|
            .nt0 = nfc_util_bytes2num(auth_context->nt.data, sizeof(MfClassicNt)),
 | 
						|
            .nr0 = nfc_util_bytes2num(auth_context->nr.data, sizeof(MfClassicNr)),
 | 
						|
            .ar0 = nfc_util_bytes2num(auth_context->ar.data, sizeof(MfClassicAr)),
 | 
						|
        };
 | 
						|
        Mfkey32LoggerParams_push_back(instance->params_arr, params);
 | 
						|
        instance->nonces_saves++;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
size_t mfkey32_logger_get_params_num(Mfkey32Logger* instance) {
 | 
						|
    furi_assert(instance);
 | 
						|
 | 
						|
    return instance->params_collected;
 | 
						|
}
 | 
						|
 | 
						|
bool mfkey32_logger_save_params(Mfkey32Logger* instance, const char* path) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(path);
 | 
						|
    furi_assert(instance->params_collected > 0);
 | 
						|
    furi_assert(instance->params_arr);
 | 
						|
 | 
						|
    bool params_saved = false;
 | 
						|
    Storage* storage = furi_record_open(RECORD_STORAGE);
 | 
						|
    Stream* stream = buffered_file_stream_alloc(storage);
 | 
						|
    FuriString* temp_str = furi_string_alloc();
 | 
						|
 | 
						|
    do {
 | 
						|
        if(!buffered_file_stream_open(stream, path, FSAM_WRITE, FSOM_OPEN_APPEND)) break;
 | 
						|
 | 
						|
        bool params_write_success = true;
 | 
						|
        Mfkey32LoggerParams_it_t it;
 | 
						|
        for(Mfkey32LoggerParams_it(it, instance->params_arr); !Mfkey32LoggerParams_end_p(it);
 | 
						|
            Mfkey32LoggerParams_next(it)) {
 | 
						|
            Mfkey32LoggerParams* params = Mfkey32LoggerParams_ref(it);
 | 
						|
            if(!params->is_filled) continue;
 | 
						|
            furi_string_printf(
 | 
						|
                temp_str,
 | 
						|
                "Sec %d key %c cuid %08lx nt0 %08lx nr0 %08lx ar0 %08lx nt1 %08lx nr1 %08lx ar1 %08lx\n",
 | 
						|
                params->sector_num,
 | 
						|
                params->key_type == MfClassicKeyTypeA ? 'A' : 'B',
 | 
						|
                params->cuid,
 | 
						|
                params->nt0,
 | 
						|
                params->nr0,
 | 
						|
                params->ar0,
 | 
						|
                params->nt1,
 | 
						|
                params->nr1,
 | 
						|
                params->ar1);
 | 
						|
            if(!stream_write_string(stream, temp_str)) {
 | 
						|
                params_write_success = false;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if(!params_write_success) break;
 | 
						|
 | 
						|
        params_saved = true;
 | 
						|
    } while(false);
 | 
						|
 | 
						|
    furi_string_free(temp_str);
 | 
						|
    buffered_file_stream_close(stream);
 | 
						|
    stream_free(stream);
 | 
						|
    furi_record_close(RECORD_STORAGE);
 | 
						|
 | 
						|
    return params_saved;
 | 
						|
}
 | 
						|
 | 
						|
void mfkey32_logger_get_params_data(Mfkey32Logger* instance, FuriString* str) {
 | 
						|
    furi_assert(instance);
 | 
						|
    furi_assert(str);
 | 
						|
    furi_assert(instance->params_collected > 0);
 | 
						|
 | 
						|
    furi_string_reset(str);
 | 
						|
    Mfkey32LoggerParams_it_t it;
 | 
						|
    for(Mfkey32LoggerParams_it(it, instance->params_arr); !Mfkey32LoggerParams_end_p(it);
 | 
						|
        Mfkey32LoggerParams_next(it)) {
 | 
						|
        Mfkey32LoggerParams* params = Mfkey32LoggerParams_ref(it);
 | 
						|
        if(!params->is_filled) continue;
 | 
						|
 | 
						|
        char key_char = params->key_type == MfClassicKeyTypeA ? 'A' : 'B';
 | 
						|
        furi_string_cat_printf(str, "Sector %d, key %c\n", params->sector_num, key_char);
 | 
						|
    }
 | 
						|
}
 |