NfcDict Refactoring (#3271)

* toolbox(keys_dict): generalize nfc_dict
* nfc: rework nfc app and tests
* toolbox(keys_dict): improve code readability
This commit is contained in:
Andrea Maugeri 2023-12-18 15:30:56 +01:00 committed by GitHub
parent 8c4716f170
commit 7642d67cae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 524 additions and 448 deletions

View file

@ -12,7 +12,7 @@
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h>
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
#include <nfc/helpers/nfc_dict.h>
#include <toolbox/keys_dict.h>
#include <nfc/nfc.h>
#include "../minunit.h"
@ -443,36 +443,36 @@ MU_TEST(mf_classic_dict_test) {
"Remove test dict failed");
}
NfcDict* dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
mu_assert(dict != NULL, "nfc_dict_alloc() failed");
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
mu_assert(dict != NULL, "keys_dict_alloc() failed");
size_t dict_keys_total = nfc_dict_get_total_keys(dict);
mu_assert(dict_keys_total == 0, "nfc_dict_keys_total() failed");
size_t dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(dict_keys_total == 0, "keys_dict_keys_total() failed");
const uint32_t test_key_num = 30;
MfClassicKey* key_arr_ref = malloc(test_key_num * sizeof(MfClassicKey));
for(size_t i = 0; i < test_key_num; i++) {
furi_hal_random_fill_buf(key_arr_ref[i].data, sizeof(MfClassicKey));
mu_assert(
nfc_dict_add_key(dict, key_arr_ref[i].data, sizeof(MfClassicKey)), "add key failed");
keys_dict_add_key(dict, key_arr_ref[i].data, sizeof(MfClassicKey)), "add key failed");
size_t dict_keys_total = nfc_dict_get_total_keys(dict);
mu_assert(dict_keys_total == (i + 1), "nfc_dict_keys_total() failed");
size_t dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(dict_keys_total == (i + 1), "keys_dict_keys_total() failed");
}
nfc_dict_free(dict);
keys_dict_free(dict);
dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
mu_assert(dict != NULL, "nfc_dict_alloc() failed");
dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
mu_assert(dict != NULL, "keys_dict_alloc() failed");
dict_keys_total = nfc_dict_get_total_keys(dict);
mu_assert(dict_keys_total == test_key_num, "nfc_dict_keys_total() failed");
dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(dict_keys_total == test_key_num, "keys_dict_keys_total() failed");
MfClassicKey key_dut = {};
size_t key_idx = 0;
while(nfc_dict_get_next_key(dict, key_dut.data, sizeof(MfClassicKey))) {
while(keys_dict_get_next_key(dict, key_dut.data, sizeof(MfClassicKey))) {
mu_assert(
memcmp(key_arr_ref[key_idx].data, key_dut.data, sizeof(MfClassicKey)) == 0,
"Loaded key data mismatch");
@ -484,19 +484,19 @@ MU_TEST(mf_classic_dict_test) {
for(size_t i = 0; i < COUNT_OF(delete_keys_idx); i++) {
MfClassicKey* key = &key_arr_ref[delete_keys_idx[i]];
mu_assert(
nfc_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)),
"nfc_dict_is_key_present() failed");
keys_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)),
"keys_dict_is_key_present() failed");
mu_assert(
nfc_dict_delete_key(dict, key->data, sizeof(MfClassicKey)),
"nfc_dict_delete_key() failed");
keys_dict_delete_key(dict, key->data, sizeof(MfClassicKey)),
"keys_dict_delete_key() failed");
}
dict_keys_total = nfc_dict_get_total_keys(dict);
dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(
dict_keys_total == test_key_num - COUNT_OF(delete_keys_idx),
"nfc_dict_keys_total() failed");
"keys_dict_keys_total() failed");
nfc_dict_free(dict);
keys_dict_free(dict);
free(key_arr_ref);
mu_assert(

View file

@ -1,6 +1,6 @@
#include "mf_user_dict.h"
#include <nfc/helpers/nfc_dict.h>
#include <toolbox/keys_dict.h>
#include <nfc/protocols/mf_classic/mf_classic.h>
#include <furi/furi.h>
@ -15,22 +15,22 @@ struct MfUserDict {
MfUserDict* mf_user_dict_alloc(size_t max_keys_to_load) {
MfUserDict* instance = malloc(sizeof(MfUserDict));
NfcDict* dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
furi_assert(dict);
size_t dict_keys_num = nfc_dict_get_total_keys(dict);
size_t dict_keys_num = keys_dict_get_total_keys(dict);
instance->keys_num = MIN(max_keys_to_load, dict_keys_num);
if(instance->keys_num > 0) {
instance->keys_arr = malloc(instance->keys_num * sizeof(MfClassicKey));
for(size_t i = 0; i < instance->keys_num; i++) {
bool key_loaded =
nfc_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey));
keys_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey));
furi_assert(key_loaded);
}
}
nfc_dict_free(dict);
keys_dict_free(dict);
return instance;
}
@ -67,13 +67,13 @@ bool mf_user_dict_delete_key(MfUserDict* instance, uint32_t index) {
furi_assert(index < instance->keys_num);
furi_assert(instance->keys_arr);
NfcDict* dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
furi_assert(dict);
bool key_delete_success =
nfc_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey));
nfc_dict_free(dict);
keys_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey));
keys_dict_free(dict);
if(key_delete_success) {
instance->keys_num--;

View file

@ -52,7 +52,7 @@
#include <nfc/nfc_device.h>
#include <nfc/helpers/nfc_data_generator.h>
#include <nfc/helpers/nfc_dict.h>
#include <toolbox/keys_dict.h>
#include <gui/modules/validators.h>
#include <toolbox/path.h>
@ -80,7 +80,7 @@ typedef enum {
} NfcRpcState;
typedef struct {
NfcDict* dict;
KeysDict* dict;
uint8_t sectors_total;
uint8_t sectors_read;
uint8_t current_sector;

View file

@ -41,7 +41,8 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
} else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) {
MfClassicKey key = {};
if(nfc_dict_get_next_key(instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) {
if(keys_dict_get_next_key(
instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) {
mfc_event->data->key_request_data.key = key;
mfc_event->data->key_request_data.key_provided = true;
instance->nfc_dict_context.dict_keys_current++;
@ -60,7 +61,7 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
} else if(mfc_event->type == MfClassicPollerEventTypeNextSector) {
nfc_dict_rewind(instance->nfc_dict_context.dict);
keys_dict_rewind(instance->nfc_dict_context.dict);
instance->nfc_dict_context.dict_keys_current = 0;
instance->nfc_dict_context.current_sector =
mfc_event->data->next_sector_data.current_sector;
@ -79,7 +80,7 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
} else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStop) {
nfc_dict_rewind(instance->nfc_dict_context.dict);
keys_dict_rewind(instance->nfc_dict_context.dict);
instance->nfc_dict_context.is_key_attack = false;
instance->nfc_dict_context.dict_keys_current = 0;
view_dispatcher_send_custom_event(
@ -124,15 +125,15 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) {
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack);
if(state == DictAttackStateUserDictInProgress) {
do {
if(!nfc_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) {
if(!keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) {
state = DictAttackStateSystemDictInProgress;
break;
}
instance->nfc_dict_context.dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
if(nfc_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
nfc_dict_free(instance->nfc_dict_context.dict);
instance->nfc_dict_context.dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
keys_dict_free(instance->nfc_dict_context.dict);
state = DictAttackStateSystemDictInProgress;
break;
}
@ -141,13 +142,13 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) {
} while(false);
}
if(state == DictAttackStateSystemDictInProgress) {
instance->nfc_dict_context.dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey));
instance->nfc_dict_context.dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey));
dict_attack_set_header(instance->dict_attack, "MF Classic System Dictionary");
}
instance->nfc_dict_context.dict_keys_total =
nfc_dict_get_total_keys(instance->nfc_dict_context.dict);
keys_dict_get_total_keys(instance->nfc_dict_context.dict);
dict_attack_set_total_dict_keys(
instance->dict_attack, instance->nfc_dict_context.dict_keys_total);
instance->nfc_dict_context.dict_keys_current = 0;
@ -185,7 +186,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
if(state == DictAttackStateUserDictInProgress) {
nfc_poller_stop(instance->poller);
nfc_poller_free(instance->poller);
nfc_dict_free(instance->nfc_dict_context.dict);
keys_dict_free(instance->nfc_dict_context.dict);
scene_manager_set_scene_state(
instance->scene_manager,
NfcSceneMfClassicDictAttack,
@ -215,7 +216,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
if(instance->nfc_dict_context.is_card_present) {
nfc_poller_stop(instance->poller);
nfc_poller_free(instance->poller);
nfc_dict_free(instance->nfc_dict_context.dict);
keys_dict_free(instance->nfc_dict_context.dict);
scene_manager_set_scene_state(
instance->scene_manager,
NfcSceneMfClassicDictAttack,
@ -253,7 +254,7 @@ void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
scene_manager_set_scene_state(
instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateUserDictInProgress);
nfc_dict_free(instance->nfc_dict_context.dict);
keys_dict_free(instance->nfc_dict_context.dict);
instance->nfc_dict_context.current_sector = 0;
instance->nfc_dict_context.sectors_total = 0;

View file

@ -14,20 +14,20 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) {
// Load flipper dict keys total
uint32_t flipper_dict_keys_total = 0;
NfcDict* dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey));
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey));
if(dict) {
flipper_dict_keys_total = nfc_dict_get_total_keys(dict);
nfc_dict_free(dict);
flipper_dict_keys_total = keys_dict_get_total_keys(dict);
keys_dict_free(dict);
}
// Load user dict keys total
uint32_t user_dict_keys_total = 0;
dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
if(dict) {
user_dict_keys_total = nfc_dict_get_total_keys(dict);
nfc_dict_free(dict);
user_dict_keys_total = keys_dict_get_total_keys(dict);
keys_dict_free(dict);
}
FuriString* temp_str = furi_string_alloc();

View file

@ -29,23 +29,23 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) {
// Add key to dict
NfcDict* dict = nfc_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
furi_assert(dict);
MfClassicKey key = {};
memcpy(key.data, instance->byte_input_store, sizeof(MfClassicKey));
if(nfc_dict_is_key_present(dict, key.data, sizeof(MfClassicKey))) {
if(keys_dict_is_key_present(dict, key.data, sizeof(MfClassicKey))) {
scene_manager_next_scene(
instance->scene_manager, NfcSceneMfClassicKeysWarnDuplicate);
} else if(nfc_dict_add_key(dict, key.data, sizeof(MfClassicKey))) {
} else if(keys_dict_add_key(dict, key.data, sizeof(MfClassicKey))) {
scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess);
dolphin_deed(DolphinDeedNfcMfcAdd);
} else {
scene_manager_previous_scene(instance->scene_manager);
}
nfc_dict_free(dict);
keys_dict_free(dict);
consumed = true;
}
}

