NFC refactoring (#3050)

"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.
This commit is contained in:
gornekich
2023-10-24 07:08:09 +04:00
committed by GitHub
parent 35c903494c
commit d92b0a82cc
514 changed files with 41488 additions and 68125 deletions
+52
View File
@@ -0,0 +1,52 @@
#include "felica_crc.h"
#include <furi/furi.h>
#define FELICA_CRC_POLY (0x1021U) // Polynomial: x^16 + x^12 + x^5 + 1
#define FELICA_CRC_INIT (0x0000U)
uint16_t felica_crc_calculate(const uint8_t* data, size_t length) {
uint16_t crc = FELICA_CRC_INIT;
for(size_t i = 0; i < length; i++) {
crc ^= ((uint16_t)data[i] << 8);
for(size_t j = 0; j < 8; j++) {
if(crc & 0x8000) {
crc <<= 1;
crc ^= FELICA_CRC_POLY;
} else {
crc <<= 1;
}
}
}
return (crc << 8) | (crc >> 8);
}
void felica_crc_append(BitBuffer* buf) {
const uint8_t* data = bit_buffer_get_data(buf);
const size_t data_size = bit_buffer_get_size_bytes(buf);
const uint16_t crc = felica_crc_calculate(data, data_size);
bit_buffer_append_bytes(buf, (const uint8_t*)&crc, FELICA_CRC_SIZE);
}
bool felica_crc_check(const BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
if(data_size <= FELICA_CRC_SIZE) return false;
uint16_t crc_received;
bit_buffer_write_bytes_mid(buf, &crc_received, data_size - FELICA_CRC_SIZE, FELICA_CRC_SIZE);
const uint8_t* data = bit_buffer_get_data(buf);
const uint16_t crc_calc = felica_crc_calculate(data, data_size - FELICA_CRC_SIZE);
return (crc_calc == crc_received);
}
void felica_crc_trim(BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
furi_assert(data_size > FELICA_CRC_SIZE);
bit_buffer_set_size_bytes(buf, data_size - FELICA_CRC_SIZE);
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include "bit_buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FELICA_CRC_SIZE sizeof(uint16_t)
void felica_crc_append(BitBuffer* buf);
bool felica_crc_check(const BitBuffer* buf);
void felica_crc_trim(BitBuffer* buf);
#ifdef __cplusplus
}
#endif
+62
View File
@@ -0,0 +1,62 @@
#include "iso13239_crc.h"
#include <core/check.h>
#define ISO13239_CRC_INIT_DEFAULT (0xFFFFU)
#define ISO13239_CRC_INIT_PICOPASS (0xE012U)
#define ISO13239_CRC_POLY (0x8408U)
static uint16_t
iso13239_crc_calculate(Iso13239CrcType type, const uint8_t* data, size_t data_size) {
uint16_t crc;
if(type == Iso13239CrcTypeDefault) {
crc = ISO13239_CRC_INIT_DEFAULT;
} else if(type == Iso13239CrcTypePicopass) {
crc = ISO13239_CRC_INIT_PICOPASS;
} else {
furi_crash("Wrong ISO13239 CRC type");
}
for(size_t i = 0; i < data_size; ++i) {
crc ^= (uint16_t)data[i];
for(size_t j = 0; j < 8; ++j) {
if(crc & 1U) {
crc = (crc >> 1) ^ ISO13239_CRC_POLY;
} else {
crc >>= 1;
}
}
}
return type == Iso13239CrcTypePicopass ? crc : ~crc;
}
void iso13239_crc_append(Iso13239CrcType type, BitBuffer* buf) {
const uint8_t* data = bit_buffer_get_data(buf);
const size_t data_size = bit_buffer_get_size_bytes(buf);
const uint16_t crc = iso13239_crc_calculate(type, data, data_size);
bit_buffer_append_bytes(buf, (const uint8_t*)&crc, ISO13239_CRC_SIZE);
}
bool iso13239_crc_check(Iso13239CrcType type, const BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
if(data_size <= ISO13239_CRC_SIZE) return false;
uint16_t crc_received;
bit_buffer_write_bytes_mid(
buf, &crc_received, data_size - ISO13239_CRC_SIZE, ISO13239_CRC_SIZE);
const uint8_t* data = bit_buffer_get_data(buf);
const uint16_t crc_calc = iso13239_crc_calculate(type, data, data_size - ISO13239_CRC_SIZE);
return (crc_calc == crc_received);
}
void iso13239_crc_trim(BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
furi_assert(data_size > ISO13239_CRC_SIZE);
bit_buffer_set_size_bytes(buf, data_size - ISO13239_CRC_SIZE);
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <toolbox/bit_buffer.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ISO13239_CRC_SIZE sizeof(uint16_t)
typedef enum {
Iso13239CrcTypeDefault,
Iso13239CrcTypePicopass,
} Iso13239CrcType;
void iso13239_crc_append(Iso13239CrcType type, BitBuffer* buf);
bool iso13239_crc_check(Iso13239CrcType type, const BitBuffer* buf);
void iso13239_crc_trim(BitBuffer* buf);
#ifdef __cplusplus
}
#endif
+64
View File
@@ -0,0 +1,64 @@
#include "iso14443_4_layer.h"
#include <furi.h>
#define ISO14443_4_BLOCK_PCB (1U << 1)
#define ISO14443_4_BLOCK_PCB_I (0U)
#define ISO14443_4_BLOCK_PCB_R (5U << 5)
#define ISO14443_4_BLOCK_PCB_S (3U << 6)
struct Iso14443_4Layer {
uint8_t pcb;
uint8_t pcb_prev;
};
static inline void iso14443_4_layer_update_pcb(Iso14443_4Layer* instance) {
instance->pcb_prev = instance->pcb;
instance->pcb ^= (uint8_t)0x01;
}
Iso14443_4Layer* iso14443_4_layer_alloc() {
Iso14443_4Layer* instance = malloc(sizeof(Iso14443_4Layer));
iso14443_4_layer_reset(instance);
return instance;
}
void iso14443_4_layer_free(Iso14443_4Layer* instance) {
furi_assert(instance);
free(instance);
}
void iso14443_4_layer_reset(Iso14443_4Layer* instance) {
furi_assert(instance);
instance->pcb = ISO14443_4_BLOCK_PCB_I | ISO14443_4_BLOCK_PCB;
}
void iso14443_4_layer_encode_block(
Iso14443_4Layer* instance,
const BitBuffer* input_data,
BitBuffer* block_data) {
furi_assert(instance);
bit_buffer_append_byte(block_data, instance->pcb);
bit_buffer_append(block_data, input_data);
iso14443_4_layer_update_pcb(instance);
}
bool iso14443_4_layer_decode_block(
Iso14443_4Layer* instance,
BitBuffer* output_data,
const BitBuffer* block_data) {
furi_assert(instance);
bool ret = false;
do {
if(!bit_buffer_starts_with_byte(block_data, instance->pcb_prev)) break;
bit_buffer_copy_right(output_data, block_data, 1);
ret = true;
} while(false);
return ret;
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include <toolbox/bit_buffer.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Iso14443_4Layer Iso14443_4Layer;
Iso14443_4Layer* iso14443_4_layer_alloc();
void iso14443_4_layer_free(Iso14443_4Layer* instance);
void iso14443_4_layer_reset(Iso14443_4Layer* instance);
void iso14443_4_layer_encode_block(
Iso14443_4Layer* instance,
const BitBuffer* input_data,
BitBuffer* block_data);
bool iso14443_4_layer_decode_block(
Iso14443_4Layer* instance,
BitBuffer* output_data,
const BitBuffer* block_data);
#ifdef __cplusplus
}
#endif
+57
View File
@@ -0,0 +1,57 @@
#include "iso14443_crc.h"
#include <core/check.h>
#define ISO14443_3A_CRC_INIT (0x6363U)
#define ISO14443_3B_CRC_INIT (0xFFFFU)
static uint16_t
iso14443_crc_calculate(Iso14443CrcType type, const uint8_t* data, size_t data_size) {
uint16_t crc;
if(type == Iso14443CrcTypeA) {
crc = ISO14443_3A_CRC_INIT;
} else if(type == Iso14443CrcTypeB) {
crc = ISO14443_3B_CRC_INIT;
} else {
furi_crash("Wrong ISO14443 CRC type");
}
for(size_t i = 0; i < data_size; i++) {
uint8_t byte = data[i];
byte ^= (uint8_t)(crc & 0xff);
byte ^= byte << 4;
crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ (byte >> 4);
}
return type == Iso14443CrcTypeA ? crc : ~crc;
}
void iso14443_crc_append(Iso14443CrcType type, BitBuffer* buf) {
const uint8_t* data = bit_buffer_get_data(buf);
const size_t data_size = bit_buffer_get_size_bytes(buf);
const uint16_t crc = iso14443_crc_calculate(type, data, data_size);
bit_buffer_append_bytes(buf, (const uint8_t*)&crc, ISO14443_CRC_SIZE);
}
bool iso14443_crc_check(Iso14443CrcType type, const BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
if(data_size <= ISO14443_CRC_SIZE) return false;
uint16_t crc_received;
bit_buffer_write_bytes_mid(
buf, &crc_received, data_size - ISO14443_CRC_SIZE, ISO14443_CRC_SIZE);
const uint8_t* data = bit_buffer_get_data(buf);
const uint16_t crc_calc = iso14443_crc_calculate(type, data, data_size - ISO14443_CRC_SIZE);
return (crc_calc == crc_received);
}
void iso14443_crc_trim(BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
furi_assert(data_size > ISO14443_CRC_SIZE);
bit_buffer_set_size_bytes(buf, data_size - ISO14443_CRC_SIZE);
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <toolbox/bit_buffer.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ISO14443_CRC_SIZE sizeof(uint16_t)
typedef enum {
Iso14443CrcTypeA,
Iso14443CrcTypeB,
} Iso14443CrcType;
void iso14443_crc_append(Iso14443CrcType type, BitBuffer* buf);
bool iso14443_crc_check(Iso14443CrcType type, const BitBuffer* buf);
void iso14443_crc_trim(BitBuffer* buf);
#ifdef __cplusplus
}
#endif
-346
View File
@@ -1,346 +0,0 @@
#include "mf_classic_dict.h"
#include <lib/toolbox/args.h>
#include <lib/flipper_format/flipper_format.h>
#define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc")
#define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc")
#define MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc")
#define TAG "MfClassicDict"
#define NFC_MF_CLASSIC_KEY_LEN (13)
struct MfClassicDict {
Stream* stream;
uint32_t total_keys;
};
bool mf_classic_dict_check_presence(MfClassicDictType dict_type) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool dict_present = false;
if(dict_type == MfClassicDictTypeSystem) {
dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK;
} else if(dict_type == MfClassicDictTypeUser) {
dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK;
} else if(dict_type == MfClassicDictTypeUnitTest) {
dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_UNIT_TEST_PATH, NULL) ==
FSE_OK;
}
furi_record_close(RECORD_STORAGE);
return dict_present;
}
MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) {
MfClassicDict* dict = malloc(sizeof(MfClassicDict));
Storage* storage = furi_record_open(RECORD_STORAGE);
dict->stream = buffered_file_stream_alloc(storage);
furi_record_close(RECORD_STORAGE);
bool dict_loaded = false;
do {
if(dict_type == MfClassicDictTypeSystem) {
if(!buffered_file_stream_open(
dict->stream,
MF_CLASSIC_DICT_FLIPPER_PATH,
FSAM_READ_WRITE,
FSOM_OPEN_EXISTING)) {
buffered_file_stream_close(dict->stream);
break;
}
} else if(dict_type == MfClassicDictTypeUser) {
if(!buffered_file_stream_open(
dict->stream, MF_CLASSIC_DICT_USER_PATH, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) {
buffered_file_stream_close(dict->stream);
break;
}
} else if(dict_type == MfClassicDictTypeUnitTest) {
if(!buffered_file_stream_open(
dict->stream,
MF_CLASSIC_DICT_UNIT_TEST_PATH,
FSAM_READ_WRITE,
FSOM_OPEN_ALWAYS)) {
buffered_file_stream_close(dict->stream);
break;
}
}
// Check for new line ending
if(!stream_eof(dict->stream)) {
if(!stream_seek(dict->stream, -1, StreamOffsetFromEnd)) break;
uint8_t last_char = 0;
if(stream_read(dict->stream, &last_char, 1) != 1) break;
if(last_char != '\n') {
FURI_LOG_D(TAG, "Adding new line ending");
if(stream_write_char(dict->stream, '\n') != 1) break;
}
if(!stream_rewind(dict->stream)) break;
}
// Read total amount of keys
FuriString* next_line;
next_line = furi_string_alloc();
while(true) {
if(!stream_read_line(dict->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) != NFC_MF_CLASSIC_KEY_LEN) continue;
dict->total_keys++;
}
furi_string_free(next_line);
stream_rewind(dict->stream);
dict_loaded = true;
FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", dict->total_keys);
} while(false);
if(!dict_loaded) {
buffered_file_stream_close(dict->stream);
free(dict);
dict = NULL;
}
return dict;
}
void mf_classic_dict_free(MfClassicDict* dict) {
furi_assert(dict);
furi_assert(dict->stream);
buffered_file_stream_close(dict->stream);
stream_free(dict->stream);
free(dict);
}
static void mf_classic_dict_int_to_str(uint8_t* key_int, FuriString* key_str) {
furi_string_reset(key_str);
for(size_t i = 0; i < 6; i++) {
furi_string_cat_printf(key_str, "%02X", key_int[i]);
}
}
static void mf_classic_dict_str_to_int(FuriString* key_str, uint64_t* key_int) {
uint8_t key_byte_tmp;
*key_int = 0ULL;
for(uint8_t i = 0; i < 12; 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 * (5 - i / 2));
}
}
uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict) {
furi_assert(dict);
return dict->total_keys;
}
bool mf_classic_dict_rewind(MfClassicDict* dict) {
furi_assert(dict);
furi_assert(dict->stream);
return stream_rewind(dict->stream);
}
bool mf_classic_dict_get_next_key_str(MfClassicDict* dict, FuriString* key) {
furi_assert(dict);
furi_assert(dict->stream);
bool key_read = false;
furi_string_reset(key);
while(!key_read) {
if(!stream_read_line(dict->stream, key)) break;
if(furi_string_get_char(key, 0) == '#') continue;
if(furi_string_size(key) != NFC_MF_CLASSIC_KEY_LEN) continue;
furi_string_left(key, 12);
key_read = true;
}
return key_read;
}
bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* temp_key;
temp_key = furi_string_alloc();
bool key_read = mf_classic_dict_get_next_key_str(dict, temp_key);
if(key_read) {
mf_classic_dict_str_to_int(temp_key, key);
}
furi_string_free(temp_key);
return key_read;
}
bool mf_classic_dict_is_key_present_str(MfClassicDict* dict, FuriString* key) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* next_line;
next_line = furi_string_alloc();
bool key_found = false;
stream_rewind(dict->stream);
while(!key_found) { //-V654
if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
furi_string_left(next_line, 12);
if(!furi_string_equal(key, next_line)) continue;
key_found = true;
}
furi_string_free(next_line);
return key_found;
}
bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key) {
FuriString* temp_key;
temp_key = furi_string_alloc();
mf_classic_dict_int_to_str(key, temp_key);
bool key_found = mf_classic_dict_is_key_present_str(dict, temp_key);
furi_string_free(temp_key);
return key_found;
}
bool mf_classic_dict_add_key_str(MfClassicDict* dict, FuriString* key) {
furi_assert(dict);
furi_assert(dict->stream);
furi_string_cat_printf(key, "\n");
bool key_added = false;
do {
if(!stream_seek(dict->stream, 0, StreamOffsetFromEnd)) break;
if(!stream_insert_string(dict->stream, key)) break;
dict->total_keys++;
key_added = true;
} while(false);
furi_string_left(key, 12);
return key_added;
}
bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* temp_key;
temp_key = furi_string_alloc();
mf_classic_dict_int_to_str(key, temp_key);
bool key_added = mf_classic_dict_add_key_str(dict, temp_key);
furi_string_free(temp_key);
return key_added;
}
bool mf_classic_dict_get_key_at_index_str(MfClassicDict* dict, FuriString* key, uint32_t target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* next_line;
uint32_t index = 0;
next_line = furi_string_alloc();
furi_string_reset(key);
bool key_found = false;
while(!key_found) {
if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
if(index++ != target) continue;
furi_string_set_n(key, next_line, 0, 12);
key_found = true;
}
furi_string_free(next_line);
return key_found;
}
bool mf_classic_dict_get_key_at_index(MfClassicDict* dict, uint64_t* key, uint32_t target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* temp_key;
temp_key = furi_string_alloc();
bool key_found = mf_classic_dict_get_key_at_index_str(dict, temp_key, target);
if(key_found) {
mf_classic_dict_str_to_int(temp_key, key);
}
furi_string_free(temp_key);
return key_found;
}
bool mf_classic_dict_find_index_str(MfClassicDict* dict, FuriString* key, uint32_t* target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* next_line;
next_line = furi_string_alloc();
bool key_found = false;
uint32_t index = 0;
stream_rewind(dict->stream);
while(!key_found) { //-V654
if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
furi_string_left(next_line, 12);
if(!furi_string_equal(key, next_line)) continue;
key_found = true;
*target = index;
}
furi_string_free(next_line);
return key_found;
}
bool mf_classic_dict_find_index(MfClassicDict* dict, uint8_t* key, uint32_t* target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* temp_key;
temp_key = furi_string_alloc();
mf_classic_dict_int_to_str(key, temp_key);
bool key_found = mf_classic_dict_find_index_str(dict, temp_key, target);
furi_string_free(temp_key);
return key_found;
}
bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* next_line;
next_line = furi_string_alloc();
uint32_t index = 0;
bool key_removed = false;
while(!key_removed) {
if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
if(index++ != target) continue;
stream_seek(dict->stream, -NFC_MF_CLASSIC_KEY_LEN, StreamOffsetFromCurrent);
if(!stream_delete(dict->stream, NFC_MF_CLASSIC_KEY_LEN)) break;
dict->total_keys--;
key_removed = true;
}
furi_string_free(next_line);
return key_removed;
}
-107
View File
@@ -1,107 +0,0 @@
#pragma once
#include <stdbool.h>
#include <storage/storage.h>
#include <lib/flipper_format/flipper_format.h>
#include <lib/toolbox/stream/file_stream.h>
#include <lib/toolbox/stream/buffered_file_stream.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
MfClassicDictTypeUser,
MfClassicDictTypeSystem,
MfClassicDictTypeUnitTest,
} MfClassicDictType;
typedef struct MfClassicDict MfClassicDict;
bool mf_classic_dict_check_presence(MfClassicDictType dict_type);
/** Allocate MfClassicDict instance
*
* @param[in] dict_type The dictionary type
*
* @return MfClassicDict instance
*/
MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type);
/** Free MfClassicDict instance
*
* @param dict MfClassicDict instance
*/
void mf_classic_dict_free(MfClassicDict* dict);
/** Get total keys count
*
* @param dict MfClassicDict instance
*
* @return total keys count
*/
uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict);
/** Rewind to the beginning
*
* @param dict MfClassicDict instance
*
* @return true on success
*/
bool mf_classic_dict_rewind(MfClassicDict* dict);
bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key);
bool mf_classic_dict_is_key_present_str(MfClassicDict* dict, FuriString* key);
bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key);
bool mf_classic_dict_get_next_key_str(MfClassicDict* dict, FuriString* key);
/** Get key at target offset as uint64_t
*
* @param dict MfClassicDict instance
* @param[out] key Pointer to the uint64_t key
* @param[in] target Target offset from current position
*
* @return true on success
*/
bool mf_classic_dict_get_key_at_index(MfClassicDict* dict, uint64_t* key, uint32_t target);
/** Get key at target offset as string_t
*
* @param dict MfClassicDict instance
* @param[out] key Found key destination buffer
* @param[in] target Target offset from current position
*
* @return true on success
*/
bool mf_classic_dict_get_key_at_index_str(MfClassicDict* dict, FuriString* key, uint32_t target);
bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key);
/** Add string representation of the key
*
* @param dict MfClassicDict instance
* @param[in] key String representation of the key
*
* @return true on success
*/
bool mf_classic_dict_add_key_str(MfClassicDict* dict, FuriString* key);
bool mf_classic_dict_find_index(MfClassicDict* dict, uint8_t* key, uint32_t* target);
bool mf_classic_dict_find_index_str(MfClassicDict* dict, FuriString* key, uint32_t* target);
/** Delete key at target offset
*
* @param dict MfClassicDict instance
* @param[in] target Target offset from current position
*
* @return true on success
*/
bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target);
#ifdef __cplusplus
}
#endif
-228
View File
@@ -1,228 +0,0 @@
#include "mfkey32.h"
#include <furi/furi.h>
#include <storage/storage.h>
#include <stream/stream.h>
#include <stream/buffered_file_stream.h>
#include <m-array.h>
#include <lib/nfc/protocols/mifare_classic.h>
#include <lib/nfc/protocols/nfc_util.h>
#define TAG "Mfkey32"
#define MFKEY32_LOGS_PATH EXT_PATH("nfc/.mfkey32.log")
typedef enum {
Mfkey32StateIdle,
Mfkey32StateAuthReceived,
Mfkey32StateAuthNtSent,
Mfkey32StateAuthArNrReceived,
} Mfkey32State;
typedef struct {
uint32_t cuid;
uint8_t sector;
MfClassicKey key;
uint32_t nt0;
uint32_t nr0;
uint32_t ar0;
uint32_t nt1;
uint32_t nr1;
uint32_t ar1;
} Mfkey32Params;
ARRAY_DEF(Mfkey32Params, Mfkey32Params, M_POD_OPLIST);
typedef struct {
uint8_t sector;
MfClassicKey key;
uint32_t nt;
uint32_t nr;
uint32_t ar;
} Mfkey32Nonce;
struct Mfkey32 {
Mfkey32State state;
Stream* file_stream;
Mfkey32Params_t params_arr;
Mfkey32Nonce nonce;
uint32_t cuid;
Mfkey32ParseDataCallback callback;
void* context;
};
Mfkey32* mfkey32_alloc(uint32_t cuid) {
Mfkey32* instance = malloc(sizeof(Mfkey32));
instance->cuid = cuid;
instance->state = Mfkey32StateIdle;
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->file_stream = buffered_file_stream_alloc(storage);
if(!buffered_file_stream_open(
instance->file_stream, MFKEY32_LOGS_PATH, FSAM_WRITE, FSOM_OPEN_APPEND)) {
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
free(instance);
instance = NULL;
} else {
Mfkey32Params_init(instance->params_arr);
}
furi_record_close(RECORD_STORAGE);
return instance;
}
void mfkey32_free(Mfkey32* instance) {
furi_assert(instance != NULL);
Mfkey32Params_clear(instance->params_arr);
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
free(instance);
}
void mfkey32_set_callback(Mfkey32* instance, Mfkey32ParseDataCallback callback, void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
static bool mfkey32_write_params(Mfkey32* instance, Mfkey32Params* params) {
FuriString* str = furi_string_alloc_printf(
"Sec %d key %c cuid %08lx nt0 %08lx nr0 %08lx ar0 %08lx nt1 %08lx nr1 %08lx ar1 %08lx\n",
params->sector,
params->key == MfClassicKeyA ? 'A' : 'B',
params->cuid,
params->nt0,
params->nr0,
params->ar0,
params->nt1,
params->nr1,
params->ar1);
bool write_success = stream_write_string(instance->file_stream, str);
furi_string_free(str);
return write_success;
}
static void mfkey32_add_params(Mfkey32* instance) {
Mfkey32Nonce* nonce = &instance->nonce;
bool nonce_added = false;
// Search if we partially collected params
if(Mfkey32Params_size(instance->params_arr)) {
Mfkey32Params_it_t it;
for(Mfkey32Params_it(it, instance->params_arr); !Mfkey32Params_end_p(it);
Mfkey32Params_next(it)) {
Mfkey32Params* params = Mfkey32Params_ref(it);
if((params->sector == nonce->sector) && (params->key == nonce->key)) {
params->nt1 = nonce->nt;
params->nr1 = nonce->nr;
params->ar1 = nonce->ar;
nonce_added = true;
FURI_LOG_I(
TAG,
"Params for sector %d key %c collected",
params->sector,
params->key == MfClassicKeyA ? 'A' : 'B');
// Write on sd card
if(mfkey32_write_params(instance, params)) {
Mfkey32Params_remove(instance->params_arr, it);
if(instance->callback) {
instance->callback(Mfkey32EventParamCollected, instance->context);
}
}
}
}
}
if(!nonce_added) {
Mfkey32Params params = {
.sector = nonce->sector,
.key = nonce->key,
.cuid = instance->cuid,
.nt0 = nonce->nt,
.nr0 = nonce->nr,
.ar0 = nonce->ar,
};
Mfkey32Params_push_back(instance->params_arr, params);
}
}
void mfkey32_process_data(
Mfkey32* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped) {
furi_assert(instance);
furi_assert(data);
Mfkey32Nonce* nonce = &instance->nonce;
uint16_t data_len = len;
if((data_len > 3) && !crc_dropped) {
data_len -= 2;
}
bool data_processed = false;
if(instance->state == Mfkey32StateIdle) {
if(reader_to_tag) {
if((data[0] == 0x60) || (data[0] == 0x61)) {
nonce->key = data[0] == 0x60 ? MfClassicKeyA : MfClassicKeyB;
nonce->sector = mf_classic_get_sector_by_block(data[1]);
instance->state = Mfkey32StateAuthReceived;
data_processed = true;
}
}
} else if(instance->state == Mfkey32StateAuthReceived) {
if(!reader_to_tag) {
if(len == 4) {
nonce->nt = nfc_util_bytes2num(data, 4);
instance->state = Mfkey32StateAuthNtSent;
data_processed = true;
}
}
} else if(instance->state == Mfkey32StateAuthNtSent) {
if(reader_to_tag) {
if(len == 8) {
nonce->nr = nfc_util_bytes2num(data, 4);
nonce->ar = nfc_util_bytes2num(&data[4], 4);
mfkey32_add_params(instance);
instance->state = Mfkey32StateIdle;
}
}
}
if(!data_processed) {
instance->state = Mfkey32StateIdle;
}
}
uint16_t mfkey32_get_auth_sectors(FuriString* data_str) {
furi_assert(data_str);
uint16_t nonces_num = 0;
Storage* storage = furi_record_open(RECORD_STORAGE);
Stream* file_stream = buffered_file_stream_alloc(storage);
FuriString* temp_str;
temp_str = furi_string_alloc();
do {
if(!buffered_file_stream_open(
file_stream, MFKEY32_LOGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING))
break;
while(true) {
if(!stream_read_line(file_stream, temp_str)) break;
size_t uid_pos = furi_string_search(temp_str, "cuid");
furi_string_left(temp_str, uid_pos);
furi_string_push_back(temp_str, '\n');
furi_string_cat(data_str, temp_str);
nonces_num++;
}
} while(false);
buffered_file_stream_close(file_stream);
stream_free(file_stream);
furi_string_free(temp_str);
return nonces_num;
}
-34
View File
@@ -1,34 +0,0 @@
#pragma once
#include <lib/nfc/protocols/mifare_classic.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Mfkey32 Mfkey32;
typedef enum {
Mfkey32EventParamCollected,
} Mfkey32Event;
typedef void (*Mfkey32ParseDataCallback)(Mfkey32Event event, void* context);
Mfkey32* mfkey32_alloc(uint32_t cuid);
void mfkey32_free(Mfkey32* instance);
void mfkey32_process_data(
Mfkey32* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped);
void mfkey32_set_callback(Mfkey32* instance, Mfkey32ParseDataCallback callback, void* context);
uint16_t mfkey32_get_auth_sectors(FuriString* string);
#ifdef __cplusplus
}
#endif
+566
View File
@@ -0,0 +1,566 @@
#include "nfc_data_generator.h"
#include <furi/furi.h>
#include <furi_hal_random.h>
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
#include <nfc/protocols/mf_classic/mf_classic.h>
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
#define NXP_MANUFACTURER_ID (0x04)
typedef void (*NfcDataGeneratorHandler)(NfcDevice* nfc_device);
typedef struct {
const char* name;
NfcDataGeneratorHandler handler;
} NfcDataGenerator;
static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03};
static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03};
static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03};
static const uint8_t default_data_ntag203[] =
{0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE};
static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00};
static void nfc_generate_mf_ul_uid(uint8_t* uid) {
uid[0] = NXP_MANUFACTURER_ID;
furi_hal_random_fill_buf(&uid[1], 6);
// I'm not sure how this is generated, but the upper nybble always seems to be 8
uid[6] &= 0x0F;
uid[6] |= 0x80;
}
static void nfc_generate_mf_ul_common(MfUltralightData* mfu_data) {
mfu_data->iso14443_3a_data->uid_len = 7;
nfc_generate_mf_ul_uid(mfu_data->iso14443_3a_data->uid);
mfu_data->iso14443_3a_data->atqa[0] = 0x44;
mfu_data->iso14443_3a_data->atqa[1] = 0x00;
mfu_data->iso14443_3a_data->sak = 0x00;
}
static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) {
*bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
*bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6];
}
static void nfc_generate_mf_ul_copy_uid_with_bcc(MfUltralightData* mfu_data) {
memcpy(mfu_data->page[0].data, mfu_data->iso14443_3a_data->uid, 3);
memcpy(mfu_data->page[1].data, &mfu_data->iso14443_3a_data->uid[3], 4);
nfc_generate_calc_bcc(
mfu_data->iso14443_3a_data->uid, &mfu_data->page[0].data[3], &mfu_data->page[2].data[0]);
}
static void nfc_generate_mf_ul_orig(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_common(mfu_data);
mfu_data->type = MfUltralightTypeUnknown;
mfu_data->pages_total = 16;
mfu_data->pages_read = 16;
nfc_generate_mf_ul_copy_uid_with_bcc(mfu_data);
memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage));
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_ul_with_config_common(MfUltralightData* mfu_data, uint8_t num_pages) {
nfc_generate_mf_ul_common(mfu_data);
mfu_data->pages_total = num_pages;
mfu_data->pages_read = num_pages;
nfc_generate_mf_ul_copy_uid_with_bcc(mfu_data);
uint16_t config_index = (num_pages - 4);
mfu_data->page[config_index].data[0] = 0x04; // STRG_MOD_EN
mfu_data->page[config_index].data[3] = 0xff; // AUTH0
mfu_data->page[config_index + 1].data[1] = 0x05; // VCTID
memset(&mfu_data->page[config_index + 2], 0xff, sizeof(MfUltralightPage)); // Default PWD
if(num_pages > 20) {
mfu_data->page[config_index - 1].data[3] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT;
}
}
static void nfc_generate_mf_ul_ev1_common(MfUltralightData* mfu_data, uint8_t num_pages) {
nfc_generate_mf_ul_with_config_common(mfu_data, num_pages);
memcpy(&mfu_data->version, version_bytes_mf0ulx1, sizeof(MfUltralightVersion));
for(size_t i = 0; i < 3; ++i) {
mfu_data->tearing_flag[i].data = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT;
}
}
static void nfc_generate_mf_ul_11(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_ev1_common(mfu_data, 20);
mfu_data->type = MfUltralightTypeUL11;
mfu_data->version.prod_subtype = 0x01;
mfu_data->version.storage_size = 0x0B;
mfu_data->page[16].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_ul_h11(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_ev1_common(mfu_data, 20);
mfu_data->type = MfUltralightTypeUL11;
mfu_data->version.prod_subtype = 0x02;
mfu_data->version.storage_size = 0x0B;
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_ul_21(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_ev1_common(mfu_data, 41);
mfu_data->type = MfUltralightTypeUL21;
mfu_data->version.prod_subtype = 0x01;
mfu_data->version.storage_size = 0x0E;
mfu_data->page[37].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_ul_h21(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_ev1_common(mfu_data, 41);
mfu_data->type = MfUltralightTypeUL21;
mfu_data->version.prod_subtype = 0x02;
mfu_data->version.storage_size = 0x0E;
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag203(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_common(mfu_data);
mfu_data->type = MfUltralightTypeNTAG203;
mfu_data->pages_total = 42;
mfu_data->pages_read = 42;
nfc_generate_mf_ul_copy_uid_with_bcc(mfu_data);
mfu_data->page[2].data[1] = 0x48; // Internal byte
memcpy(&mfu_data->page[3], default_data_ntag203, sizeof(MfUltralightPage)); //-V1086
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag21x_common(MfUltralightData* mfu_data, uint8_t num_pages) {
nfc_generate_mf_ul_with_config_common(mfu_data, num_pages);
memcpy(&mfu_data->version, version_bytes_ntag21x, sizeof(MfUltralightVersion));
mfu_data->page[2].data[1] = 0x48; // Internal byte
// Capability container
mfu_data->page[3].data[0] = 0xE1;
mfu_data->page[3].data[1] = 0x10;
}
static void nfc_generate_ntag213(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag21x_common(mfu_data, 45);
mfu_data->type = MfUltralightTypeNTAG213;
mfu_data->version.storage_size = 0x0F;
mfu_data->page[3].data[2] = 0x12;
// Default contents
memcpy(&mfu_data->page[4], default_data_ntag213, sizeof(default_data_ntag213));
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag215(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag21x_common(mfu_data, 135);
mfu_data->type = MfUltralightTypeNTAG215;
mfu_data->version.storage_size = 0x11;
mfu_data->page[3].data[2] = 0x3E;
// Default contents
memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216));
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag216(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag21x_common(mfu_data, 231);
mfu_data->type = MfUltralightTypeNTAG216;
mfu_data->version.storage_size = 0x13;
mfu_data->page[3].data[2] = 0x6D;
// Default contents
memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216));
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag_i2c_common(
MfUltralightData* mfu_data,
MfUltralightType type,
uint16_t num_pages) {
nfc_generate_mf_ul_common(mfu_data);
mfu_data->type = type;
memcpy(&mfu_data->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c));
mfu_data->pages_total = num_pages;
mfu_data->pages_read = num_pages;
memcpy(
mfu_data->page[0].data,
mfu_data->iso14443_3a_data->uid,
mfu_data->iso14443_3a_data->uid_len);
mfu_data->page[1].data[3] = mfu_data->iso14443_3a_data->sak;
mfu_data->page[2].data[0] = mfu_data->iso14443_3a_data->atqa[0];
mfu_data->page[2].data[1] = mfu_data->iso14443_3a_data->atqa[1];
uint16_t config_register_page = 0;
uint16_t session_register_page = 0;
// Sync with mifare_ultralight.c
switch(type) {
case MfUltralightTypeNTAGI2C1K:
config_register_page = 227;
session_register_page = 229;
break;
case MfUltralightTypeNTAGI2C2K:
config_register_page = 481;
session_register_page = 483;
break;
case MfUltralightTypeNTAGI2CPlus1K:
case MfUltralightTypeNTAGI2CPlus2K:
config_register_page = 232;
session_register_page = 234;
break;
default:
furi_crash("Unknown MFUL");
break;
}
memcpy(
&mfu_data->page[config_register_page],
default_config_ntag_i2c,
sizeof(default_config_ntag_i2c));
memcpy(
&mfu_data->page[session_register_page],
default_config_ntag_i2c,
sizeof(default_config_ntag_i2c));
}
static void nfc_generate_ntag_i2c_1k(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag_i2c_common(mfu_data, MfUltralightTypeNTAGI2C1K, 231);
mfu_data->version.prod_ver_minor = 0x01;
mfu_data->version.storage_size = 0x13;
memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
mfu_data->page[3].data[2] = 0x6D; // Size of tag in CC
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag_i2c_2k(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag_i2c_common(mfu_data, MfUltralightTypeNTAGI2C2K, 485);
mfu_data->version.prod_ver_minor = 0x01;
mfu_data->version.storage_size = 0x15;
memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
mfu_data->page[3].data[2] = 0xEA; // Size of tag in CC
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag_i2c_plus_common(
MfUltralightData* mfu_data,
MfUltralightType type,
uint16_t num_pages) {
nfc_generate_ntag_i2c_common(mfu_data, type, num_pages);
uint16_t config_index = 227;
mfu_data->page[config_index].data[3] = 0xff; // AUTH0
memset(&mfu_data->page[config_index + 2], 0xFF, sizeof(MfUltralightPage)); // Default PWD
}
static void nfc_generate_ntag_i2c_plus_1k(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag_i2c_plus_common(mfu_data, MfUltralightTypeNTAGI2CPlus1K, 236);
mfu_data->version.prod_ver_minor = 0x02;
mfu_data->version.storage_size = 0x13;
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag_i2c_plus_2k(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag_i2c_plus_common(mfu_data, MfUltralightTypeNTAGI2CPlus2K, 492);
mfu_data->version.prod_ver_minor = 0x02;
mfu_data->version.storage_size = 0x15;
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) {
uid[0] = NXP_MANUFACTURER_ID;
furi_hal_random_fill_buf(&uid[1], length - 1);
}
static void
nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) {
data->iso14443_3a_data->uid_len = uid_len;
data->iso14443_3a_data->atqa[0] = 0x44;
data->iso14443_3a_data->atqa[1] = 0x00;
data->iso14443_3a_data->sak = 0x08;
data->type = type;
}
static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) {
// All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h.
MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].data;
sec_tr->access_bits.data[0] = 0xFF;
sec_tr->access_bits.data[1] = 0x07;
sec_tr->access_bits.data[2] = 0x80;
sec_tr->access_bits.data[3] = 0x69; // Nice
mf_classic_set_block_read(data, block, &data->block[block]);
mf_classic_set_key_found(
data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF);
mf_classic_set_key_found(
data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeB, 0xFFFFFFFFFFFF);
}
static void nfc_generate_mf_classic_block_0(
uint8_t* block,
uint8_t uid_len,
uint8_t sak,
uint8_t atqa0,
uint8_t atqa1) {
// Block length is always 16 bytes, and the UID can be either 4 or 7 bytes
furi_assert(uid_len == 4 || uid_len == 7);
furi_assert(block);
if(uid_len == 4) {
// Calculate BCC
block[uid_len] = 0;
for(int i = 0; i < uid_len; i++) {
block[uid_len] ^= block[i];
}
} else {
uid_len -= 1;
}
block[uid_len + 1] = sak;
block[uid_len + 2] = atqa0;
block[uid_len + 3] = atqa1;
for(int i = uid_len + 4; i < 16; i++) {
block[i] = 0xFF;
}
}
static void nfc_generate_mf_classic(NfcDevice* nfc_device, uint8_t uid_len, MfClassicType type) {
MfClassicData* mfc_data = mf_classic_alloc();
nfc_generate_mf_classic_uid(mfc_data->block[0].data, uid_len);
nfc_generate_mf_classic_common(mfc_data, uid_len, type);
// Set the UID
mfc_data->iso14443_3a_data->uid[0] = NXP_MANUFACTURER_ID;
for(int i = 1; i < uid_len; i++) {
mfc_data->iso14443_3a_data->uid[i] = mfc_data->block[0].data[i];
}
mf_classic_set_block_read(mfc_data, 0, &mfc_data->block[0]);
uint16_t block_num = mf_classic_get_total_block_num(type);
if(type == MfClassicType4k) {
// Set every block to 0xFF
for(uint16_t i = 1; i < block_num; i++) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc_data, i);
} else {
memset(&mfc_data->block[i].data, 0xFF, 16);
}
mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]);
}
// Set SAK to 18
mfc_data->iso14443_3a_data->sak = 0x18;
} else if(type == MfClassicType1k) {
// Set every block to 0xFF
for(uint16_t i = 1; i < block_num; i++) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc_data, i);
} else {
memset(&mfc_data->block[i].data, 0xFF, 16);
}
mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]);
}
// Set SAK to 08
mfc_data->iso14443_3a_data->sak = 0x08;
} else if(type == MfClassicTypeMini) {
// Set every block to 0xFF
for(uint16_t i = 1; i < block_num; i++) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc_data, i);
} else {
memset(&mfc_data->block[i].data, 0xFF, 16);
}
mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]);
}
// Set SAK to 09
mfc_data->iso14443_3a_data->sak = 0x09;
}
nfc_generate_mf_classic_block_0(
mfc_data->block[0].data,
uid_len,
mfc_data->iso14443_3a_data->sak,
mfc_data->iso14443_3a_data->atqa[0],
mfc_data->iso14443_3a_data->atqa[1]);
mfc_data->type = type;
nfc_device_set_data(nfc_device, NfcProtocolMfClassic, mfc_data);
mf_classic_free(mfc_data);
}
static void nfc_generate_mf_classic_mini(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 4, MfClassicTypeMini);
}
static void nfc_generate_mf_classic_1k_4b_uid(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 4, MfClassicType1k);
}
static void nfc_generate_mf_classic_1k_7b_uid(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 7, MfClassicType1k);
}
static void nfc_generate_mf_classic_4k_4b_uid(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 4, MfClassicType4k);
}
static void nfc_generate_mf_classic_4k_7b_uid(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 7, MfClassicType4k);
}
static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = {
[NfcDataGeneratorTypeMfUltralight] =
{
.name = "Mifare Ultralight",
.handler = nfc_generate_mf_ul_orig,
},
[NfcDataGeneratorTypeMfUltralightEV1_11] =
{
.name = "Mifare Ultralight EV1 11",
.handler = nfc_generate_mf_ul_11,
},
[NfcDataGeneratorTypeMfUltralightEV1_H11] =
{
.name = "Mifare Ultralight EV1 H11",
.handler = nfc_generate_mf_ul_h11,
},
[NfcDataGeneratorTypeMfUltralightEV1_21] =
{
.name = "Mifare Ultralight EV1 21",
.handler = nfc_generate_mf_ul_21,
},
[NfcDataGeneratorTypeMfUltralightEV1_H21] =
{
.name = "Mifare Ultralight EV1 H21",
.handler = nfc_generate_mf_ul_h21,
},
[NfcDataGeneratorTypeNTAG203] =
{
.name = "NTAG203",
.handler = nfc_generate_ntag203,
},
[NfcDataGeneratorTypeNTAG213] =
{
.name = "NTAG213",
.handler = nfc_generate_ntag213,
},
[NfcDataGeneratorTypeNTAG215] =
{
.name = "NTAG215",
.handler = nfc_generate_ntag215,
},
[NfcDataGeneratorTypeNTAG216] =
{
.name = "NTAG216",
.handler = nfc_generate_ntag216,
},
[NfcDataGeneratorTypeNTAGI2C1k] =
{
.name = "NTAG I2C 1k",
.handler = nfc_generate_ntag_i2c_1k,
},
[NfcDataGeneratorTypeNTAGI2C2k] =
{
.name = "NTAG I2C 2k",
.handler = nfc_generate_ntag_i2c_2k,
},
[NfcDataGeneratorTypeNTAGI2CPlus1k] =
{
.name = "NTAG I2C Plus 1k",
.handler = nfc_generate_ntag_i2c_plus_1k,
},
[NfcDataGeneratorTypeNTAGI2CPlus2k] =
{
.name = "NTAG I2C Plus 2k",
.handler = nfc_generate_ntag_i2c_plus_2k,
},
[NfcDataGeneratorTypeMfClassicMini] =
{
.name = "Mifare Mini",
.handler = nfc_generate_mf_classic_mini,
},
[NfcDataGeneratorTypeMfClassic1k_4b] =
{
.name = "Mifare Classic 1k 4byte UID",
.handler = nfc_generate_mf_classic_1k_4b_uid,
},
[NfcDataGeneratorTypeMfClassic1k_7b] =
{
.name = "Mifare Classic 1k 7byte UID",
.handler = nfc_generate_mf_classic_1k_7b_uid,
},
[NfcDataGeneratorTypeMfClassic4k_4b] =
{
.name = "Mifare Classic 4k 4byte UID",
.handler = nfc_generate_mf_classic_4k_4b_uid,
},
[NfcDataGeneratorTypeMfClassic4k_7b] =
{
.name = "Mifare Classic 4k 7byte UID",
.handler = nfc_generate_mf_classic_4k_7b_uid,
},
};
const char* nfc_data_generator_get_name(NfcDataGeneratorType type) {
return nfc_data_generator[type].name;
}
void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevice* nfc_device) {
nfc_data_generator[type].handler(nfc_device);
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <nfc/nfc_device.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
NfcDataGeneratorTypeMfUltralight,
NfcDataGeneratorTypeMfUltralightEV1_11,
NfcDataGeneratorTypeMfUltralightEV1_H11,
NfcDataGeneratorTypeMfUltralightEV1_21,
NfcDataGeneratorTypeMfUltralightEV1_H21,
NfcDataGeneratorTypeNTAG203,
NfcDataGeneratorTypeNTAG213,
NfcDataGeneratorTypeNTAG215,
NfcDataGeneratorTypeNTAG216,
NfcDataGeneratorTypeNTAGI2C1k,
NfcDataGeneratorTypeNTAGI2C2k,
NfcDataGeneratorTypeNTAGI2CPlus1k,
NfcDataGeneratorTypeNTAGI2CPlus2k,
NfcDataGeneratorTypeMfClassicMini,
NfcDataGeneratorTypeMfClassic1k_4b,
NfcDataGeneratorTypeMfClassic1k_7b,
NfcDataGeneratorTypeMfClassic4k_4b,
NfcDataGeneratorTypeMfClassic4k_7b,
NfcDataGeneratorTypeNum,
} NfcDataGeneratorType;
const char* nfc_data_generator_get_name(NfcDataGeneratorType type);
void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevice* nfc_device);
#ifdef __cplusplus
}
#endif
-71
View File
@@ -1,71 +0,0 @@
#include "nfc_debug_log.h"
#include <storage/storage.h>
#include <stream/buffered_file_stream.h>
#define TAG "NfcDebugLog"
#define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.txt")
struct NfcDebugLog {
Stream* file_stream;
FuriString* data_str;
};
NfcDebugLog* nfc_debug_log_alloc() {
NfcDebugLog* instance = malloc(sizeof(NfcDebugLog));
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->file_stream = buffered_file_stream_alloc(storage);
if(!buffered_file_stream_open(
instance->file_stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) {
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
instance->file_stream = NULL;
}
if(!instance->file_stream) {
free(instance);
instance = NULL;
} else {
instance->data_str = furi_string_alloc();
}
furi_record_close(RECORD_STORAGE);
return instance;
}
void nfc_debug_log_free(NfcDebugLog* instance) {
furi_assert(instance);
furi_assert(instance->file_stream);
furi_assert(instance->data_str);
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
furi_string_free(instance->data_str);
free(instance);
}
void nfc_debug_log_process_data(
NfcDebugLog* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped) {
furi_assert(instance);
furi_assert(instance->file_stream);
furi_assert(instance->data_str);
furi_assert(data);
UNUSED(crc_dropped);
furi_string_printf(instance->data_str, "%lu %c:", furi_get_tick(), reader_to_tag ? 'R' : 'T');
uint16_t data_len = len;
for(size_t i = 0; i < data_len; i++) {
furi_string_cat_printf(instance->data_str, " %02x", data[i]);
}
furi_string_push_back(instance->data_str, '\n');
stream_write_string(instance->file_stream, instance->data_str);
}
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef struct NfcDebugLog NfcDebugLog;
NfcDebugLog* nfc_debug_log_alloc();
void nfc_debug_log_free(NfcDebugLog* instance);
void nfc_debug_log_process_data(
NfcDebugLog* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped);
-130
View File
@@ -1,130 +0,0 @@
#include "nfc_debug_pcap.h"
#include <storage/storage.h>
#include <stream/buffered_file_stream.h>
#include <furi_hal_nfc.h>
#include <furi_hal_rtc.h>
#define TAG "NfcDebugPcap"
#define PCAP_MAGIC 0xa1b2c3d4
#define PCAP_MAJOR 2
#define PCAP_MINOR 4
#define DLT_ISO_14443 264
#define DATA_PICC_TO_PCD 0xFF
#define DATA_PCD_TO_PICC 0xFE
#define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB
#define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA
#define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.pcap")
struct NfcDebugPcap {
Stream* file_stream;
};
static Stream* nfc_debug_pcap_open(Storage* storage) {
Stream* stream = NULL;
stream = buffered_file_stream_alloc(storage);
if(!buffered_file_stream_open(stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) {
buffered_file_stream_close(stream);
stream_free(stream);
stream = NULL;
} else {
if(!stream_tell(stream)) {
struct {
uint32_t magic;
uint16_t major, minor;
uint32_t reserved[2];
uint32_t snaplen;
uint32_t link_type;
} __attribute__((__packed__)) pcap_hdr = {
.magic = PCAP_MAGIC,
.major = PCAP_MAJOR,
.minor = PCAP_MINOR,
.snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE,
.link_type = DLT_ISO_14443,
};
if(stream_write(stream, (uint8_t*)&pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) {
FURI_LOG_E(TAG, "Failed to write pcap header");
buffered_file_stream_close(stream);
stream_free(stream);
stream = NULL;
}
}
}
return stream;
}
NfcDebugPcap* nfc_debug_pcap_alloc() {
NfcDebugPcap* instance = malloc(sizeof(NfcDebugPcap));
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->file_stream = nfc_debug_pcap_open(storage);
if(!instance->file_stream) {
free(instance);
instance = NULL;
}
furi_record_close(RECORD_STORAGE);
return instance;
}
void nfc_debug_pcap_free(NfcDebugPcap* instance) {
furi_assert(instance);
furi_assert(instance->file_stream);
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
free(instance);
}
void nfc_debug_pcap_process_data(
NfcDebugPcap* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped) {
furi_assert(instance);
furi_assert(data);
FuriHalRtcDateTime datetime;
furi_hal_rtc_get_datetime(&datetime);
uint8_t event = 0;
if(reader_to_tag) {
if(crc_dropped) {
event = DATA_PCD_TO_PICC_CRC_DROPPED;
} else {
event = DATA_PCD_TO_PICC;
}
} else {
if(crc_dropped) {
event = DATA_PICC_TO_PCD_CRC_DROPPED;
} else {
event = DATA_PICC_TO_PCD;
}
}
struct {
// https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header
uint32_t ts_sec;
uint32_t ts_usec;
uint32_t incl_len;
uint32_t orig_len;
// https://www.kaiser.cx/posts/pcap-iso14443/#_packet_data
uint8_t version;
uint8_t event;
uint16_t len;
} __attribute__((__packed__)) pkt_hdr = {
.ts_sec = furi_hal_rtc_datetime_to_timestamp(&datetime),
.ts_usec = 0,
.incl_len = len + 4,
.orig_len = len + 4,
.version = 0,
.event = event,
.len = len << 8 | len >> 8,
};
stream_write(instance->file_stream, (uint8_t*)&pkt_hdr, sizeof(pkt_hdr));
stream_write(instance->file_stream, data, len);
}
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef struct NfcDebugPcap NfcDebugPcap;
NfcDebugPcap* nfc_debug_pcap_alloc();
void nfc_debug_pcap_free(NfcDebugPcap* instance);
void nfc_debug_pcap_process_data(
NfcDebugPcap* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped);
+270
View File
@@ -0,0 +1,270 @@
#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;
}
+103
View File
@@ -0,0 +1,103 @@
#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
-528
View File
@@ -1,528 +0,0 @@
#include <furi_hal_random.h>
#include "nfc_generators.h"
#define NXP_MANUFACTURER_ID (0x04)
static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03};
static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03};
static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03};
static const uint8_t default_data_ntag203[] =
{0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE};
static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00};
static void nfc_generate_common_start(NfcDeviceData* data) {
nfc_device_data_clear(data);
}
static void nfc_generate_mf_ul_uid(uint8_t* uid) {
uid[0] = NXP_MANUFACTURER_ID;
furi_hal_random_fill_buf(&uid[1], 6);
// I'm not sure how this is generated, but the upper nybble always seems to be 8
uid[6] &= 0x0F;
uid[6] |= 0x80;
}
static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) {
uid[0] = NXP_MANUFACTURER_ID;
furi_hal_random_fill_buf(&uid[1], length - 1);
}
static void nfc_generate_mf_classic_block_0(
uint8_t* block,
uint8_t uid_len,
uint8_t sak,
uint8_t atqa0,
uint8_t atqa1) {
// Block length is always 16 bytes, and the UID can be either 4 or 7 bytes
furi_assert(uid_len == 4 || uid_len == 7);
furi_assert(block);
if(uid_len == 4) {
// Calculate BCC
block[uid_len] = 0;
for(int i = 0; i < uid_len; i++) {
block[uid_len] ^= block[i];
}
} else {
uid_len -= 1;
}
block[uid_len + 1] = sak;
block[uid_len + 2] = atqa0;
block[uid_len + 3] = atqa1;
for(int i = uid_len + 4; i < 16; i++) {
block[i] = 0xFF;
}
}
static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) {
// All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h.
MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].value;
sec_tr->access_bits[0] = 0xFF;
sec_tr->access_bits[1] = 0x07;
sec_tr->access_bits[2] = 0x80;
sec_tr->access_bits[3] = 0x69; // Nice
memset(sec_tr->key_a, 0xff, sizeof(sec_tr->key_a));
memset(sec_tr->key_b, 0xff, sizeof(sec_tr->key_b));
mf_classic_set_block_read(data, block, &data->block[block]);
mf_classic_set_key_found(
data, mf_classic_get_sector_by_block(block), MfClassicKeyA, 0xFFFFFFFFFFFF);
mf_classic_set_key_found(
data, mf_classic_get_sector_by_block(block), MfClassicKeyB, 0xFFFFFFFFFFFF);
}
static void nfc_generate_mf_ul_common(NfcDeviceData* data) {
data->nfc_data.type = FuriHalNfcTypeA;
data->nfc_data.interface = FuriHalNfcInterfaceRf;
data->nfc_data.uid_len = 7;
nfc_generate_mf_ul_uid(data->nfc_data.uid);
data->nfc_data.atqa[0] = 0x44;
data->nfc_data.atqa[1] = 0x00;
data->nfc_data.sak = 0x00;
data->protocol = NfcDeviceProtocolMifareUl;
}
static void
nfc_generate_mf_classic_common(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
data->nfc_data.type = FuriHalNfcTypeA;
data->nfc_data.interface = FuriHalNfcInterfaceRf;
data->nfc_data.uid_len = uid_len;
data->nfc_data.atqa[0] = 0x44;
data->nfc_data.atqa[1] = 0x00;
data->nfc_data.sak = 0x08;
data->protocol = NfcDeviceProtocolMifareClassic;
data->mf_classic_data.type = type;
}
static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) {
*bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
*bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6];
}
static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcDeviceData* data) {
MfUltralightData* mful = &data->mf_ul_data;
memcpy(mful->data, data->nfc_data.uid, 3);
memcpy(&mful->data[4], &data->nfc_data.uid[3], 4);
nfc_generate_calc_bcc(data->nfc_data.uid, &mful->data[3], &mful->data[8]);
}
static void nfc_generate_mf_ul_orig(NfcDeviceData* data) {
nfc_generate_common_start(data);
nfc_generate_mf_ul_common(data);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUnknown;
mful->data_size = 16 * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
// TODO: what's internal byte on page 2?
memset(&mful->data[4 * 4], 0xFF, 4);
}
static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) {
nfc_generate_common_start(data);
nfc_generate_mf_ul_common(data);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG203;
mful->data_size = 42 * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
mful->data[9] = 0x48; // Internal byte
memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203));
}
static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t num_pages) {
nfc_generate_common_start(data);
nfc_generate_mf_ul_common(data);
MfUltralightData* mful = &data->mf_ul_data;
mful->data_size = num_pages * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
uint16_t config_index = (num_pages - 4) * 4;
mful->data[config_index] = 0x04; // STRG_MOD_EN
mful->data[config_index + 3] = 0xFF; // AUTH0
mful->data[config_index + 5] = 0x05; // VCTID
memset(&mful->data[config_index + 8], 0xFF, 4); // Default PWD
if(num_pages > 20) mful->data[config_index - 1] = MF_UL_TEARING_FLAG_DEFAULT;
}
static void nfc_generate_mf_ul_ev1_common(NfcDeviceData* data, uint8_t num_pages) {
nfc_generate_mf_ul_with_config_common(data, num_pages);
MfUltralightData* mful = &data->mf_ul_data;
memcpy(&mful->version, version_bytes_mf0ulx1, sizeof(version_bytes_mf0ulx1));
for(size_t i = 0; i < 3; ++i) {
mful->tearing[i] = MF_UL_TEARING_FLAG_DEFAULT;
}
// TODO: what's internal byte on page 2?
}
static void nfc_generate_mf_ul_11(NfcDeviceData* data) {
nfc_generate_mf_ul_ev1_common(data, 20);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUL11;
mful->version.prod_subtype = 0x01;
mful->version.storage_size = 0x0B;
mful->data[16 * 4] = 0x00; // Low capacitance version does not have STRG_MOD_EN
}
static void nfc_generate_mf_ul_h11(NfcDeviceData* data) {
nfc_generate_mf_ul_ev1_common(data, 20);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUL11;
mful->version.prod_subtype = 0x02;
mful->version.storage_size = 0x0B;
}
static void nfc_generate_mf_ul_21(NfcDeviceData* data) {
nfc_generate_mf_ul_ev1_common(data, 41);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUL21;
mful->version.prod_subtype = 0x01;
mful->version.storage_size = 0x0E;
mful->data[37 * 4] = 0x00; // Low capacitance version does not have STRG_MOD_EN
}
static void nfc_generate_mf_ul_h21(NfcDeviceData* data) {
nfc_generate_mf_ul_ev1_common(data, 41);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUL21;
mful->version.prod_subtype = 0x02;
mful->version.storage_size = 0x0E;
}
static void nfc_generate_ntag21x_common(NfcDeviceData* data, uint8_t num_pages) {
nfc_generate_mf_ul_with_config_common(data, num_pages);
MfUltralightData* mful = &data->mf_ul_data;
memcpy(&mful->version, version_bytes_ntag21x, sizeof(version_bytes_mf0ulx1));
mful->data[9] = 0x48; // Internal byte
// Capability container
mful->data[12] = 0xE1;
mful->data[13] = 0x10;
}
static void nfc_generate_ntag213(NfcDeviceData* data) {
nfc_generate_ntag21x_common(data, 45);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG213;
mful->version.storage_size = 0x0F;
mful->data[14] = 0x12;
// Default contents
memcpy(&mful->data[16], default_data_ntag213, sizeof(default_data_ntag213));
}
static void nfc_generate_ntag215(NfcDeviceData* data) {
nfc_generate_ntag21x_common(data, 135);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG215;
mful->version.storage_size = 0x11;
mful->data[14] = 0x3E;
// Default contents
memcpy(&mful->data[16], default_data_ntag215_216, sizeof(default_data_ntag215_216));
}
static void nfc_generate_ntag216(NfcDeviceData* data) {
nfc_generate_ntag21x_common(data, 231);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG216;
mful->version.storage_size = 0x13;
mful->data[14] = 0x6D;
// Default contents
memcpy(&mful->data[16], default_data_ntag215_216, sizeof(default_data_ntag215_216));
}
static void
nfc_generate_ntag_i2c_common(NfcDeviceData* data, MfUltralightType type, uint16_t num_pages) {
nfc_generate_common_start(data);
nfc_generate_mf_ul_common(data);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = type;
memcpy(&mful->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c));
mful->data_size = num_pages * 4;
mful->data_read = mful->data_size;
memcpy(mful->data, data->nfc_data.uid, data->nfc_data.uid_len);
mful->data[7] = data->nfc_data.sak;
mful->data[8] = data->nfc_data.atqa[0];
mful->data[9] = data->nfc_data.atqa[1];
uint16_t config_register_page;
uint16_t session_register_page;
// Sync with mifare_ultralight.c
switch(type) {
case MfUltralightTypeNTAGI2C1K:
config_register_page = 227;
session_register_page = 229;
break;
case MfUltralightTypeNTAGI2C2K:
config_register_page = 481;
session_register_page = 483;
break;
case MfUltralightTypeNTAGI2CPlus1K:
case MfUltralightTypeNTAGI2CPlus2K:
config_register_page = 232;
session_register_page = 234;
break;
default:
furi_crash("Unknown MFUL");
break;
}
memcpy(
&mful->data[config_register_page * 4],
default_config_ntag_i2c,
sizeof(default_config_ntag_i2c));
memcpy(
&mful->data[session_register_page * 4],
default_config_ntag_i2c,
sizeof(default_config_ntag_i2c));
}
static void nfc_generate_ntag_i2c_1k(NfcDeviceData* data) {
nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C1K, 231);
MfUltralightData* mful = &data->mf_ul_data;
mful->version.prod_ver_minor = 0x01;
mful->version.storage_size = 0x13;
memcpy(&mful->data[12], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
mful->data[14] = 0x6D; // Size of tag in CC
}
static void nfc_generate_ntag_i2c_2k(NfcDeviceData* data) {
nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C2K, 485);
MfUltralightData* mful = &data->mf_ul_data;
mful->version.prod_ver_minor = 0x01;
mful->version.storage_size = 0x15;
memcpy(&mful->data[12], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
mful->data[14] = 0xEA; // Size of tag in CC
}
static void nfc_generate_ntag_i2c_plus_common(
NfcDeviceData* data,
MfUltralightType type,
uint16_t num_pages) {
nfc_generate_ntag_i2c_common(data, type, num_pages);
MfUltralightData* mful = &data->mf_ul_data;
uint16_t config_index = 227 * 4;
mful->data[config_index + 3] = 0xFF; // AUTH0
memset(&mful->data[config_index + 8], 0xFF, 4); // Default PWD
}
static void nfc_generate_ntag_i2c_plus_1k(NfcDeviceData* data) {
nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus1K, 236);
MfUltralightData* mful = &data->mf_ul_data;
mful->version.prod_ver_minor = 0x02;
mful->version.storage_size = 0x13;
}
static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) {
nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus2K, 492);
MfUltralightData* mful = &data->mf_ul_data;
mful->version.prod_ver_minor = 0x02;
mful->version.storage_size = 0x15;
}
void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
nfc_generate_common_start(data);
nfc_generate_mf_classic_uid(data->mf_classic_data.block[0].value, uid_len);
nfc_generate_mf_classic_common(data, uid_len, type);
// Set the UID
data->nfc_data.uid[0] = NXP_MANUFACTURER_ID;
for(int i = 1; i < uid_len; i++) {
data->nfc_data.uid[i] = data->mf_classic_data.block[0].value[i];
}
MfClassicData* mfc = &data->mf_classic_data;
mf_classic_set_block_read(mfc, 0, &mfc->block[0]);
if(type == MfClassicType4k) {
// Set every block to 0xFF
for(uint16_t i = 1; i < 256; i += 1) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc, i);
} else {
memset(&mfc->block[i].value, 0xFF, 16);
}
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
}
// Set SAK to 18
data->nfc_data.sak = 0x18;
} else if(type == MfClassicType1k) {
// Set every block to 0xFF
for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc, i);
} else {
memset(&mfc->block[i].value, 0xFF, 16);
}
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
}
// Set SAK to 08
data->nfc_data.sak = 0x08;
} else if(type == MfClassicTypeMini) {
// Set every block to 0xFF
for(uint16_t i = 1; i < MF_MINI_TOTAL_SECTORS_NUM * 4; i += 1) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc, i);
} else {
memset(&mfc->block[i].value, 0xFF, 16);
}
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
}
// Set SAK to 09
data->nfc_data.sak = 0x09;
}
nfc_generate_mf_classic_block_0(
data->mf_classic_data.block[0].value,
uid_len,
data->nfc_data.sak,
data->nfc_data.atqa[0],
data->nfc_data.atqa[1]);
mfc->type = type;
}
static void nfc_generate_mf_mini(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 4, MfClassicTypeMini);
}
static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 4, MfClassicType1k);
}
static void nfc_generate_mf_classic_1k_7b_uid(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 7, MfClassicType1k);
}
static void nfc_generate_mf_classic_4k_4b_uid(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 4, MfClassicType4k);
}
static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 7, MfClassicType4k);
}
static const NfcGenerator mf_ul_generator = {
.name = "Mifare Ultralight",
.generator_func = nfc_generate_mf_ul_orig,
};
static const NfcGenerator mf_ul_11_generator = {
.name = "Mifare Ultralight EV1 11",
.generator_func = nfc_generate_mf_ul_11,
};
static const NfcGenerator mf_ul_h11_generator = {
.name = "Mifare Ultralight EV1 H11",
.generator_func = nfc_generate_mf_ul_h11,
};
static const NfcGenerator mf_ul_21_generator = {
.name = "Mifare Ultralight EV1 21",
.generator_func = nfc_generate_mf_ul_21,
};
static const NfcGenerator mf_ul_h21_generator = {
.name = "Mifare Ultralight EV1 H21",
.generator_func = nfc_generate_mf_ul_h21,
};
static const NfcGenerator ntag203_generator = {
.name = "NTAG203",
.generator_func = nfc_generate_mf_ul_ntag203,
};
static const NfcGenerator ntag213_generator = {
.name = "NTAG213",
.generator_func = nfc_generate_ntag213,
};
static const NfcGenerator ntag215_generator = {
.name = "NTAG215",
.generator_func = nfc_generate_ntag215,
};
static const NfcGenerator ntag216_generator = {
.name = "NTAG216",
.generator_func = nfc_generate_ntag216,
};
static const NfcGenerator ntag_i2c_1k_generator = {
.name = "NTAG I2C 1k",
.generator_func = nfc_generate_ntag_i2c_1k,
};
static const NfcGenerator ntag_i2c_2k_generator = {
.name = "NTAG I2C 2k",
.generator_func = nfc_generate_ntag_i2c_2k,
};
static const NfcGenerator ntag_i2c_plus_1k_generator = {
.name = "NTAG I2C Plus 1k",
.generator_func = nfc_generate_ntag_i2c_plus_1k,
};
static const NfcGenerator ntag_i2c_plus_2k_generator = {
.name = "NTAG I2C Plus 2k",
.generator_func = nfc_generate_ntag_i2c_plus_2k,
};
static const NfcGenerator mifare_mini_generator = {
.name = "Mifare Mini",
.generator_func = nfc_generate_mf_mini,
};
static const NfcGenerator mifare_classic_1k_4b_uid_generator = {
.name = "Mifare Classic 1k 4byte UID",
.generator_func = nfc_generate_mf_classic_1k_4b_uid,
};
static const NfcGenerator mifare_classic_1k_7b_uid_generator = {
.name = "Mifare Classic 1k 7byte UID",
.generator_func = nfc_generate_mf_classic_1k_7b_uid,
};
static const NfcGenerator mifare_classic_4k_4b_uid_generator = {
.name = "Mifare Classic 4k 4byte UID",
.generator_func = nfc_generate_mf_classic_4k_4b_uid,
};
static const NfcGenerator mifare_classic_4k_7b_uid_generator = {
.name = "Mifare Classic 4k 7byte UID",
.generator_func = nfc_generate_mf_classic_4k_7b_uid,
};
const NfcGenerator* const nfc_generators[] = {
&mf_ul_generator,
&mf_ul_11_generator,
&mf_ul_h11_generator,
&mf_ul_21_generator,
&mf_ul_h21_generator,
&ntag203_generator,
&ntag213_generator,
&ntag215_generator,
&ntag216_generator,
&ntag_i2c_1k_generator,
&ntag_i2c_2k_generator,
&ntag_i2c_plus_1k_generator,
&ntag_i2c_plus_2k_generator,
&mifare_mini_generator,
&mifare_classic_1k_4b_uid_generator,
&mifare_classic_1k_7b_uid_generator,
&mifare_classic_4k_4b_uid_generator,
&mifare_classic_4k_7b_uid_generator,
NULL,
};
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include "../nfc_device.h"
typedef void (*NfcGeneratorFunc)(NfcDeviceData* data);
typedef struct {
const char* name;
NfcGeneratorFunc generator_func;
} NfcGenerator;
extern const NfcGenerator* const nfc_generators[];
void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type);
+70
View File
@@ -0,0 +1,70 @@
#include "nfc_util.h"
#include <furi.h>
static const uint8_t nfc_util_odd_byte_parity[256] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0,
1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1,
0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0,
0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1,
0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1};
void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest) {
furi_assert(dest);
furi_assert(len <= 8);
while(len--) {
dest[len] = (uint8_t)src;
src >>= 8;
}
}
uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) {
furi_assert(src);
furi_assert(len <= 8);
uint64_t res = 0;
while(len--) {
res = (res << 8) | (*src);
src++;
}
return res;
}
uint8_t nfc_util_even_parity32(uint32_t data) {
// data ^= data >> 16;
// data ^= data >> 8;
// return !nfc_util_odd_byte_parity[data];
return (__builtin_parity(data) & 0xFF);
}
uint8_t nfc_util_odd_parity8(uint8_t data) {
return nfc_util_odd_byte_parity[data];
}
void nfc_util_odd_parity(const uint8_t* src, uint8_t* dst, uint8_t len) {
furi_assert(src);
furi_assert(dst);
uint8_t parity = 0;
uint8_t bit = 0;
while(len--) {
parity |= nfc_util_odd_parity8(*src) << (7 - bit); // parity is MSB first
bit++;
if(bit == 8) {
*dst = parity;
dst++;
parity = 0;
bit = 0;
}
src++;
}
if(bit) {
*dst = parity;
}
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest);
uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len);
uint8_t nfc_util_even_parity32(uint32_t data);
uint8_t nfc_util_odd_parity8(uint8_t data);
void nfc_util_odd_parity(const uint8_t* src, uint8_t* dst, uint8_t len);
#ifdef __cplusplus
}
#endif
-265
View File
@@ -1,265 +0,0 @@
#include "reader_analyzer.h"
#include <lib/nfc/protocols/nfc_util.h>
#include <lib/nfc/protocols/mifare_classic.h>
#include <m-array.h>
#include "mfkey32.h"
#include "nfc_debug_pcap.h"
#include "nfc_debug_log.h"
#define TAG "ReaderAnalyzer"
#define READER_ANALYZER_MAX_BUFF_SIZE (1024)
typedef struct {
bool reader_to_tag;
bool crc_dropped;
uint16_t len;
} ReaderAnalyzerHeader;
typedef enum {
ReaderAnalyzerNfcDataMfClassic,
} ReaderAnalyzerNfcData;
struct ReaderAnalyzer {
FuriHalNfcDevData nfc_data;
bool alive;
FuriStreamBuffer* stream;
FuriThread* thread;
ReaderAnalyzerParseDataCallback callback;
void* context;
ReaderAnalyzerMode mode;
Mfkey32* mfkey32;
NfcDebugLog* debug_log;
NfcDebugPcap* pcap;
};
const FuriHalNfcDevData reader_analyzer_nfc_data[] = {
[ReaderAnalyzerNfcDataMfClassic] =
{.sak = 0x08,
.atqa = {0x44, 0x00},
.interface = FuriHalNfcInterfaceRf,
.type = FuriHalNfcTypeA,
.uid_len = 7,
.uid = {0x04, 0x77, 0x70, 0x2A, 0x23, 0x4F, 0x80},
.cuid = 0x2A234F80},
};
void reader_analyzer_parse(ReaderAnalyzer* instance, uint8_t* buffer, size_t size) {
if(size < sizeof(ReaderAnalyzerHeader)) return;
size_t bytes_i = 0;
while(bytes_i < size) {
ReaderAnalyzerHeader* header = (ReaderAnalyzerHeader*)&buffer[bytes_i];
uint16_t len = header->len;
if(bytes_i + len > size) break;
bytes_i += sizeof(ReaderAnalyzerHeader);
if(instance->mfkey32) {
mfkey32_process_data(
instance->mfkey32,
&buffer[bytes_i],
len,
header->reader_to_tag,
header->crc_dropped);
}
if(instance->pcap) {
nfc_debug_pcap_process_data(
instance->pcap, &buffer[bytes_i], len, header->reader_to_tag, header->crc_dropped);
}
if(instance->debug_log) {
nfc_debug_log_process_data(
instance->debug_log,
&buffer[bytes_i],
len,
header->reader_to_tag,
header->crc_dropped);
}
bytes_i += len;
}
}
int32_t reader_analyzer_thread(void* context) {
ReaderAnalyzer* reader_analyzer = context;
uint8_t buffer[READER_ANALYZER_MAX_BUFF_SIZE] = {};
while(reader_analyzer->alive || !furi_stream_buffer_is_empty(reader_analyzer->stream)) {
size_t ret = furi_stream_buffer_receive(
reader_analyzer->stream, buffer, READER_ANALYZER_MAX_BUFF_SIZE, 50);
if(ret) {
reader_analyzer_parse(reader_analyzer, buffer, ret);
}
}
return 0;
}
ReaderAnalyzer* reader_analyzer_alloc() {
ReaderAnalyzer* instance = malloc(sizeof(ReaderAnalyzer));
instance->nfc_data = reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic];
instance->alive = false;
instance->stream =
furi_stream_buffer_alloc(READER_ANALYZER_MAX_BUFF_SIZE, sizeof(ReaderAnalyzerHeader));
instance->thread =
furi_thread_alloc_ex("ReaderAnalyzerWorker", 2048, reader_analyzer_thread, instance);
furi_thread_set_priority(instance->thread, FuriThreadPriorityLow);
return instance;
}
static void reader_analyzer_mfkey_callback(Mfkey32Event event, void* context) {
furi_assert(context);
ReaderAnalyzer* instance = context;
if(event == Mfkey32EventParamCollected) {
if(instance->callback) {
instance->callback(ReaderAnalyzerEventMfkeyCollected, instance->context);
}
}
}
void reader_analyzer_start(ReaderAnalyzer* instance, ReaderAnalyzerMode mode) {
furi_assert(instance);
furi_stream_buffer_reset(instance->stream);
if(mode & ReaderAnalyzerModeDebugLog) {
instance->debug_log = nfc_debug_log_alloc();
}
if(mode & ReaderAnalyzerModeMfkey) {
instance->mfkey32 = mfkey32_alloc(instance->nfc_data.cuid);
if(instance->mfkey32) {
mfkey32_set_callback(instance->mfkey32, reader_analyzer_mfkey_callback, instance);
}
}
if(mode & ReaderAnalyzerModeDebugPcap) {
instance->pcap = nfc_debug_pcap_alloc();
}
instance->alive = true;
furi_thread_start(instance->thread);
}
void reader_analyzer_stop(ReaderAnalyzer* instance) {
furi_assert(instance);
instance->alive = false;
furi_thread_join(instance->thread);
if(instance->debug_log) {
nfc_debug_log_free(instance->debug_log);
instance->debug_log = NULL;
}
if(instance->mfkey32) {
mfkey32_free(instance->mfkey32);
instance->mfkey32 = NULL;
}
if(instance->pcap) {
nfc_debug_pcap_free(instance->pcap);
instance->pcap = NULL;
}
}
void reader_analyzer_free(ReaderAnalyzer* instance) {
furi_assert(instance);
reader_analyzer_stop(instance);
furi_thread_free(instance->thread);
furi_stream_buffer_free(instance->stream);
free(instance);
}
void reader_analyzer_set_callback(
ReaderAnalyzer* instance,
ReaderAnalyzerParseDataCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
NfcProtocol
reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len) {
furi_assert(instance);
furi_assert(buff_rx);
UNUSED(len);
NfcProtocol protocol = NfcDeviceProtocolUnknown;
if((buff_rx[0] == 0x60) || (buff_rx[0] == 0x61)) {
protocol = NfcDeviceProtocolMifareClassic;
}
return protocol;
}
FuriHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance) {
furi_assert(instance);
instance->nfc_data = reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic];
return &instance->nfc_data;
}
void reader_analyzer_set_nfc_data(ReaderAnalyzer* instance, FuriHalNfcDevData* nfc_data) {
furi_assert(instance);
furi_assert(nfc_data);
memcpy(&instance->nfc_data, nfc_data, sizeof(FuriHalNfcDevData));
}
static void reader_analyzer_write(
ReaderAnalyzer* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped) {
ReaderAnalyzerHeader header = {
.reader_to_tag = reader_to_tag, .crc_dropped = crc_dropped, .len = len};
size_t data_sent = 0;
data_sent = furi_stream_buffer_send(
instance->stream, &header, sizeof(ReaderAnalyzerHeader), FuriWaitForever);
if(data_sent != sizeof(ReaderAnalyzerHeader)) {
FURI_LOG_W(TAG, "Sent %zu out of %zu bytes", data_sent, sizeof(ReaderAnalyzerHeader));
}
data_sent = furi_stream_buffer_send(instance->stream, data, len, FuriWaitForever);
if(data_sent != len) {
FURI_LOG_W(TAG, "Sent %zu out of %u bytes", data_sent, len);
}
}
static void
reader_analyzer_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
UNUSED(crc_dropped);
ReaderAnalyzer* reader_analyzer = context;
uint16_t bytes = bits < 8 ? 1 : bits / 8;
reader_analyzer_write(reader_analyzer, data, bytes, false, crc_dropped);
}
static void
reader_analyzer_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
UNUSED(crc_dropped);
ReaderAnalyzer* reader_analyzer = context;
uint16_t bytes = bits < 8 ? 1 : bits / 8;
reader_analyzer_write(reader_analyzer, data, bytes, true, crc_dropped);
}
void reader_analyzer_prepare_tx_rx(
ReaderAnalyzer* instance,
FuriHalNfcTxRxContext* tx_rx,
bool is_picc) {
furi_assert(instance);
furi_assert(tx_rx);
if(is_picc) {
tx_rx->sniff_tx = reader_analyzer_write_rx;
tx_rx->sniff_rx = reader_analyzer_write_tx;
} else {
tx_rx->sniff_rx = reader_analyzer_write_rx;
tx_rx->sniff_tx = reader_analyzer_write_tx;
}
tx_rx->sniff_context = instance;
}
-43
View File
@@ -1,43 +0,0 @@
#pragma once
#include <stdint.h>
#include <lib/nfc/nfc_device.h>
typedef enum {
ReaderAnalyzerModeDebugLog = 0x01,
ReaderAnalyzerModeMfkey = 0x02,
ReaderAnalyzerModeDebugPcap = 0x04,
} ReaderAnalyzerMode;
typedef enum {
ReaderAnalyzerEventMfkeyCollected,
} ReaderAnalyzerEvent;
typedef struct ReaderAnalyzer ReaderAnalyzer;
typedef void (*ReaderAnalyzerParseDataCallback)(ReaderAnalyzerEvent event, void* context);
ReaderAnalyzer* reader_analyzer_alloc();
void reader_analyzer_free(ReaderAnalyzer* instance);
void reader_analyzer_set_callback(
ReaderAnalyzer* instance,
ReaderAnalyzerParseDataCallback callback,
void* context);
void reader_analyzer_start(ReaderAnalyzer* instance, ReaderAnalyzerMode mode);
void reader_analyzer_stop(ReaderAnalyzer* instance);
NfcProtocol
reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len);
FuriHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance);
void reader_analyzer_set_nfc_data(ReaderAnalyzer* instance, FuriHalNfcDevData* nfc_data);
void reader_analyzer_prepare_tx_rx(
ReaderAnalyzer* instance,
FuriHalNfcTxRxContext* tx_rx,
bool is_picc);