View file

@ -48,7 +48,6 @@ env.Append(
File("helpers/iso14443_crc.h"),
File("helpers/iso13239_crc.h"),
File("helpers/nfc_data_generator.h"),
File("helpers/nfc_dict.h"),
],
)

View file

@ -1,270 +0,0 @@
#include "nfc_dict.h"
#include <storage/storage.h>
#include <flipper_format/flipper_format.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#include <toolbox/args.h>
#include <nfc/helpers/nfc_util.h>
#define TAG "NfcDict"
struct NfcDict {
Stream* stream;
size_t key_size;
size_t key_size_symbols;
uint32_t total_keys;
};
typedef struct {
const char* path;
FS_OpenMode open_mode;
} NfcDictFile;
bool nfc_dict_check_presence(const char* path) {
furi_assert(path);
Storage* storage = furi_record_open(RECORD_STORAGE);
bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK;
furi_record_close(RECORD_STORAGE);
return dict_present;
}
NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size) {
furi_assert(path);
NfcDict* instance = malloc(sizeof(NfcDict));
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->stream = buffered_file_stream_alloc(storage);
furi_record_close(RECORD_STORAGE);
FS_OpenMode open_mode = FSOM_OPEN_EXISTING;
if(mode == NfcDictModeOpenAlways) {
open_mode = FSOM_OPEN_ALWAYS;
}
instance->key_size = key_size;
// Byte = 2 symbols + 1 end of line
instance->key_size_symbols = key_size * 2 + 1;
bool dict_loaded = false;
do {
if(!buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode)) {
buffered_file_stream_close(instance->stream);
break;
}
// Check for new line ending
if(!stream_eof(instance->stream)) {
if(!stream_seek(instance->stream, -1, StreamOffsetFromEnd)) break;
uint8_t last_char = 0;
if(stream_read(instance->stream, &last_char, 1) != 1) break;
if(last_char != '\n') {
FURI_LOG_D(TAG, "Adding new line ending");
if(stream_write_char(instance->stream, '\n') != 1) break;
}
if(!stream_rewind(instance->stream)) break;
}
// Read total amount of keys
FuriString* next_line;
next_line = furi_string_alloc();
while(true) {
if(!stream_read_line(instance->stream, next_line)) {
FURI_LOG_T(TAG, "No keys left in dict");
break;
}
FURI_LOG_T(
TAG,
"Read line: %s, len: %zu",
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) != instance->key_size_symbols) continue;
instance->total_keys++;
}
furi_string_free(next_line);
stream_rewind(instance->stream);
dict_loaded = true;
FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", instance->total_keys);
} while(false);
if(!dict_loaded) {
buffered_file_stream_close(instance->stream);
free(instance);
instance = NULL;
}
return instance;
}
void nfc_dict_free(NfcDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
buffered_file_stream_close(instance->stream);
stream_free(instance->stream);
free(instance);
}
static void nfc_dict_int_to_str(NfcDict* instance, const uint8_t* key_int, FuriString* key_str) {
furi_string_reset(key_str);
for(size_t i = 0; i < instance->key_size; i++) {
furi_string_cat_printf(key_str, "%02X", key_int[i]);
}
}
static void nfc_dict_str_to_int(NfcDict* instance, FuriString* key_str, uint64_t* key_int) {
uint8_t key_byte_tmp;
*key_int = 0ULL;
for(uint8_t i = 0; i < instance->key_size * 2; i += 2) {
args_char_to_hex(
furi_string_get_char(key_str, i), furi_string_get_char(key_str, i + 1), &key_byte_tmp);
*key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2));
}
}
uint32_t nfc_dict_get_total_keys(NfcDict* instance) {
furi_assert(instance);
return instance->total_keys;
}
bool nfc_dict_rewind(NfcDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
return stream_rewind(instance->stream);
}
static bool nfc_dict_get_next_key_str(NfcDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
bool key_read = false;
furi_string_reset(key);
while(!key_read) {
if(!stream_read_line(instance->stream, key)) break;
if(furi_string_get_char(key, 0) == '#') continue;
if(furi_string_size(key) != instance->key_size_symbols) continue;
furi_string_left(key, instance->key_size_symbols - 1);
key_read = true;
}
return key_read;
}
bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
FuriString* temp_key = furi_string_alloc();
uint64_t key_int = 0;
bool key_read = nfc_dict_get_next_key_str(instance, temp_key);
if(key_read) {
nfc_dict_str_to_int(instance, temp_key, &key_int);
nfc_util_num2bytes(key_int, key_size, key);
}
furi_string_free(temp_key);
return key_read;
}
static bool nfc_dict_is_key_present_str(NfcDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
FuriString* next_line;
next_line = furi_string_alloc();
bool key_found = false;
stream_rewind(instance->stream);
while(!key_found) { //-V654
if(!stream_read_line(instance->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != instance->key_size_symbols) continue;
furi_string_left(next_line, instance->key_size_symbols - 1);
if(!furi_string_equal(key, next_line)) continue;
key_found = true;
}
furi_string_free(next_line);
return key_found;
}
bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(key);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
FuriString* temp_key = furi_string_alloc();
nfc_dict_int_to_str(instance, key, temp_key);
bool key_found = nfc_dict_is_key_present_str(instance, temp_key);
furi_string_free(temp_key);
return key_found;
}
static bool nfc_dict_add_key_str(NfcDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
furi_string_cat_printf(key, "\n");
bool key_added = false;
do {
if(!stream_seek(instance->stream, 0, StreamOffsetFromEnd)) break;
if(!stream_insert_string(instance->stream, key)) break;
instance->total_keys++;
key_added = true;
} while(false);
furi_string_left(key, instance->key_size_symbols - 1);
return key_added;
}
bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(key);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
FuriString* temp_key = furi_string_alloc();
nfc_dict_int_to_str(instance, key, temp_key);
bool key_added = nfc_dict_add_key_str(instance, temp_key);
furi_string_free(temp_key);
return key_added;
}
bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(key);
furi_assert(instance->key_size == key_size);
bool key_removed = false;
uint8_t* temp_key = malloc(key_size);
nfc_dict_rewind(instance);
while(!key_removed) {
if(!nfc_dict_get_next_key(instance, temp_key, key_size)) break;
if(memcmp(temp_key, key, key_size) == 0) {
int32_t offset = (-1) * (instance->key_size_symbols);
stream_seek(instance->stream, offset, StreamOffsetFromCurrent);
if(!stream_delete(instance->stream, instance->key_size_symbols)) break;
instance->total_keys--;
key_removed = true;
}
}
nfc_dict_rewind(instance);
free(temp_key);
return key_removed;
}

View file

@ -1,103 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
NfcDictModeOpenExisting,
NfcDictModeOpenAlways,
} NfcDictMode;
typedef struct NfcDict NfcDict;
/** Check dictionary presence
*
* @param path - dictionary path
*
* @return true if dictionary exists, false otherwise
*/
bool nfc_dict_check_presence(const char* path);
/** Open or create dictionary
* Depending on mode, dictionary will be opened or created.
*
* @param path - dictionary path
* @param mode - NfcDictMode value
* @param key_size - size of dictionary keys in bytes
*
* @return NfcDict dictionary instance
*/
NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size);
/** Close dictionary
*
* @param instance - NfcDict dictionary instance
*/
void nfc_dict_free(NfcDict* instance);
/** Get total number of keys in dictionary
*
* @param instance - NfcDict dictionary instance
*
* @return total number of keys in dictionary
*/
uint32_t nfc_dict_get_total_keys(NfcDict* instance);
/** Rewind dictionary
*
* @param instance - NfcDict dictionary instance
*
* @return true if rewind was successful, false otherwise
*/
bool nfc_dict_rewind(NfcDict* instance);
/** Check if key is present in dictionary
*
* @param instance - NfcDict dictionary instance
* @param key - key to check
* @param key_size - size of key in bytes
*
* @return true if key is present, false otherwise
*/
bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size);
/** Get next key from dictionary
* This function will return next key from dictionary. If there are no more
* keys, it will return false, and nfc_dict_rewind() should be called.
*
* @param instance - NfcDict dictionary instance
* @param key - buffer to store key
* @param key_size - size of key in bytes
*
* @return true if key was successfully retrieved, false otherwise
*/
bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size);
/** Add key to dictionary
*
* @param instance - NfcDict dictionary instance
* @param key - key to add
* @param key_size - size of key in bytes
*
* @return true if key was successfully added, false otherwise
*/
bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size);
/** Delete key from dictionary
*
* @param instance - NfcDict dictionary instance
* @param key - key to delete
* @param key_size - size of key in bytes
*
* @return true if key was successfully deleted, false otherwise
*/
bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size);
#ifdef __cplusplus
}
#endif

View file

@ -34,6 +34,7 @@ env.Append(
File("hex.h"),
File("simple_array.h"),
File("bit_buffer.h"),
File("keys_dict.h"),
],
)

335
lib/toolbox/keys_dict.c Normal file
View file

@ -0,0 +1,335 @@
#include "keys_dict.h"
#include <storage/storage.h>
#include <flipper_format/flipper_format.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#include <toolbox/args.h>
#define TAG "KeysDict"
struct KeysDict {
Stream* stream;
size_t key_size;
size_t key_size_symbols;
size_t total_keys;
};
static inline void keys_dict_add_ending_new_line(KeysDict* instance) {
if(stream_seek(instance->stream, -1, StreamOffsetFromEnd)) {
uint8_t last_char = 0;
// Check if the last char is new line or add a new line
if(stream_read(instance->stream, &last_char, 1) == 1 && last_char != '\n') {
FURI_LOG_D(TAG, "Adding new line ending");
stream_write_char(instance->stream, '\n');
}
stream_rewind(instance->stream);
}
}
static bool keys_dict_read_key_line(KeysDict* instance, FuriString* line, bool* is_endfile) {
if(stream_read_line(instance->stream, line) == false) {
*is_endfile = true;
}
else {
FURI_LOG_T(
TAG, "Read line: %s, len: %zu", furi_string_get_cstr(line), furi_string_size(line));
bool is_comment = furi_string_get_char(line, 0) == '#';
if(!is_comment) {
furi_string_left(line, instance->key_size_symbols - 1);
}
bool is_correct_size = furi_string_size(line) == instance->key_size_symbols - 1;
return !is_comment && is_correct_size;
}
return false;
}
bool keys_dict_check_presence(const char* path) {
furi_assert(path);
Storage* storage = furi_record_open(RECORD_STORAGE);
bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK;
furi_record_close(RECORD_STORAGE);
return dict_present;
}
KeysDict* keys_dict_alloc(const char* path, KeysDictMode mode, size_t key_size) {
furi_assert(path);
furi_assert(key_size > 0);
KeysDict* instance = malloc(sizeof(KeysDict));
Storage* storage = furi_record_open(RECORD_STORAGE);
furi_assert(storage);
instance->stream = buffered_file_stream_alloc(storage);
furi_assert(instance->stream);
FS_OpenMode open_mode = (mode == KeysDictModeOpenAlways) ? FSOM_OPEN_ALWAYS :
FSOM_OPEN_EXISTING;
// Byte = 2 symbols + 1 end of line
instance->key_size = key_size;
instance->key_size_symbols = key_size * 2 + 1;
instance->total_keys = 0;
bool file_exists =
buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode);
if(!file_exists) {
buffered_file_stream_close(instance->stream);
} else {
// Eventually add new line character in the last line to avoid skipping keys
keys_dict_add_ending_new_line(instance);
}
FuriString* line = furi_string_alloc();
bool is_endfile = false;
// In this loop we only count the entries in the file
// We prefer not to load the whole file in memory for space reasons
while(file_exists && !is_endfile) {
bool read_key = keys_dict_read_key_line(instance, line, &is_endfile);
if(read_key) {
instance->total_keys++;
}
}
stream_rewind(instance->stream);
FURI_LOG_I(TAG, "Loaded dictionary with %u keys", instance->total_keys);
furi_string_free(line);
return instance;
}
void keys_dict_free(KeysDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
buffered_file_stream_close(instance->stream);
stream_free(instance->stream);
free(instance);
furi_record_close(RECORD_STORAGE);
}
static void keys_dict_int_to_str(KeysDict* instance, const uint8_t* key_int, FuriString* key_str) {
furi_assert(instance);
furi_assert(key_str);
furi_assert(key_int);
furi_string_reset(key_str);
for(size_t i = 0; i < instance->key_size; i++)
furi_string_cat_printf(key_str, "%02X", key_int[i]);
}
static void keys_dict_str_to_int(KeysDict* instance, FuriString* key_str, uint64_t* key_int) {
furi_assert(instance);
furi_assert(key_str);
furi_assert(key_int);
uint8_t key_byte_tmp;
char h, l;
*key_int = 0ULL;
for(size_t i = 0; i < instance->key_size_symbols - 1; i += 2) {
h = furi_string_get_char(key_str, i);
l = furi_string_get_char(key_str, i + 1);
args_char_to_hex(h, l, &key_byte_tmp);
*key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2));
}
}
size_t keys_dict_get_total_keys(KeysDict* instance) {
furi_assert(instance);
return instance->total_keys;
}
bool keys_dict_rewind(KeysDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
return stream_rewind(instance->stream);
}
static bool keys_dict_get_next_key_str(KeysDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(key);
bool key_read = false;
bool is_endfile = false;
furi_string_reset(key);
while(!key_read && !is_endfile) key_read = keys_dict_read_key_line(instance, key, &is_endfile);
return key_read;
}
bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
furi_assert(key);
FuriString* temp_key = furi_string_alloc();
bool key_read = keys_dict_get_next_key_str(instance, temp_key);
if(key_read) {
size_t tmp_len = key_size;
uint64_t key_int = 0;
keys_dict_str_to_int(instance, temp_key, &key_int);
while(tmp_len--) {
key[tmp_len] = (uint8_t)key_int;
key_int >>= 8;
}
}
furi_string_free(temp_key);
return key_read;
}
static bool keys_dict_is_key_present_str(KeysDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(key);
FuriString* line = furi_string_alloc();
bool is_endfile = false;
bool line_found = false;
uint32_t actual_pos = stream_tell(instance->stream);
stream_rewind(instance->stream);
while(!line_found && !is_endfile)
line_found = // The line is found if the line was read and the key is equal to the line
(keys_dict_read_key_line(instance, line, &is_endfile)) &&
(furi_string_equal(key, line));
furi_string_free(line);
// Restore the position of the stream
stream_seek(instance->stream, actual_pos, StreamOffsetFromStart);
return line_found;
}
bool keys_dict_is_key_present(KeysDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
furi_assert(key);
FuriString* temp_key = furi_string_alloc();
keys_dict_int_to_str(instance, key, temp_key);
bool key_found = keys_dict_is_key_present_str(instance, temp_key);
furi_string_free(temp_key);
return key_found;
}
static bool keys_dict_add_key_str(KeysDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(key);
furi_string_cat_str(key, "\n");
bool key_added = false;
uint32_t actual_pos = stream_tell(instance->stream);
if(stream_seek(instance->stream, 0, StreamOffsetFromEnd) &&
stream_insert_string(instance->stream, key)) {
instance->total_keys++;
key_added = true;
}
stream_seek(instance->stream, actual_pos, StreamOffsetFromStart);
return key_added;
}
bool keys_dict_add_key(KeysDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
furi_assert(key);
FuriString* temp_key = furi_string_alloc();
furi_assert(temp_key);
keys_dict_int_to_str(instance, key, temp_key);
bool key_added = keys_dict_add_key_str(instance, temp_key);
FURI_LOG_I(TAG, "Added key %s", furi_string_get_cstr(temp_key));
furi_string_free(temp_key);
return key_added;
}
bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
furi_assert(key);
bool key_removed = false;
bool is_endfile = false;
uint8_t* temp_key = malloc(key_size);
stream_rewind(instance->stream);
while(!key_removed && !is_endfile) {
if(!keys_dict_get_next_key(instance, temp_key, key_size)) {
break;
}
if(memcmp(temp_key, key, key_size) == 0) {
stream_seek(instance->stream, -instance->key_size_symbols, StreamOffsetFromCurrent);
if(stream_delete(instance->stream, instance->key_size_symbols) == false) {
break;
}
instance->total_keys--;
key_removed = true;
}
}
FuriString* tmp = furi_string_alloc();
keys_dict_int_to_str(instance, key, tmp);
FURI_LOG_I(TAG, "Removed key %s", furi_string_get_cstr(tmp));
furi_string_free(tmp);
stream_rewind(instance->stream);
free(temp_key);
return key_removed;
}

103
lib/toolbox/keys_dict.h Normal file
View file

@ -0,0 +1,103 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
KeysDictModeOpenExisting,
KeysDictModeOpenAlways,
} KeysDictMode;
typedef struct KeysDict KeysDict;
/** Check if the file list exists
*
* @param path - list path
*
* @return true if list exists, false otherwise
*/
bool keys_dict_check_presence(const char* path);
/** Open or create list
* Depending on mode, list will be opened or created.
*
* @param path - Path of the file that contain the list
* @param mode - ListKeysMode value
* @param key_size - Size of each key in bytes
*
* @return Returns KeysDict list instance
*/
KeysDict* keys_dict_alloc(const char* path, KeysDictMode mode, size_t key_size);
/** Close list
*
* @param instance - KeysDict list instance
*/
void keys_dict_free(KeysDict* instance);
/** Get total number of keys in list
*
* @param instance - KeysDict list instance
*
* @return Returns total number of keys in list
*/
size_t keys_dict_get_total_keys(KeysDict* instance);
/** Rewind list
*
* @param instance - KeysDict list instance
*
* @return Returns true if rewind was successful, false otherwise
*/
bool keys_dict_rewind(KeysDict* instance);
/** Check if key is present in list
*
* @param instance - KeysDict list instance
* @param key - key to check
* @param key_size - Size of the key in bytes
*
* @return Returns true if key is present, false otherwise
*/
bool keys_dict_is_key_present(KeysDict* instance, const uint8_t* key, size_t key_size);
/** Get next key from the list
* This function will return next key from list. If there are no more
* keys, it will return false, and keys_dict_rewind() should be called.
*
* @param instance - KeysDict list instance
* @param key - Array where to store key
* @param key_size - Size of key in bytes
*
* @return Returns true if key was successfully retrieved, false otherwise
*/
bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size);
/** Add key to list
*
* @param instance - KeysDict list instance
* @param key - Key to add
* @param key_size - Size of the key in bytes
*
* @return Returns true if key was successfully added, false otherwise
*/
bool keys_dict_add_key(KeysDict* instance, const uint8_t* key, size_t key_size);
/** Delete key from list
*
* @param instance - KeysDict list instance
* @param key - Key to delete
* @param key_size - Size of the key in bytes
*
* @return Returns true if key was successfully deleted, false otherwise
*/
bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_size);
#ifdef __cplusplus
}
#endif

View file

@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,49.3,,
Version,+,50.0,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@ -139,6 +139,7 @@ Header,+,lib/toolbox/crc32_calc.h,,
Header,+,lib/toolbox/dir_walk.h,,
Header,+,lib/toolbox/float_tools.h,,
Header,+,lib/toolbox/hex.h,,
Header,+,lib/toolbox/keys_dict.h,,
Header,+,lib/toolbox/manchester_decoder.h,,
Header,+,lib/toolbox/manchester_encoder.h,,
Header,+,lib/toolbox/name_generator.h,,
@ -1592,6 +1593,15 @@ Function,-,j1f,float,float
Function,-,jn,double,"int, double"
Function,-,jnf,float,"int, float"
Function,-,jrand48,long,unsigned short[3]
Function,+,keys_dict_add_key,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_alloc,KeysDict*,"const char*, KeysDictMode, size_t"
Function,+,keys_dict_check_presence,_Bool,const char*
Function,+,keys_dict_delete_key,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_free,void,KeysDict*
Function,+,keys_dict_get_next_key,_Bool,"KeysDict*, uint8_t*, size_t"
Function,+,keys_dict_get_total_keys,size_t,KeysDict*
Function,+,keys_dict_is_key_present,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_rewind,_Bool,KeysDict*
Function,-,l64a,char*,long
Function,-,labs,long,long
Function,-,lcong48,void,unsigned short[7]

1 entry status name type params
2 Version + 49.3 50.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
139 Header + lib/toolbox/dir_walk.h
140 Header + lib/toolbox/float_tools.h
141 Header + lib/toolbox/hex.h
142 Header + lib/toolbox/keys_dict.h
143 Header + lib/toolbox/manchester_decoder.h
144 Header + lib/toolbox/manchester_encoder.h
145 Header + lib/toolbox/name_generator.h
1593 Function - jn double int, double
1594 Function - jnf float int, float
1595 Function - jrand48 long unsigned short[3]
1596 Function + keys_dict_add_key _Bool KeysDict*, const uint8_t*, size_t
1597 Function + keys_dict_alloc KeysDict* const char*, KeysDictMode, size_t
1598 Function + keys_dict_check_presence _Bool const char*
1599 Function + keys_dict_delete_key _Bool KeysDict*, const uint8_t*, size_t
1600 Function + keys_dict_free void KeysDict*
1601 Function + keys_dict_get_next_key _Bool KeysDict*, uint8_t*, size_t
1602 Function + keys_dict_get_total_keys size_t KeysDict*
1603 Function + keys_dict_is_key_present _Bool KeysDict*, const uint8_t*, size_t
1604 Function + keys_dict_rewind _Bool KeysDict*
1605 Function - l64a char* long
1606 Function - labs long long
1607 Function - lcong48 void unsigned short[7]

View file

@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,49.3,,
Version,+,50.0,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
@ -114,7 +114,6 @@ Header,+,lib/nanopb/pb_encode.h,,
Header,+,lib/nfc/helpers/iso13239_crc.h,,
Header,+,lib/nfc/helpers/iso14443_crc.h,,
Header,+,lib/nfc/helpers/nfc_data_generator.h,,
Header,+,lib/nfc/helpers/nfc_dict.h,,
Header,+,lib/nfc/helpers/nfc_util.h,,
Header,+,lib/nfc/nfc.h,,
Header,+,lib/nfc/nfc_device.h,,
@ -204,6 +203,7 @@ Header,+,lib/toolbox/crc32_calc.h,,
Header,+,lib/toolbox/dir_walk.h,,
Header,+,lib/toolbox/float_tools.h,,
Header,+,lib/toolbox/hex.h,,
Header,+,lib/toolbox/keys_dict.h,,
Header,+,lib/toolbox/manchester_decoder.h,,
Header,+,lib/toolbox/manchester_encoder.h,,
Header,+,lib/toolbox/name_generator.h,,
@ -1967,6 +1967,15 @@ Function,-,j1f,float,float
Function,-,jn,double,"int, double"
Function,-,jnf,float,"int, float"
Function,-,jrand48,long,unsigned short[3]
Function,+,keys_dict_add_key,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_alloc,KeysDict*,"const char*, KeysDictMode, size_t"
Function,+,keys_dict_check_presence,_Bool,const char*
Function,+,keys_dict_delete_key,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_free,void,KeysDict*
Function,+,keys_dict_get_next_key,_Bool,"KeysDict*, uint8_t*, size_t"
Function,+,keys_dict_get_total_keys,size_t,KeysDict*
Function,+,keys_dict_is_key_present,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_rewind,_Bool,KeysDict*
Function,-,l64a,char*,long
Function,-,labs,long,long
Function,-,lcong48,void,unsigned short[7]
@ -2441,15 +2450,6 @@ Function,+,nfc_device_save,_Bool,"NfcDevice*, const char*"
Function,+,nfc_device_set_data,void,"NfcDevice*, NfcProtocol, const NfcDeviceData*"
Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*"
Function,+,nfc_device_set_uid,_Bool,"NfcDevice*, const uint8_t*, size_t"
Function,+,nfc_dict_add_key,_Bool,"NfcDict*, const uint8_t*, size_t"
Function,+,nfc_dict_alloc,NfcDict*,"const char*, NfcDictMode, size_t"
Function,+,nfc_dict_check_presence,_Bool,const char*
Function,+,nfc_dict_delete_key,_Bool,"NfcDict*, const uint8_t*, size_t"
Function,+,nfc_dict_free,void,NfcDict*
Function,+,nfc_dict_get_next_key,_Bool,"NfcDict*, uint8_t*, size_t"
Function,+,nfc_dict_get_total_keys,uint32_t,NfcDict*
Function,+,nfc_dict_is_key_present,_Bool,"NfcDict*, const uint8_t*, size_t"
Function,+,nfc_dict_rewind,_Bool,NfcDict*
Function,+,nfc_felica_listener_set_sensf_res_data,NfcError,"Nfc*, const uint8_t*, const uint8_t, const uint8_t*, const uint8_t"
Function,+,nfc_free,void,Nfc*
Function,+,nfc_iso14443a_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t"

1 entry status name type params
2 Version + 49.3 50.0
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/cli/cli.h
114 Header + lib/nfc/helpers/iso13239_crc.h
115 Header + lib/nfc/helpers/iso14443_crc.h
116 Header + lib/nfc/helpers/nfc_data_generator.h
Header + lib/nfc/helpers/nfc_dict.h
117 Header + lib/nfc/helpers/nfc_util.h
118 Header + lib/nfc/nfc.h
119 Header + lib/nfc/nfc_device.h
203 Header + lib/toolbox/dir_walk.h
204 Header + lib/toolbox/float_tools.h
205 Header + lib/toolbox/hex.h
206 Header + lib/toolbox/keys_dict.h
207 Header + lib/toolbox/manchester_decoder.h
208 Header + lib/toolbox/manchester_encoder.h
209 Header + lib/toolbox/name_generator.h
1967 Function - jn double int, double
1968 Function - jnf float int, float
1969 Function - jrand48 long unsigned short[3]
1970 Function + keys_dict_add_key _Bool KeysDict*, const uint8_t*, size_t
1971 Function + keys_dict_alloc KeysDict* const char*, KeysDictMode, size_t
1972 Function + keys_dict_check_presence _Bool const char*
1973 Function + keys_dict_delete_key _Bool KeysDict*, const uint8_t*, size_t
1974 Function + keys_dict_free void KeysDict*
1975 Function + keys_dict_get_next_key _Bool KeysDict*, uint8_t*, size_t
1976 Function + keys_dict_get_total_keys size_t KeysDict*
1977 Function + keys_dict_is_key_present _Bool KeysDict*, const uint8_t*, size_t
1978 Function + keys_dict_rewind _Bool KeysDict*
1979 Function - l64a char* long
1980 Function - labs long long
1981 Function - lcong48 void unsigned short[7]
2450 Function + nfc_device_set_data void NfcDevice*, NfcProtocol, const NfcDeviceData*
2451 Function + nfc_device_set_loading_callback void NfcDevice*, NfcLoadingCallback, void*
2452 Function + nfc_device_set_uid _Bool NfcDevice*, const uint8_t*, size_t
Function + nfc_dict_add_key _Bool NfcDict*, const uint8_t*, size_t
Function + nfc_dict_alloc NfcDict* const char*, NfcDictMode, size_t
Function + nfc_dict_check_presence _Bool const char*
Function + nfc_dict_delete_key _Bool NfcDict*, const uint8_t*, size_t
Function + nfc_dict_free void NfcDict*
Function + nfc_dict_get_next_key _Bool NfcDict*, uint8_t*, size_t
Function + nfc_dict_get_total_keys uint32_t NfcDict*
Function + nfc_dict_is_key_present _Bool NfcDict*, const uint8_t*, size_t
Function + nfc_dict_rewind _Bool NfcDict*
2453 Function + nfc_felica_listener_set_sensf_res_data NfcError Nfc*, const uint8_t*, const uint8_t, const uint8_t*, const uint8_t
2454 Function + nfc_free void Nfc*
2455 Function + nfc_iso14443a_listener_set_col_res_data NfcError Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t