Merge branch 'dev' into astra/3746-mfp-detect

This commit is contained in:
Astra
2024-04-23 10:39:34 +09:00
committed by GitHub
1001 changed files with 15407 additions and 6205 deletions
+202 -11
View File
@@ -13,6 +13,14 @@
static const uint32_t felica_data_format_version = 1;
/** @brief This is used in felica_prepare_first_block to define which
* type of block needs to be prepared.
*/
typedef enum {
FelicaMACTypeRead,
FelicaMACTypeWrite,
} FelicaMACType;
const NfcDeviceBase nfc_device_felica = {
.protocol_name = FELICA_PROTOCOL_NAME,
.alloc = (NfcDeviceAlloc)felica_alloc,
@@ -29,24 +37,24 @@ const NfcDeviceBase nfc_device_felica = {
.get_base_data = (NfcDeviceGetBaseData)felica_get_base_data,
};
FelicaData* felica_alloc() {
FelicaData* felica_alloc(void) {
FelicaData* data = malloc(sizeof(FelicaData));
return data;
}
void felica_free(FelicaData* data) {
furi_assert(data);
furi_check(data);
free(data);
}
void felica_reset(FelicaData* data) {
furi_check(data);
memset(data, 0, sizeof(FelicaData));
}
void felica_copy(FelicaData* data, const FelicaData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
*data = *other;
}
@@ -59,7 +67,7 @@ bool felica_verify(FelicaData* data, const FuriString* device_type) {
}
bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
bool parsed = false;
@@ -77,13 +85,32 @@ bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) {
break;
parsed = true;
uint32_t blocks_total = 0;
uint32_t blocks_read = 0;
if(!flipper_format_read_uint32(ff, "Blocks total", &blocks_total, 1)) break;
if(!flipper_format_read_uint32(ff, "Blocks read", &blocks_read, 1)) break;
data->blocks_total = (uint8_t)blocks_total;
data->blocks_read = (uint8_t)blocks_read;
FuriString* temp_str = furi_string_alloc();
for(uint8_t i = 0; i < data->blocks_total; i++) {
furi_string_printf(temp_str, "Block %d", i);
if(!flipper_format_read_hex(
ff,
furi_string_get_cstr(temp_str),
(&data->data.dump[i * sizeof(FelicaBlock)]),
sizeof(FelicaBlock))) {
parsed = false;
break;
}
}
} while(false);
return parsed;
}
bool felica_save(const FelicaData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
bool saved = false;
@@ -98,15 +125,33 @@ bool felica_save(const FelicaData* data, FlipperFormat* ff) {
ff, FELICA_MANUFACTURE_PARAMETER, data->pmm.data, FELICA_PMM_SIZE))
break;
uint32_t blocks_total = data->blocks_total;
uint32_t blocks_read = data->blocks_read;
if(!flipper_format_write_uint32(ff, "Blocks total", &blocks_total, 1)) break;
if(!flipper_format_write_uint32(ff, "Blocks read", &blocks_read, 1)) break;
saved = true;
FuriString* temp_str = furi_string_alloc();
for(uint8_t i = 0; i < blocks_total; i++) {
furi_string_printf(temp_str, "Block %d", i);
if(!flipper_format_write_hex(
ff,
furi_string_get_cstr(temp_str),
(&data->data.dump[i * sizeof(FelicaBlock)]),
sizeof(FelicaBlock))) {
saved = false;
break;
}
}
furi_string_free(temp_str);
} while(false);
return saved;
}
bool felica_is_equal(const FelicaData* data, const FelicaData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
return memcmp(data, other, sizeof(FelicaData)) == 0;
}
@@ -119,7 +164,7 @@ const char* felica_get_device_name(const FelicaData* data, NfcDeviceNameType nam
}
const uint8_t* felica_get_uid(const FelicaData* data, size_t* uid_len) {
furi_assert(data);
furi_check(data);
// Consider Manufacturer ID as UID
if(uid_len) {
@@ -130,7 +175,7 @@ const uint8_t* felica_get_uid(const FelicaData* data, size_t* uid_len) {
}
bool felica_set_uid(FelicaData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
// Consider Manufacturer ID as UID
const bool uid_valid = uid_len == FELICA_IDM_SIZE;
@@ -145,3 +190,149 @@ FelicaData* felica_get_base_data(const FelicaData* data) {
UNUSED(data);
furi_crash("No base data");
}
static void felica_reverse_copy_block(const uint8_t* array, uint8_t* reverse_array) {
furi_assert(array);
furi_assert(reverse_array);
for(int i = 0; i < 8; i++) {
reverse_array[i] = array[7 - i];
}
}
void felica_calculate_session_key(
mbedtls_des3_context* ctx,
const uint8_t* ck,
const uint8_t* rc,
uint8_t* out) {
furi_check(ctx);
furi_check(ck);
furi_check(rc);
furi_check(out);
uint8_t iv[8];
memset(iv, 0, 8);
uint8_t ck_reversed[16];
felica_reverse_copy_block(ck, ck_reversed);
felica_reverse_copy_block(ck + 8, ck_reversed + 8);
uint8_t rc_reversed[16];
felica_reverse_copy_block(rc, rc_reversed);
felica_reverse_copy_block(rc + 8, rc_reversed + 8);
mbedtls_des3_set2key_enc(ctx, ck_reversed);
mbedtls_des3_crypt_cbc(ctx, MBEDTLS_DES_ENCRYPT, FELICA_DATA_BLOCK_SIZE, iv, rc_reversed, out);
}
static bool felica_calculate_mac(
mbedtls_des3_context* ctx,
const uint8_t* session_key,
const uint8_t* rc,
const uint8_t* first_block,
const uint8_t* data,
const size_t length,
uint8_t* mac) {
furi_check((length % 8) == 0);
uint8_t reverse_data[8];
uint8_t iv[8];
uint8_t out[8];
mbedtls_des3_set2key_enc(ctx, session_key);
felica_reverse_copy_block(rc, iv);
felica_reverse_copy_block(first_block, reverse_data);
uint8_t i = 0;
bool error = false;
do {
if(mbedtls_des3_crypt_cbc(ctx, MBEDTLS_DES_ENCRYPT, 8, iv, reverse_data, out) == 0) {
memcpy(iv, out, sizeof(iv));
felica_reverse_copy_block(data + i, reverse_data);
i += 8;
} else {
error = true;
break;
}
} while(i <= length);
if(!error) {
felica_reverse_copy_block(out, mac);
}
return !error;
}
static void felica_prepare_first_block(
FelicaMACType operation_type,
const uint8_t* blocks,
const uint8_t block_count,
uint8_t* out) {
furi_check(blocks);
furi_check(out);
if(operation_type == FelicaMACTypeRead) {
memset(out, 0xFF, 8);
for(uint8_t i = 0, j = 0; i < block_count; i++, j += 2) {
out[j] = blocks[i];
out[j + 1] = 0;
}
} else {
furi_check(block_count == 4);
memset(out, 0, 8);
out[0] = blocks[0];
out[1] = blocks[1];
out[2] = blocks[2];
out[4] = blocks[3];
out[6] = FELICA_BLOCK_INDEX_MAC_A;
}
}
bool felica_check_mac(
mbedtls_des3_context* ctx,
const uint8_t* session_key,
const uint8_t* rc,
const uint8_t* blocks,
const uint8_t block_count,
uint8_t* data) {
furi_check(ctx);
furi_check(session_key);
furi_check(rc);
furi_check(blocks);
furi_check(data);
uint8_t first_block[8];
uint8_t mac[8];
felica_prepare_first_block(FelicaMACTypeRead, blocks, block_count, first_block);
uint8_t data_size_without_mac = FELICA_DATA_BLOCK_SIZE * (block_count - 1);
felica_calculate_mac(ctx, session_key, rc, first_block, data, data_size_without_mac, mac);
uint8_t* mac_ptr = data + data_size_without_mac;
return !memcmp(mac, mac_ptr, 8);
}
void felica_calculate_mac_write(
mbedtls_des3_context* ctx,
const uint8_t* session_key,
const uint8_t* rc,
const uint8_t* wcnt,
const uint8_t* data,
uint8_t* mac) {
furi_check(ctx);
furi_check(session_key);
furi_check(rc);
furi_check(wcnt);
furi_check(data);
furi_check(mac);
const uint8_t WCNT_length = 3;
uint8_t block_data[WCNT_length + 1];
uint8_t first_block[8];
memcpy(block_data, wcnt, WCNT_length);
block_data[3] = FELICA_BLOCK_INDEX_STATE;
felica_prepare_first_block(FelicaMACTypeWrite, block_data, WCNT_length + 1, first_block);
uint8_t session_swapped[FELICA_DATA_BLOCK_SIZE];
memcpy(session_swapped, session_key + 8, 8);
memcpy(session_swapped + 8, session_key, 8);
felica_calculate_mac(ctx, session_swapped, rc, first_block, data, FELICA_DATA_BLOCK_SIZE, mac);
}
+102 -1
View File
@@ -2,6 +2,7 @@
#include <toolbox/bit_buffer.h>
#include <nfc/protocols/nfc_device_base_i.h>
#include <mbedtls/include/mbedtls/des.h>
#ifdef __cplusplus
extern "C" {
@@ -9,6 +10,23 @@ extern "C" {
#define FELICA_IDM_SIZE (8U)
#define FELICA_PMM_SIZE (8U)
#define FELICA_DATA_BLOCK_SIZE (16U)
#define FELICA_BLOCKS_TOTAL_COUNT (27U)
#define FELICA_BLOCK_INDEX_REG (0x0EU)
#define FELICA_BLOCK_INDEX_RC (0x80U)
#define FELICA_BLOCK_INDEX_MAC (0x81U)
#define FELICA_BLOCK_INDEX_ID (0x82U)
#define FELICA_BLOCK_INDEX_D_ID (0x83U)
#define FELICA_BLOCK_INDEX_SER_C (0x84U)
#define FELICA_BLOCK_INDEX_SYS_C (0x85U)
#define FELICA_BLOCK_INDEX_CKV (0x86U)
#define FELICA_BLOCK_INDEX_CK (0x87U)
#define FELICA_BLOCK_INDEX_MC (0x88U)
#define FELICA_BLOCK_INDEX_WCNT (0x90U)
#define FELICA_BLOCK_INDEX_MAC_A (0x91U)
#define FELICA_BLOCK_INDEX_STATE (0x92U)
#define FELICA_BLOCK_INDEX_CRC_CHECK (0xA0U)
#define FELICA_GUARD_TIME_US (20000U)
#define FELICA_FDT_POLL_FC (10000U)
@@ -23,6 +41,7 @@ extern "C" {
#define FELICA_TIME_SLOT_8 (0x07U)
#define FELICA_TIME_SLOT_16 (0x0FU)
/** @brief Type of possible Felica errors */
typedef enum {
FelicaErrorNone,
FelicaErrorNotPresent,
@@ -35,22 +54,83 @@ typedef enum {
FelicaErrorTimeout,
} FelicaError;
/** @brief Separate type for card key block. Used in authentication process */
typedef struct {
uint8_t data[FELICA_DATA_BLOCK_SIZE];
} FelicaCardKey;
/** @brief In Felica there two types of auth. Internal is the first one, after
* which external became possible. Here are two flags representing which one
* was passed */
typedef struct {
bool internal : 1;
bool external : 1;
} FelicaAuthenticationStatus;
/** @brief Struct which controls the process of authentication and can be passed as
* a parameter to the application level. In order to force user to fill card key block data. */
typedef struct {
bool skip_auth; /**< By default it is true, so auth is skipped. By setting this to false several auth steps will be performed in order to pass auth*/
FelicaCardKey
card_key; /**< User must fill this field with known card key in order to pass auth*/
FelicaAuthenticationStatus auth_status; /**< Authentication status*/
} FelicaAuthenticationContext;
/** @brief Felica ID block */
typedef struct {
uint8_t data[FELICA_IDM_SIZE];
} FelicaIDm;
/** @brief Felica PMm block */
typedef struct {
uint8_t data[FELICA_PMM_SIZE];
} FelicaPMm;
/** @brief Felica block with status flags indicating last operation with it.
* See Felica manual for more details on status codes. */
typedef struct {
uint8_t SF1; /**< Status flag 1, equals to 0 when success*/
uint8_t SF2; /**< Status flag 2, equals to 0 when success*/
uint8_t data[FELICA_DATA_BLOCK_SIZE]; /**< Block data */
} FelicaBlock;
/** @brief Felica filesystem structure */
typedef struct {
FelicaBlock spad[14];
FelicaBlock reg;
FelicaBlock rc;
FelicaBlock mac;
FelicaBlock id;
FelicaBlock d_id;
FelicaBlock ser_c;
FelicaBlock sys_c;
FelicaBlock ckv;
FelicaBlock ck;
FelicaBlock mc;
FelicaBlock wcnt;
FelicaBlock mac_a;
FelicaBlock state;
FelicaBlock crc_check;
} FelicaFileSystem;
/** @brief Union which represents filesystem in junction with plain data dump */
typedef union {
FelicaFileSystem fs;
uint8_t dump[sizeof(FelicaFileSystem)];
} FelicaFSUnion;
/** @brief Structure used to store Felica data and additional values about reading */
typedef struct {
FelicaIDm idm;
FelicaPMm pmm;
uint8_t blocks_total;
uint8_t blocks_read;
FelicaFSUnion data;
} FelicaData;
extern const NfcDeviceBase nfc_device_felica;
FelicaData* felica_alloc();
FelicaData* felica_alloc(void);
void felica_free(FelicaData* data);
@@ -74,6 +154,27 @@ bool felica_set_uid(FelicaData* data, const uint8_t* uid, size_t uid_len);
FelicaData* felica_get_base_data(const FelicaData* data);
void felica_calculate_session_key(
mbedtls_des3_context* ctx,
const uint8_t* ck,
const uint8_t* rc,
uint8_t* out);
bool felica_check_mac(
mbedtls_des3_context* ctx,
const uint8_t* session_key,
const uint8_t* rc,
const uint8_t* blocks,
const uint8_t block_count,
uint8_t* data);
void felica_calculate_mac_write(
mbedtls_des3_context* ctx,
const uint8_t* session_key,
const uint8_t* rc,
const uint8_t* wcnt,
const uint8_t* data,
uint8_t* mac);
#ifdef __cplusplus
}
#endif
+215 -18
View File
@@ -3,6 +3,11 @@
#include <nfc/protocols/nfc_poller_base.h>
#include <furi.h>
#include <furi_hal.h>
#define TAG "FelicaPoller"
typedef NfcCommand (*FelicaPollerReadHandler)(FelicaPoller* instance);
const FelicaData* felica_poller_get_data(FelicaPoller* instance) {
furi_assert(instance);
@@ -23,6 +28,8 @@ static FelicaPoller* felica_poller_alloc(Nfc* nfc) {
nfc_set_guard_time_us(instance->nfc, FELICA_GUARD_TIME_US);
nfc_set_fdt_poll_fc(instance->nfc, FELICA_FDT_POLL_FC);
nfc_set_fdt_poll_poll_us(instance->nfc, FELICA_POLL_POLL_MIN_US);
mbedtls_des3_init(&instance->auth.des_context);
instance->data = felica_alloc();
instance->felica_event.data = &instance->felica_event_data;
@@ -40,6 +47,7 @@ static void felica_poller_free(FelicaPoller* instance) {
furi_assert(instance->rx_buffer);
furi_assert(instance->data);
mbedtls_des3_free(&instance->auth.des_context);
bit_buffer_free(instance->tx_buffer);
bit_buffer_free(instance->rx_buffer);
felica_free(instance->data);
@@ -55,6 +63,212 @@ static void
instance->context = context;
}
NfcCommand felica_poller_state_handler_idle(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Idle");
felica_reset(instance->data);
instance->state = FelicaPollerStateActivated;
return NfcCommandContinue;
}
NfcCommand felica_poller_state_handler_activate(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Activate");
NfcCommand command = NfcCommandContinue;
FelicaError error = felica_poller_activate(instance, instance->data);
if(error == FelicaErrorNone) {
furi_hal_random_fill_buf(instance->data->data.fs.rc.data, FELICA_DATA_BLOCK_SIZE);
instance->felica_event.type = FelicaPollerEventTypeRequestAuthContext;
instance->felica_event_data.auth_context = &instance->auth.context;
instance->callback(instance->general_event, instance->context);
bool skip_auth = instance->auth.context.skip_auth;
instance->state = skip_auth ? FelicaPollerStateReadBlocks :
FelicaPollerStateAuthenticateInternal;
} else if(error != FelicaErrorTimeout) {
instance->felica_event.type = FelicaPollerEventTypeError;
instance->felica_event_data.error = error;
instance->state = FelicaPollerStateReadFailed;
}
return command;
}
NfcCommand felica_poller_state_handler_auth_internal(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Auth Internal");
felica_calculate_session_key(
&instance->auth.des_context,
instance->auth.context.card_key.data,
instance->data->data.fs.rc.data,
instance->auth.session_key.data);
instance->state = FelicaPollerStateReadBlocks;
uint8_t blocks[3] = {FELICA_BLOCK_INDEX_RC, 0, 0};
FelicaPollerWriteCommandResponse* tx_resp;
do {
FelicaError error = felica_poller_write_blocks(
instance, 1, blocks, instance->data->data.fs.rc.data, &tx_resp);
if((error != FelicaErrorNone) || (tx_resp->SF1 != 0) || (tx_resp->SF2 != 0)) break;
blocks[0] = FELICA_BLOCK_INDEX_ID;
blocks[1] = FELICA_BLOCK_INDEX_WCNT;
blocks[2] = FELICA_BLOCK_INDEX_MAC_A;
FelicaPollerReadCommandResponse* rx_resp;
error = felica_poller_read_blocks(instance, sizeof(blocks), blocks, &rx_resp);
if(error != FelicaErrorNone || rx_resp->SF1 != 0 || rx_resp->SF2 != 0) break;
if(felica_check_mac(
&instance->auth.des_context,
instance->auth.session_key.data,
instance->data->data.fs.rc.data,
blocks,
rx_resp->block_count,
rx_resp->data)) {
instance->auth.context.auth_status.internal = true;
instance->data->data.fs.wcnt.SF1 = 0;
instance->data->data.fs.wcnt.SF2 = 0;
memcpy(
instance->data->data.fs.wcnt.data,
rx_resp->data + FELICA_DATA_BLOCK_SIZE,
FELICA_DATA_BLOCK_SIZE);
instance->state = FelicaPollerStateAuthenticateExternal;
}
} while(false);
return NfcCommandContinue;
}
NfcCommand felica_poller_state_handler_auth_external(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Auth External");
instance->state = FelicaPollerStateReadBlocks;
uint8_t blocks[2];
instance->data->data.fs.state.data[0] = 1;
FelicaAuthentication* auth = &instance->auth;
felica_calculate_mac_write(
&auth->des_context,
auth->session_key.data,
instance->data->data.fs.rc.data,
instance->data->data.fs.wcnt.data,
instance->data->data.fs.state.data,
instance->data->data.fs.mac_a.data);
memcpy(instance->data->data.fs.mac_a.data + 8, instance->data->data.fs.wcnt.data, 3); //-V1086
uint8_t tx_data[FELICA_DATA_BLOCK_SIZE * 2];
memcpy(tx_data, instance->data->data.fs.state.data, FELICA_DATA_BLOCK_SIZE);
memcpy(
tx_data + FELICA_DATA_BLOCK_SIZE,
instance->data->data.fs.mac_a.data,
FELICA_DATA_BLOCK_SIZE);
do {
blocks[0] = FELICA_BLOCK_INDEX_STATE;
blocks[1] = FELICA_BLOCK_INDEX_MAC_A;
FelicaPollerWriteCommandResponse* tx_resp;
FelicaError error = felica_poller_write_blocks(instance, 2, blocks, tx_data, &tx_resp);
if(error != FelicaErrorNone || tx_resp->SF1 != 0 || tx_resp->SF2 != 0) break;
FelicaPollerReadCommandResponse* rx_resp;
error = felica_poller_read_blocks(instance, 1, blocks, &rx_resp);
if(error != FelicaErrorNone || rx_resp->SF1 != 0 || rx_resp->SF2 != 0) break;
instance->data->data.fs.state.SF1 = 0;
instance->data->data.fs.state.SF2 = 0;
memcpy(instance->data->data.fs.state.data, rx_resp->data, FELICA_DATA_BLOCK_SIZE);
instance->auth.context.auth_status.external = instance->data->data.fs.state.data[0];
} while(false);
instance->state = FelicaPollerStateReadBlocks;
return NfcCommandContinue;
}
NfcCommand felica_poller_state_handler_read_blocks(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Read Blocks");
uint8_t block_count = 1;
uint8_t block_list[4] = {0, 0, 0, 0};
block_list[0] = instance->block_index;
instance->block_index++;
if(instance->block_index == FELICA_BLOCK_INDEX_REG + 1) {
instance->block_index = FELICA_BLOCK_INDEX_RC;
} else if(instance->block_index == FELICA_BLOCK_INDEX_MC + 1) {
instance->block_index = FELICA_BLOCK_INDEX_WCNT;
} else if(instance->block_index == FELICA_BLOCK_INDEX_STATE + 1) {
instance->block_index = FELICA_BLOCK_INDEX_CRC_CHECK;
}
FelicaPollerReadCommandResponse* response;
FelicaError error = felica_poller_read_blocks(instance, block_count, block_list, &response);
if(error == FelicaErrorNone) {
block_count = (response->SF1 == 0) ? response->block_count : block_count;
uint8_t* data_ptr =
instance->data->data.dump + instance->data->blocks_total * sizeof(FelicaBlock);
*data_ptr++ = response->SF1;
*data_ptr++ = response->SF2;
if(response->SF1 == 0) {
uint8_t* response_data_ptr = response->data;
instance->data->blocks_read++;
memcpy(data_ptr, response_data_ptr, FELICA_DATA_BLOCK_SIZE);
} else {
memset(data_ptr, 0, FELICA_DATA_BLOCK_SIZE);
}
instance->data->blocks_total++;
if(instance->data->blocks_total == FELICA_BLOCKS_TOTAL_COUNT) {
instance->state = FelicaPollerStateReadSuccess;
}
} else {
instance->felica_event.type = FelicaPollerEventTypeError;
instance->felica_event_data.error = error;
instance->state = FelicaPollerStateReadFailed;
}
return NfcCommandContinue;
}
NfcCommand felica_poller_state_handler_read_success(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Read Success");
if(!instance->auth.context.auth_status.internal ||
!instance->auth.context.auth_status.external) {
instance->data->blocks_read--;
instance->felica_event.type = FelicaPollerEventTypeIncomplete;
} else {
memcpy(
instance->data->data.fs.ck.data,
instance->auth.context.card_key.data,
FELICA_DATA_BLOCK_SIZE);
instance->felica_event.type = FelicaPollerEventTypeReady;
}
instance->felica_event_data.error = FelicaErrorNone;
return instance->callback(instance->general_event, instance->context);
}
NfcCommand felica_poller_state_handler_read_failed(FelicaPoller* instance) {
FURI_LOG_D(TAG, "Read Fail");
instance->callback(instance->general_event, instance->context);
return NfcCommandStop;
}
static const FelicaPollerReadHandler felica_poller_handler[FelicaPollerStateNum] = {
[FelicaPollerStateIdle] = felica_poller_state_handler_idle,
[FelicaPollerStateActivated] = felica_poller_state_handler_activate,
[FelicaPollerStateAuthenticateInternal] = felica_poller_state_handler_auth_internal,
[FelicaPollerStateAuthenticateExternal] = felica_poller_state_handler_auth_external,
[FelicaPollerStateReadBlocks] = felica_poller_state_handler_read_blocks,
[FelicaPollerStateReadSuccess] = felica_poller_state_handler_read_success,
[FelicaPollerStateReadFailed] = felica_poller_state_handler_read_failed,
};
static NfcCommand felica_poller_run(NfcGenericEvent event, void* context) {
furi_assert(context);
furi_assert(event.protocol == NfcProtocolInvalid);
@@ -65,24 +279,7 @@ static NfcCommand felica_poller_run(NfcGenericEvent event, void* context) {
NfcCommand command = NfcCommandContinue;
if(nfc_event->type == NfcEventTypePollerReady) {
if(instance->state != FelicaPollerStateActivated) {
FelicaError error = felica_poller_activate(instance, instance->data);
if(error == FelicaErrorNone) {
instance->felica_event.type = FelicaPollerEventTypeReady;
instance->felica_event_data.error = error;
command = instance->callback(instance->general_event, instance->context);
} else {
instance->felica_event.type = FelicaPollerEventTypeError;
instance->felica_event_data.error = error;
command = instance->callback(instance->general_event, instance->context);
// Add delay to switch context
furi_delay_ms(100);
}
} else {
instance->felica_event.type = FelicaPollerEventTypeReady;
instance->felica_event_data.error = FelicaErrorNone;
command = instance->callback(instance->general_event, instance->context);
}
command = felica_poller_handler[instance->state](instance);
}
return command;
+20 -1
View File
@@ -19,14 +19,33 @@ typedef struct FelicaPoller FelicaPoller;
*/
typedef enum {
FelicaPollerEventTypeError, /**< An error occured during activation procedure. */
FelicaPollerEventTypeReady, /**< The card was activated by the poller. */
FelicaPollerEventTypeReady, /**< The card was activated and fully read by the poller. */
FelicaPollerEventTypeIncomplete, /**< The card was activated and partly read by the poller. */
FelicaPollerEventTypeRequestAuthContext, /**< Authentication context was requested by poller. */
} FelicaPollerEventType;
/**
* @brief Stucture for holding Felica session key which is calculated from rc and ck.
*/
typedef struct {
uint8_t data[FELICA_DATA_BLOCK_SIZE];
} FelicaSessionKey;
/**
* @brief Structure used to hold authentication related fields.
*/
typedef struct {
mbedtls_des3_context des_context; /**< Context for mbedtls des functions. */
FelicaSessionKey session_key; /**< Calculated session key. */
FelicaAuthenticationContext context; /**< Public auth context provided to upper levels. */
} FelicaAuthentication;
/**
* @brief Felica poller event data.
*/
typedef union {
FelicaError error; /**< Error code indicating card activation fail reason. */
FelicaAuthenticationContext* auth_context; /**< Authentication context to be filled by user. */
} FelicaPollerEventData;
/**
+103 -4
View File
@@ -3,6 +3,11 @@
#include <nfc/helpers/felica_crc.h>
#define TAG "FelicaPoller"
#define FELICA_CMD_READ_WITHOUT_ENCRYPTION (0x06U)
#define FELICA_CMD_WRITE_WITHOUT_ENCRYPTION (0x08U)
#define FELICA_SERVICE_RW_ACCESS (0x0009U)
#define FELICA_SERVICE_RO_ACCESS (0x000BU)
static FelicaError felica_poller_process_error(NfcError error) {
switch(error) {
@@ -15,8 +20,8 @@ static FelicaError felica_poller_process_error(NfcError error) {
}
}
static FelicaError felica_poller_frame_exchange(
FelicaPoller* instance,
FelicaError felica_poller_frame_exchange(
const FelicaPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
@@ -93,11 +98,105 @@ FelicaError felica_poller_polling(
return error;
}
static void felica_poller_prepare_tx_buffer(
const FelicaPoller* instance,
const uint8_t command,
const uint16_t service_code,
const uint8_t block_count,
const uint8_t* const blocks,
const uint8_t data_block_count,
const uint8_t* data) {
FelicaCommandHeader cmd = {
.code = command,
.idm = instance->data->idm,
.service_num = 1,
.service_code = service_code,
.block_count = block_count,
};
FelicaBlockListElement block_list[4] = {{0}, {0}, {0}, {0}};
for(uint8_t i = 0; i < block_count; i++) {
block_list[i].length = 1;
block_list[i].block_number = blocks[i];
}
uint8_t block_list_count = block_count;
uint8_t block_list_size = block_list_count * sizeof(FelicaBlockListElement);
uint8_t total_size = sizeof(FelicaCommandHeader) + 1 + block_list_size +
data_block_count * FELICA_DATA_BLOCK_SIZE;
bit_buffer_reset(instance->tx_buffer);
bit_buffer_append_byte(instance->tx_buffer, total_size);
bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)&cmd, sizeof(FelicaCommandHeader));
bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)&block_list, block_list_size);
if(data_block_count != 0) {
bit_buffer_append_bytes(
instance->tx_buffer, data, data_block_count * FELICA_DATA_BLOCK_SIZE);
}
}
FelicaError felica_poller_read_blocks(
FelicaPoller* instance,
const uint8_t block_count,
const uint8_t* const block_numbers,
FelicaPollerReadCommandResponse** const response_ptr) {
furi_assert(instance);
furi_assert(block_count <= 4);
furi_assert(block_numbers);
furi_assert(response_ptr);
felica_poller_prepare_tx_buffer(
instance,
FELICA_CMD_READ_WITHOUT_ENCRYPTION,
FELICA_SERVICE_RO_ACCESS,
block_count,
block_numbers,
0,
NULL);
bit_buffer_reset(instance->rx_buffer);
FelicaError error = felica_poller_frame_exchange(
instance, instance->tx_buffer, instance->rx_buffer, FELICA_POLLER_POLLING_FWT);
if(error == FelicaErrorNone) {
*response_ptr = (FelicaPollerReadCommandResponse*)bit_buffer_get_data(instance->rx_buffer);
}
return error;
}
FelicaError felica_poller_write_blocks(
const FelicaPoller* instance,
const uint8_t block_count,
const uint8_t* const block_numbers,
const uint8_t* data,
FelicaPollerWriteCommandResponse** const response_ptr) {
furi_assert(instance);
furi_assert(block_count <= 2);
furi_assert(block_numbers);
furi_assert(data);
furi_assert(response_ptr);
felica_poller_prepare_tx_buffer(
instance,
FELICA_CMD_WRITE_WITHOUT_ENCRYPTION,
FELICA_SERVICE_RW_ACCESS,
block_count,
block_numbers,
block_count,
data);
bit_buffer_reset(instance->rx_buffer);
FelicaError error = felica_poller_frame_exchange(
instance, instance->tx_buffer, instance->rx_buffer, FELICA_POLLER_POLLING_FWT);
if(error == FelicaErrorNone) {
*response_ptr =
(FelicaPollerWriteCommandResponse*)bit_buffer_get_data(instance->rx_buffer);
}
return error;
}
FelicaError felica_poller_activate(FelicaPoller* instance, FelicaData* data) {
furi_assert(instance);
felica_reset(data);
FelicaError ret;
do {
+103 -1
View File
@@ -1,7 +1,6 @@
#pragma once
#include "felica_poller.h"
#include <toolbox/bit_buffer.h>
#ifdef __cplusplus
@@ -18,11 +17,20 @@ extern "C" {
typedef enum {
FelicaPollerStateIdle,
FelicaPollerStateActivated,
FelicaPollerStateAuthenticateInternal,
FelicaPollerStateAuthenticateExternal,
FelicaPollerStateReadBlocks,
FelicaPollerStateReadSuccess,
FelicaPollerStateReadFailed,
FelicaPollerStateNum
} FelicaPollerState;
struct FelicaPoller {
Nfc* nfc;
FelicaPollerState state;
FelicaAuthentication auth;
FelicaData* data;
BitBuffer* tx_buffer;
BitBuffer* rx_buffer;
@@ -31,6 +39,7 @@ struct FelicaPoller {
FelicaPollerEvent felica_event;
FelicaPollerEventData felica_event_data;
NfcGenericCallback callback;
uint8_t block_index;
void* context;
};
@@ -46,13 +55,106 @@ typedef struct {
uint8_t request_data[2];
} FelicaPollerPollingResponse;
typedef struct {
uint8_t service_code : 4;
uint8_t access_mode : 3;
uint8_t length : 1;
uint8_t block_number;
} FelicaBlockListElement;
#pragma pack(push, 1)
typedef struct {
uint8_t code;
FelicaIDm idm;
uint8_t service_num;
uint16_t service_code;
uint8_t block_count;
} FelicaCommandHeader;
#pragma pack(pop)
typedef struct {
uint8_t length;
uint8_t response_code;
FelicaIDm idm;
uint8_t SF1;
uint8_t SF2;
uint8_t block_count;
uint8_t data[];
} FelicaPollerReadCommandResponse;
typedef struct {
uint8_t length;
uint8_t response_code;
FelicaIDm idm;
uint8_t SF1;
uint8_t SF2;
} FelicaPollerWriteCommandResponse;
const FelicaData* felica_poller_get_data(FelicaPoller* instance);
/**
* @brief Performs felica polling operation as part of the activation process
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] cmd Pointer to polling command structure
* @param[out] resp Pointer to the response structure
* @return FelicaErrorNone on success, an error code on failure
*/
FelicaError felica_poller_polling(
FelicaPoller* instance,
const FelicaPollerPollingCommand* cmd,
FelicaPollerPollingResponse* resp);
/**
* @brief Performs felica read operation for blocks provided as parameters
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] block_count Amount of blocks involved in reading procedure
* @param[in] block_numbers Array with block indexes according to felica docs
* @param[out] response_ptr Pointer to the response structure
* @return FelicaErrorNone on success, an error code on failure.
*/
FelicaError felica_poller_read_blocks(
FelicaPoller* instance,
const uint8_t block_count,
const uint8_t* const block_numbers,
FelicaPollerReadCommandResponse** const response_ptr);
/**
* @brief Performs felica write operation with data provided as parameters
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] block_count Amount of blocks involved in writing procedure
* @param[in] block_numbers Array with block indexes according to felica docs
* @param[in] data Data of blocks provided in block_numbers
* @param[out] response_ptr Pointer to the response structure
* @return FelicaErrorNone on success, an error code on failure.
*/
FelicaError felica_poller_write_blocks(
const FelicaPoller* instance,
const uint8_t block_count,
const uint8_t* const block_numbers,
const uint8_t* data,
FelicaPollerWriteCommandResponse** const response_ptr);
/**
* @brief Perform frame exchange procedure.
*
* Prepares data for sending by adding crc, after that performs
* low level calls to send package data to the card
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] tx_buffer pointer to the buffer with data to be transmitted
* @param[out] rx_buffer pointer to the buffer with received data from card
* @param[in] fwt timeout window
* @return FelicaErrorNone on success, an error code on failure.
*/
FelicaError felica_poller_frame_exchange(
const FelicaPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt);
#ifdef __cplusplus
}
#endif
+25 -19
View File
@@ -28,36 +28,40 @@ const NfcDeviceBase nfc_device_iso14443_3a = {
.get_base_data = (NfcDeviceGetBaseData)iso14443_3a_get_base_data,
};
Iso14443_3aData* iso14443_3a_alloc() {
Iso14443_3aData* iso14443_3a_alloc(void) {
Iso14443_3aData* data = malloc(sizeof(Iso14443_3aData));
return data;
}
void iso14443_3a_free(Iso14443_3aData* data) {
furi_assert(data);
furi_check(data);
free(data);
}
void iso14443_3a_reset(Iso14443_3aData* data) {
furi_assert(data);
furi_check(data);
memset(data, 0, sizeof(Iso14443_3aData));
}
void iso14443_3a_copy(Iso14443_3aData* data, const Iso14443_3aData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
*data = *other;
}
bool iso14443_3a_verify(Iso14443_3aData* data, const FuriString* device_type) {
UNUSED(data);
furi_check(device_type);
return furi_string_equal(device_type, ISO14443_3A_PROTOCOL_NAME_LEGACY);
}
bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool parsed = false;
@@ -78,7 +82,8 @@ bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version
}
bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool saved = false;
@@ -98,8 +103,8 @@ bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff) {
}
bool iso14443_3a_is_equal(const Iso14443_3aData* data, const Iso14443_3aData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
return memcmp(data, other, sizeof(Iso14443_3aData)) == 0;
}
@@ -111,7 +116,7 @@ const char* iso14443_3a_get_device_name(const Iso14443_3aData* data, NfcDeviceNa
}
const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len) {
furi_assert(data);
furi_check(data);
if(uid_len) {
*uid_len = data->uid_len;
@@ -121,7 +126,8 @@ const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len)
}
bool iso14443_3a_set_uid(Iso14443_3aData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
furi_check(uid);
const bool uid_valid = uid_len == ISO14443_3A_UID_4_BYTES ||
uid_len == ISO14443_3A_UID_7_BYTES ||
@@ -141,7 +147,7 @@ Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data) {
}
uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* data) {
furi_assert(data);
furi_check(data);
uint32_t cuid = 0;
const uint8_t* cuid_start = data->uid;
@@ -154,33 +160,33 @@ uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* data) {
}
bool iso14443_3a_supports_iso14443_4(const Iso14443_3aData* data) {
furi_assert(data);
furi_check(data);
return data->sak & ISO14443A_ATS_BIT;
}
uint8_t iso14443_3a_get_sak(const Iso14443_3aData* data) {
furi_assert(data);
furi_check(data);
return data->sak;
}
void iso14443_3a_get_atqa(const Iso14443_3aData* data, uint8_t atqa[2]) {
furi_assert(data);
furi_assert(atqa);
furi_check(data);
furi_check(atqa);
memcpy(atqa, data->atqa, sizeof(data->atqa));
}
void iso14443_3a_set_sak(Iso14443_3aData* data, uint8_t sak) {
furi_assert(data);
furi_check(data);
data->sak = sak;
}
void iso14443_3a_set_atqa(Iso14443_3aData* data, const uint8_t atqa[2]) {
furi_assert(data);
furi_assert(atqa);
furi_check(data);
furi_check(atqa);
memcpy(data->atqa, atqa, sizeof(data->atqa));
}
+1 -1
View File
@@ -62,7 +62,7 @@ typedef struct {
uint8_t sak;
} Iso14443_3aData;
Iso14443_3aData* iso14443_3a_alloc();
Iso14443_3aData* iso14443_3a_alloc(void);
void iso14443_3a_free(Iso14443_3aData* data);
@@ -55,8 +55,8 @@ static Iso14443_3aError iso14443_3a_poller_standard_frame_exchange(
}
Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_check(instance);
furi_check(instance->nfc);
NfcError error = NfcErrorNone;
Iso14443_3aError ret = Iso14443_3aErrorNone;
@@ -80,9 +80,9 @@ Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance)
}
Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_assert(instance->tx_buffer);
furi_check(instance);
furi_check(instance->nfc);
furi_check(instance->tx_buffer);
uint8_t halt_cmd[2] = {0x50, 0x00};
bit_buffer_copy_bytes(instance->tx_buffer, halt_cmd, sizeof(halt_cmd));
@@ -96,10 +96,10 @@ Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance) {
Iso14443_3aError
iso14443_3a_poller_activate(Iso14443_3aPoller* instance, Iso14443_3aData* iso14443_3a_data) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_assert(instance->tx_buffer);
furi_assert(instance->rx_buffer);
furi_check(instance);
furi_check(instance->nfc);
furi_check(instance->tx_buffer);
furi_check(instance->rx_buffer);
// Reset Iso14443_3a poller state
memset(&instance->col_res, 0, sizeof(instance->col_res));
@@ -244,9 +244,9 @@ Iso14443_3aError iso14443_3a_poller_txrx_custom_parity(
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
furi_assert(instance);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
Iso14443_3aError ret = Iso14443_3aErrorNone;
NfcError error =
@@ -263,9 +263,9 @@ Iso14443_3aError iso14443_3a_poller_txrx(
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
furi_assert(instance);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
Iso14443_3aError ret = Iso14443_3aErrorNone;
NfcError error = nfc_poller_trx(instance->nfc, tx_buffer, rx_buffer, fwt);
@@ -281,9 +281,9 @@ Iso14443_3aError iso14443_3a_poller_send_standard_frame(
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
furi_assert(instance);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
Iso14443_3aError ret =
iso14443_3a_poller_standard_frame_exchange(instance, tx_buffer, rx_buffer, fwt);
@@ -35,8 +35,8 @@ NfcCommand iso14443_3a_poller_read_callback(NfcGenericEvent event, void* context
}
Iso14443_3aError iso14443_3a_poller_sync_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data) {
furi_assert(nfc);
furi_assert(iso14443_3a_data);
furi_check(nfc);
furi_check(iso14443_3a_data);
Iso14443_3aPollerContext poller_context = {};
poller_context.thread_id = furi_thread_get_current_id();
+23 -18
View File
@@ -30,24 +30,26 @@ const NfcDeviceBase nfc_device_iso14443_3b = {
.get_base_data = (NfcDeviceGetBaseData)iso14443_3b_get_base_data,
};
Iso14443_3bData* iso14443_3b_alloc() {
Iso14443_3bData* iso14443_3b_alloc(void) {
Iso14443_3bData* data = malloc(sizeof(Iso14443_3bData));
return data;
}
void iso14443_3b_free(Iso14443_3bData* data) {
furi_assert(data);
furi_check(data);
free(data);
}
void iso14443_3b_reset(Iso14443_3bData* data) {
furi_check(data);
memset(data, 0, sizeof(Iso14443_3bData));
}
void iso14443_3b_copy(Iso14443_3bData* data, const Iso14443_3bData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
*data = *other;
}
@@ -60,7 +62,8 @@ bool iso14443_3b_verify(Iso14443_3bData* data, const FuriString* device_type) {
}
bool iso14443_3b_load(Iso14443_3bData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool parsed = false;
@@ -84,7 +87,8 @@ bool iso14443_3b_load(Iso14443_3bData* data, FlipperFormat* ff, uint32_t version
}
bool iso14443_3b_save(const Iso14443_3bData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool saved = false;
@@ -107,8 +111,8 @@ bool iso14443_3b_save(const Iso14443_3bData* data, FlipperFormat* ff) {
}
bool iso14443_3b_is_equal(const Iso14443_3bData* data, const Iso14443_3bData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
return memcmp(data, other, sizeof(Iso14443_3bData)) == 0;
}
@@ -121,15 +125,16 @@ const char* iso14443_3b_get_device_name(const Iso14443_3bData* data, NfcDeviceNa
}
const uint8_t* iso14443_3b_get_uid(const Iso14443_3bData* data, size_t* uid_len) {
furi_assert(data);
furi_assert(uid_len);
furi_check(data);
furi_check(uid_len);
*uid_len = ISO14443_3B_UID_SIZE;
return data->uid;
}
bool iso14443_3b_set_uid(Iso14443_3bData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
furi_check(uid);
const bool uid_valid = uid_len == ISO14443_3B_UID_SIZE;
@@ -146,13 +151,13 @@ Iso14443_3bData* iso14443_3b_get_base_data(const Iso14443_3bData* data) {
}
bool iso14443_3b_supports_iso14443_4(const Iso14443_3bData* data) {
furi_assert(data);
furi_check(data);
return data->protocol_info.protocol_type == 0x01;
}
bool iso14443_3b_supports_bit_rate(const Iso14443_3bData* data, Iso14443_3bBitRate bit_rate) {
furi_assert(data);
furi_check(data);
const uint8_t capability = data->protocol_info.bit_rate_capability;
@@ -177,7 +182,7 @@ bool iso14443_3b_supports_bit_rate(const Iso14443_3bData* data, Iso14443_3bBitRa
}
bool iso14443_3b_supports_frame_option(const Iso14443_3bData* data, Iso14443_3bFrameOption option) {
furi_assert(data);
furi_check(data);
switch(option) {
case Iso14443_3bFrameOptionNad:
@@ -190,15 +195,15 @@ bool iso14443_3b_supports_frame_option(const Iso14443_3bData* data, Iso14443_3bF
}
const uint8_t* iso14443_3b_get_application_data(const Iso14443_3bData* data, size_t* data_size) {
furi_assert(data);
furi_assert(data_size);
furi_check(data);
furi_check(data_size);
*data_size = ISO14443_3B_APP_DATA_SIZE;
return data->app_data;
}
uint16_t iso14443_3b_get_frame_size_max(const Iso14443_3bData* data) {
furi_assert(data);
furi_check(data);
const uint8_t fs_bits = data->protocol_info.max_frame_size;
@@ -216,7 +221,7 @@ uint16_t iso14443_3b_get_frame_size_max(const Iso14443_3bData* data) {
}
uint32_t iso14443_3b_get_fwt_fc_max(const Iso14443_3bData* data) {
furi_assert(data);
furi_check(data);
const uint8_t fwi = data->protocol_info.fwi;
return fwi < 0x0F ? 4096UL << fwi : ISO14443_3B_FDT_POLL_DEFAULT_FC;
+1 -1
View File
@@ -40,7 +40,7 @@ typedef struct Iso14443_3bData Iso14443_3bData;
// Virtual methods
Iso14443_3bData* iso14443_3b_alloc();
Iso14443_3bData* iso14443_3b_alloc(void);
void iso14443_3b_free(Iso14443_3bData* data);
@@ -64,8 +64,9 @@ static Iso14443_3bError iso14443_3b_poller_frame_exchange(
}
Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_check(instance);
furi_check(instance->nfc);
furi_check(data);
iso14443_3b_reset(data);
@@ -155,7 +156,7 @@ Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso144
}
Iso14443_3bError iso14443_3b_poller_halt(Iso14443_3bPoller* instance) {
furi_assert(instance);
furi_check(instance);
bit_buffer_reset(instance->tx_buffer);
bit_buffer_reset(instance->rx_buffer);
@@ -188,6 +189,10 @@ Iso14443_3bError iso14443_3b_poller_send_frame(
Iso14443_3bPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer) {
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
Iso14443_3bError ret;
do {
+23 -15
View File
@@ -35,7 +35,7 @@ const NfcDeviceBase nfc_device_iso14443_4a = {
.get_base_data = (NfcDeviceGetBaseData)iso14443_4a_get_base_data,
};
Iso14443_4aData* iso14443_4a_alloc() {
Iso14443_4aData* iso14443_4a_alloc(void) {
Iso14443_4aData* data = malloc(sizeof(Iso14443_4aData));
data->iso14443_3a_data = iso14443_3a_alloc();
@@ -45,7 +45,7 @@ Iso14443_4aData* iso14443_4a_alloc() {
}
void iso14443_4a_free(Iso14443_4aData* data) {
furi_assert(data);
furi_check(data);
simple_array_free(data->ats_data.t1_tk);
iso14443_3a_free(data->iso14443_3a_data);
@@ -54,7 +54,7 @@ void iso14443_4a_free(Iso14443_4aData* data) {
}
void iso14443_4a_reset(Iso14443_4aData* data) {
furi_assert(data);
furi_check(data);
iso14443_3a_reset(data->iso14443_3a_data);
@@ -68,8 +68,8 @@ void iso14443_4a_reset(Iso14443_4aData* data) {
}
void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data);
@@ -91,7 +91,8 @@ bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type) {
}
bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool parsed = false;
@@ -145,7 +146,8 @@ bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version
}
bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool saved = false;
@@ -186,6 +188,9 @@ bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff) {
}
bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other) {
furi_check(data);
furi_check(other);
return iso14443_3a_is_equal(data->iso14443_3a_data, other->iso14443_3a_data);
}
@@ -196,23 +201,26 @@ const char* iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcDeviceNa
}
const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len) {
furi_check(data);
furi_check(uid_len);
return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len);
}
bool iso14443_4a_set_uid(Iso14443_4aData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
return iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len);
}
Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data) {
furi_assert(data);
furi_check(data);
return data->iso14443_3a_data;
}
uint16_t iso14443_4a_get_frame_size_max(const Iso14443_4aData* data) {
furi_assert(data);
furi_check(data);
const uint8_t fsci = data->ats_data.t0 & 0x0F;
@@ -230,7 +238,7 @@ uint16_t iso14443_4a_get_frame_size_max(const Iso14443_4aData* data) {
}
uint32_t iso14443_4a_get_fwt_fc_max(const Iso14443_4aData* data) {
furi_assert(data);
furi_check(data);
uint32_t fwt_fc_max = ISO14443_4A_FDT_DEFAULT_FC;
@@ -248,8 +256,8 @@ uint32_t iso14443_4a_get_fwt_fc_max(const Iso14443_4aData* data) {
}
const uint8_t* iso14443_4a_get_historical_bytes(const Iso14443_4aData* data, uint32_t* count) {
furi_assert(data);
furi_assert(count);
furi_check(data);
furi_check(count);
*count = simple_array_get_count(data->ats_data.t1_tk);
const uint8_t* hist_bytes = NULL;
@@ -261,7 +269,7 @@ const uint8_t* iso14443_4a_get_historical_bytes(const Iso14443_4aData* data, uin
}
bool iso14443_4a_supports_bit_rate(const Iso14443_4aData* data, Iso14443_4aBitRate bit_rate) {
furi_assert(data);
furi_check(data);
if(!(data->ats_data.t0 & ISO14443_4A_ATS_T0_TA1))
return bit_rate == Iso14443_4aBitRateBoth106Kbit;
@@ -289,7 +297,7 @@ bool iso14443_4a_supports_bit_rate(const Iso14443_4aData* data, Iso14443_4aBitRa
}
bool iso14443_4a_supports_frame_option(const Iso14443_4aData* data, Iso14443_4aFrameOption option) {
furi_assert(data);
furi_check(data);
const Iso14443_4aAtsData* ats_data = &data->ats_data;
if(!(ats_data->t0 & ISO14443_4A_ATS_T0_TC1)) return false;
+1 -1
View File
@@ -46,7 +46,7 @@ typedef struct {
// Virtual methods
Iso14443_4aData* iso14443_4a_alloc();
Iso14443_4aData* iso14443_4a_alloc(void);
void iso14443_4a_free(Iso14443_4aData* data);
@@ -7,9 +7,13 @@
#define TAG "Iso14443_4aPoller"
#define ISO14443_4A_FSDI_256 (0x8U)
#define ISO14443_4A_FWT_MAX (4096UL << 14)
#define ISO14443_4A_WTXM_MASK (0x3FU)
#define ISO14443_4A_WTXM_MAX (0x3BU)
#define ISO14443_4A_SWTX (0xF2U)
Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) {
furi_assert(instance);
furi_check(instance);
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
instance->poller_state = Iso14443_4aPollerStateIdle;
@@ -19,7 +23,8 @@ Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) {
Iso14443_4aError
iso14443_4a_poller_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data) {
furi_assert(instance);
furi_check(instance);
furi_check(data);
bit_buffer_reset(instance->tx_buffer);
bit_buffer_append_byte(instance->tx_buffer, ISO14443_4A_CMD_READ_ATS);
@@ -54,7 +59,9 @@ Iso14443_4aError iso14443_4a_poller_send_block(
Iso14443_4aPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer) {
furi_assert(instance);
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
bit_buffer_reset(instance->tx_buffer);
iso14443_4_layer_encode_block(instance->iso14443_4_layer, tx_buffer, instance->tx_buffer);
@@ -71,9 +78,35 @@ Iso14443_4aError iso14443_4a_poller_send_block(
if(iso14443_3a_error != Iso14443_3aErrorNone) {
error = iso14443_4a_process_error(iso14443_3a_error);
break;
}
} else if(!iso14443_4_layer_decode_block(
instance->iso14443_4_layer, rx_buffer, instance->rx_buffer)) {
if(bit_buffer_starts_with_byte(instance->rx_buffer, ISO14443_4A_SWTX)) {
do {
uint8_t wtxm = bit_buffer_get_byte(instance->rx_buffer, 1) & ISO14443_4A_WTXM_MASK;
if(wtxm > ISO14443_4A_WTXM_MAX) {
return Iso14443_4aErrorProtocol;
}
bit_buffer_reset(instance->tx_buffer);
bit_buffer_copy_left(instance->tx_buffer, instance->rx_buffer, 1);
bit_buffer_append_byte(instance->tx_buffer, wtxm);
iso14443_3a_error = iso14443_3a_poller_send_standard_frame(
instance->iso14443_3a_poller,
instance->tx_buffer,
instance->rx_buffer,
MAX(iso14443_4a_get_fwt_fc_max(instance->data) * wtxm, ISO14443_4A_FWT_MAX));
if(iso14443_3a_error != Iso14443_3aErrorNone) {
error = iso14443_4a_process_error(iso14443_3a_error);
return error;
}
} while(bit_buffer_starts_with_byte(instance->rx_buffer, ISO14443_4A_SWTX));
}
if(!iso14443_4_layer_decode_block(
instance->iso14443_4_layer, rx_buffer, instance->rx_buffer)) {
error = Iso14443_4aErrorProtocol;
break;
}
+18 -9
View File
@@ -22,7 +22,7 @@ const NfcDeviceBase nfc_device_iso14443_4b = {
.get_base_data = (NfcDeviceGetBaseData)iso14443_4b_get_base_data,
};
Iso14443_4bData* iso14443_4b_alloc() {
Iso14443_4bData* iso14443_4b_alloc(void) {
Iso14443_4bData* data = malloc(sizeof(Iso14443_4bData));
data->iso14443_3b_data = iso14443_3b_alloc();
@@ -30,21 +30,21 @@ Iso14443_4bData* iso14443_4b_alloc() {
}
void iso14443_4b_free(Iso14443_4bData* data) {
furi_assert(data);
furi_check(data);
iso14443_3b_free(data->iso14443_3b_data);
free(data);
}
void iso14443_4b_reset(Iso14443_4bData* data) {
furi_assert(data);
furi_check(data);
iso14443_3b_reset(data->iso14443_3b_data);
}
void iso14443_4b_copy(Iso14443_4bData* data, const Iso14443_4bData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
iso14443_3b_copy(data->iso14443_3b_data, other->iso14443_3b_data);
}
@@ -58,16 +58,21 @@ bool iso14443_4b_verify(Iso14443_4bData* data, const FuriString* device_type) {
}
bool iso14443_4b_load(Iso14443_4bData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
return iso14443_3b_load(data->iso14443_3b_data, ff, version);
}
bool iso14443_4b_save(const Iso14443_4bData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
return iso14443_3b_save(data->iso14443_3b_data, ff);
}
bool iso14443_4b_is_equal(const Iso14443_4bData* data, const Iso14443_4bData* other) {
furi_check(data);
furi_check(other);
return iso14443_3b_is_equal(data->iso14443_3b_data, other->iso14443_3b_data);
}
@@ -78,17 +83,21 @@ const char* iso14443_4b_get_device_name(const Iso14443_4bData* data, NfcDeviceNa
}
const uint8_t* iso14443_4b_get_uid(const Iso14443_4bData* data, size_t* uid_len) {
furi_check(data);
furi_check(uid_len);
return iso14443_3b_get_uid(data->iso14443_3b_data, uid_len);
}
bool iso14443_4b_set_uid(Iso14443_4bData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
furi_check(uid);
return iso14443_3b_set_uid(data->iso14443_3b_data, uid, uid_len);
}
Iso14443_3bData* iso14443_4b_get_base_data(const Iso14443_4bData* data) {
furi_assert(data);
furi_check(data);
return data->iso14443_3b_data;
}
+1 -1
View File
@@ -17,7 +17,7 @@ typedef struct Iso14443_4bData Iso14443_4bData;
// Virtual methods
Iso14443_4bData* iso14443_4b_alloc();
Iso14443_4bData* iso14443_4b_alloc(void);
void iso14443_4b_free(Iso14443_4bData* data);
@@ -7,7 +7,7 @@
#define TAG "Iso14443_4bPoller"
Iso14443_4bError iso14443_4b_poller_halt(Iso14443_4bPoller* instance) {
furi_assert(instance);
furi_check(instance);
iso14443_3b_poller_halt(instance->iso14443_3b_poller);
instance->poller_state = Iso14443_4bPollerStateIdle;
@@ -19,7 +19,9 @@ Iso14443_4bError iso14443_4b_poller_send_block(
Iso14443_4bPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer) {
furi_assert(instance);
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
bit_buffer_reset(instance->tx_buffer);
iso14443_4_layer_encode_block(instance->iso14443_4_layer, tx_buffer, instance->tx_buffer);
+27 -20
View File
@@ -36,7 +36,7 @@ const NfcDeviceBase nfc_device_iso15693_3 = {
.get_base_data = (NfcDeviceGetBaseData)iso15693_3_get_base_data,
};
Iso15693_3Data* iso15693_3_alloc() {
Iso15693_3Data* iso15693_3_alloc(void) {
Iso15693_3Data* data = malloc(sizeof(Iso15693_3Data));
data->block_data = simple_array_alloc(&simple_array_config_uint8_t);
@@ -46,7 +46,7 @@ Iso15693_3Data* iso15693_3_alloc() {
}
void iso15693_3_free(Iso15693_3Data* data) {
furi_assert(data);
furi_check(data);
simple_array_free(data->block_data);
simple_array_free(data->block_security);
@@ -54,7 +54,7 @@ void iso15693_3_free(Iso15693_3Data* data) {
}
void iso15693_3_reset(Iso15693_3Data* data) {
furi_assert(data);
furi_check(data);
memset(data->uid, 0, ISO15693_3_UID_SIZE);
memset(&data->system_info, 0, sizeof(Iso15693_3SystemInfo));
@@ -65,8 +65,8 @@ void iso15693_3_reset(Iso15693_3Data* data) {
}
void iso15693_3_copy(Iso15693_3Data* data, const Iso15693_3Data* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
memcpy(data->uid, other->uid, ISO15693_3_UID_SIZE);
@@ -79,6 +79,8 @@ void iso15693_3_copy(Iso15693_3Data* data, const Iso15693_3Data* other) {
bool iso15693_3_verify(Iso15693_3Data* data, const FuriString* device_type) {
UNUSED(data);
furi_check(device_type);
return furi_string_equal(device_type, ISO15693_3_PROTOCOL_NAME_LEGACY);
}
@@ -136,7 +138,8 @@ static inline bool iso15693_3_load_security(Iso15693_3Data* data, FlipperFormat*
}
bool iso15693_3_load(Iso15693_3Data* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
UNUSED(version);
bool loaded = false;
@@ -207,7 +210,8 @@ bool iso15693_3_load(Iso15693_3Data* data, FlipperFormat* ff, uint32_t version)
}
bool iso15693_3_save(const Iso15693_3Data* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool saved = false;
@@ -280,12 +284,15 @@ bool iso15693_3_save(const Iso15693_3Data* data, FlipperFormat* ff) {
}
bool iso15693_3_is_equal(const Iso15693_3Data* data, const Iso15693_3Data* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
return memcmp(data->uid, other->uid, ISO15693_3_UID_SIZE) == 0 &&
memcmp(&data->settings, &other->settings, sizeof(Iso15693_3Settings)) == 0 &&
memcmp(&data->system_info, &other->system_info, sizeof(Iso15693_3SystemInfo)) == 0 &&
memcmp( //-V1103
&data->system_info,
&other->system_info,
sizeof(Iso15693_3SystemInfo)) == 0 &&
simple_array_is_equal(data->block_data, other->block_data) &&
simple_array_is_equal(data->block_security, other->block_security);
}
@@ -298,15 +305,15 @@ const char* iso15693_3_get_device_name(const Iso15693_3Data* data, NfcDeviceName
}
const uint8_t* iso15693_3_get_uid(const Iso15693_3Data* data, size_t* uid_len) {
furi_assert(data);
furi_check(data);
if(uid_len) *uid_len = ISO15693_3_UID_SIZE;
return data->uid;
}
bool iso15693_3_set_uid(Iso15693_3Data* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_assert(uid);
furi_check(data);
furi_check(uid);
bool uid_valid = uid_len == ISO15693_3_UID_SIZE;
@@ -325,33 +332,33 @@ Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data) {
}
bool iso15693_3_is_block_locked(const Iso15693_3Data* data, uint8_t block_index) {
furi_assert(data);
furi_assert(block_index < data->system_info.block_count);
furi_check(data);
furi_check(block_index < data->system_info.block_count);
return *(const uint8_t*)simple_array_cget(data->block_security, block_index);
}
uint8_t iso15693_3_get_manufacturer_id(const Iso15693_3Data* data) {
furi_assert(data);
furi_check(data);
return data->uid[1];
}
uint16_t iso15693_3_get_block_count(const Iso15693_3Data* data) {
furi_assert(data);
furi_check(data);
return data->system_info.block_count;
}
uint8_t iso15693_3_get_block_size(const Iso15693_3Data* data) {
furi_assert(data);
furi_check(data);
return data->system_info.block_size;
}
const uint8_t* iso15693_3_get_block_data(const Iso15693_3Data* data, uint8_t block_index) {
furi_assert(data);
furi_assert(data->system_info.block_count > block_index);
furi_check(data);
furi_check(data->system_info.block_count > block_index);
return (const uint8_t*)simple_array_cget(
data->block_data, block_index * data->system_info.block_size);
+1 -1
View File
@@ -122,7 +122,7 @@ typedef struct {
SimpleArray* block_security;
} Iso15693_3Data;
Iso15693_3Data* iso15693_3_alloc();
Iso15693_3Data* iso15693_3_alloc(void);
void iso15693_3_free(Iso15693_3Data* data);
@@ -38,6 +38,8 @@ Iso15693_3Error iso15693_3_poller_send_frame(
BitBuffer* rx_buffer,
uint32_t fwt) {
furi_assert(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
Iso15693_3Error ret = Iso15693_3ErrorNone;
-178
View File
@@ -1,178 +0,0 @@
#include "crypto1.h"
#include <lib/nfc/helpers/nfc_util.h>
#include <lib/bit_lib/bit_lib.h>
#include <furi.h>
// Algorithm from https://github.com/RfidResearchGroup/proxmark3.git
#define SWAPENDIAN(x) \
((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16)
#define LF_POLY_ODD (0x29CE5C)
#define LF_POLY_EVEN (0x870804)
#define BEBIT(x, n) FURI_BIT(x, (n) ^ 24)
Crypto1* crypto1_alloc() {
Crypto1* instance = malloc(sizeof(Crypto1));
return instance;
}
void crypto1_free(Crypto1* instance) {
furi_assert(instance);
free(instance);
}
void crypto1_reset(Crypto1* crypto1) {
furi_assert(crypto1);
crypto1->even = 0;
crypto1->odd = 0;
}
void crypto1_init(Crypto1* crypto1, uint64_t key) {
furi_assert(crypto1);
crypto1->even = 0;
crypto1->odd = 0;
for(int8_t i = 47; i > 0; i -= 2) {
crypto1->odd = crypto1->odd << 1 | FURI_BIT(key, (i - 1) ^ 7);
crypto1->even = crypto1->even << 1 | FURI_BIT(key, i ^ 7);
}
}
static uint32_t crypto1_filter(uint32_t in) {
uint32_t out = 0;
out = 0xf22c0 >> (in & 0xf) & 16;
out |= 0x6c9c0 >> (in >> 4 & 0xf) & 8;
out |= 0x3c8b0 >> (in >> 8 & 0xf) & 4;
out |= 0x1e458 >> (in >> 12 & 0xf) & 2;
out |= 0x0d938 >> (in >> 16 & 0xf) & 1;
return FURI_BIT(0xEC57E80A, out);
}
uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) {
furi_assert(crypto1);
uint8_t out = crypto1_filter(crypto1->odd);
uint32_t feed = out & (!!is_encrypted);
feed ^= !!in;
feed ^= LF_POLY_ODD & crypto1->odd;
feed ^= LF_POLY_EVEN & crypto1->even;
crypto1->even = crypto1->even << 1 | (nfc_util_even_parity32(feed));
FURI_SWAP(crypto1->odd, crypto1->even);
return out;
}
uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) {
furi_assert(crypto1);
uint8_t out = 0;
for(uint8_t i = 0; i < 8; i++) {
out |= crypto1_bit(crypto1, FURI_BIT(in, i), is_encrypted) << i;
}
return out;
}
uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) {
furi_assert(crypto1);
uint32_t out = 0;
for(uint8_t i = 0; i < 32; i++) {
out |= (uint32_t)crypto1_bit(crypto1, BEBIT(in, i), is_encrypted) << (24 ^ i);
}
return out;
}
uint32_t prng_successor(uint32_t x, uint32_t n) {
SWAPENDIAN(x);
while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
return SWAPENDIAN(x);
}
void crypto1_decrypt(Crypto1* crypto, const BitBuffer* buff, BitBuffer* out) {
furi_assert(crypto);
furi_assert(buff);
furi_assert(out);
size_t bits = bit_buffer_get_size(buff);
bit_buffer_set_size(out, bits);
const uint8_t* encrypted_data = bit_buffer_get_data(buff);
if(bits < 8) {
uint8_t decrypted_byte = 0;
uint8_t encrypted_byte = encrypted_data[0];
decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 0)) << 0;
decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 1)) << 1;
decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 2)) << 2;
decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 3)) << 3;
bit_buffer_set_byte(out, 0, decrypted_byte);
} else {
for(size_t i = 0; i < bits / 8; i++) {
uint8_t decrypted_byte = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i];
bit_buffer_set_byte(out, i, decrypted_byte);
}
}
}
void crypto1_encrypt(Crypto1* crypto, uint8_t* keystream, const BitBuffer* buff, BitBuffer* out) {
furi_assert(crypto);
furi_assert(buff);
furi_assert(out);
size_t bits = bit_buffer_get_size(buff);
bit_buffer_set_size(out, bits);
const uint8_t* plain_data = bit_buffer_get_data(buff);
if(bits < 8) {
uint8_t encrypted_byte = 0;
for(size_t i = 0; i < bits; i++) {
encrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i;
}
bit_buffer_set_byte(out, 0, encrypted_byte);
} else {
for(size_t i = 0; i < bits / 8; i++) {
uint8_t encrypted_byte = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^
plain_data[i];
bool parity_bit =
((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01);
bit_buffer_set_byte_with_parity(out, i, encrypted_byte, parity_bit);
}
}
}
void crypto1_encrypt_reader_nonce(
Crypto1* crypto,
uint64_t key,
uint32_t cuid,
uint8_t* nt,
uint8_t* nr,
BitBuffer* out,
bool is_nested) {
furi_assert(crypto);
furi_assert(nt);
furi_assert(nr);
furi_assert(out);
bit_buffer_set_size_bytes(out, 8);
uint32_t nt_num = bit_lib_bytes_to_num_be(nt, sizeof(uint32_t));
crypto1_init(crypto, key);
if(is_nested) {
nt_num = crypto1_word(crypto, nt_num ^ cuid, 1) ^ nt_num;
} else {
crypto1_word(crypto, nt_num ^ cuid, 0);
}
for(size_t i = 0; i < 4; i++) {
uint8_t byte = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
bool parity_bit = ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01);
bit_buffer_set_byte_with_parity(out, i, byte, parity_bit);
nr[i] = byte;
}
nt_num = prng_successor(nt_num, 32);
for(size_t i = 4; i < 8; i++) {
nt_num = prng_successor(nt_num, 8);
uint8_t byte = crypto1_byte(crypto, 0, 0) ^ (uint8_t)(nt_num);
bool parity_bit = ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt_num)) & 0x01);
bit_buffer_set_byte_with_parity(out, i, byte, parity_bit);
}
}
-45
View File
@@ -1,45 +0,0 @@
#pragma once
#include <toolbox/bit_buffer.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint32_t odd;
uint32_t even;
} Crypto1;
Crypto1* crypto1_alloc();
void crypto1_free(Crypto1* instance);
void crypto1_reset(Crypto1* crypto1);
void crypto1_init(Crypto1* crypto1, uint64_t key);
uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted);
uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted);
uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted);
void crypto1_decrypt(Crypto1* crypto, const BitBuffer* buff, BitBuffer* out);
void crypto1_encrypt(Crypto1* crypto, uint8_t* keystream, const BitBuffer* buff, BitBuffer* out);
void crypto1_encrypt_reader_nonce(
Crypto1* crypto,
uint64_t key,
uint32_t cuid,
uint8_t* nt,
uint8_t* nr,
BitBuffer* out,
bool is_nested);
uint32_t prng_successor(uint32_t x, uint32_t n);
#ifdef __cplusplus
}
#endif
+43 -33
View File
@@ -56,28 +56,28 @@ const NfcDeviceBase nfc_device_mf_classic = {
.get_base_data = (NfcDeviceGetBaseData)mf_classic_get_base_data,
};
MfClassicData* mf_classic_alloc() {
MfClassicData* mf_classic_alloc(void) {
MfClassicData* data = malloc(sizeof(MfClassicData));
data->iso14443_3a_data = iso14443_3a_alloc();
return data;
}
void mf_classic_free(MfClassicData* data) {
furi_assert(data);
furi_check(data);
iso14443_3a_free(data->iso14443_3a_data);
free(data);
}
void mf_classic_reset(MfClassicData* data) {
furi_assert(data);
furi_check(data);
iso14443_3a_reset(data->iso14443_3a_data);
}
void mf_classic_copy(MfClassicData* data, const MfClassicData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data);
for(size_t i = 0; i < COUNT_OF(data->block); i++) {
@@ -92,7 +92,9 @@ void mf_classic_copy(MfClassicData* data, const MfClassicData* other) {
}
bool mf_classic_verify(MfClassicData* data, const FuriString* device_type) {
furi_check(device_type);
UNUSED(data);
return furi_string_equal_str(device_type, "Mifare Classic");
}
@@ -146,7 +148,8 @@ static void mf_classic_parse_block(FuriString* block_str, MfClassicData* data, u
}
bool mf_classic_load(MfClassicData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
FuriString* temp_str = furi_string_alloc();
bool parsed = false;
@@ -255,7 +258,8 @@ static void
}
bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
FuriString* temp_str = furi_string_alloc();
bool saved = false;
@@ -297,6 +301,9 @@ bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff) {
}
bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other) {
furi_check(data);
furi_check(other);
bool is_equal = false;
bool data_array_is_equal = true;
@@ -329,8 +336,8 @@ bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other)
}
const char* mf_classic_get_device_name(const MfClassicData* data, NfcDeviceNameType name_type) {
furi_assert(data);
furi_assert(data->type < MfClassicTypeNum);
furi_check(data);
furi_check(data->type < MfClassicTypeNum);
if(name_type == NfcDeviceNameTypeFull) {
return mf_classic_features[data->type].full_name;
@@ -340,13 +347,13 @@ const char* mf_classic_get_device_name(const MfClassicData* data, NfcDeviceNameT
}
const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len) {
furi_assert(data);
furi_check(data);
return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len);
}
bool mf_classic_set_uid(MfClassicData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
bool uid_valid = iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len);
@@ -370,16 +377,18 @@ bool mf_classic_set_uid(MfClassicData* data, const uint8_t* uid, size_t uid_len)
}
Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data) {
furi_assert(data);
furi_check(data);
return data->iso14443_3a_data;
}
uint8_t mf_classic_get_total_sectors_num(MfClassicType type) {
furi_check(type < MfClassicTypeNum);
return mf_classic_features[type].sectors_total;
}
uint16_t mf_classic_get_total_block_num(MfClassicType type) {
furi_check(type < MfClassicTypeNum);
return mf_classic_features[type].blocks_total;
}
@@ -411,7 +420,7 @@ uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block) {
MfClassicSectorTrailer*
mf_classic_get_sector_trailer_by_sector(const MfClassicData* data, uint8_t sector_num) {
furi_assert(data);
furi_check(data);
uint8_t sec_tr_block = mf_classic_get_sector_trailer_num_by_sector(sector_num);
MfClassicSectorTrailer* sec_trailer = (MfClassicSectorTrailer*)&data->block[sec_tr_block];
@@ -436,7 +445,8 @@ uint8_t mf_classic_get_sector_by_block(uint8_t block) {
}
bool mf_classic_block_to_value(const MfClassicBlock* block, int32_t* value, uint8_t* addr) {
furi_assert(block);
furi_check(block);
furi_check(value);
uint32_t v = *(uint32_t*)&block->data[0];
uint32_t v_inv = *(uint32_t*)&block->data[sizeof(uint32_t)];
@@ -445,9 +455,7 @@ bool mf_classic_block_to_value(const MfClassicBlock* block, int32_t* value, uint
bool val_checks =
((v == v1) && (v == ~v_inv) && (block->data[12] == (~block->data[13] & 0xFF)) &&
(block->data[14] == (~block->data[15] & 0xFF)) && (block->data[12] == block->data[14]));
if(value) {
*value = (int32_t)v;
}
*value = (int32_t)v;
if(addr) {
*addr = block->data[12];
}
@@ -455,7 +463,7 @@ bool mf_classic_block_to_value(const MfClassicBlock* block, int32_t* value, uint
}
void mf_classic_value_to_block(int32_t value, uint8_t addr, MfClassicBlock* block) {
furi_assert(block);
furi_check(block);
uint32_t v_inv = ~((uint32_t)value);
@@ -473,7 +481,7 @@ bool mf_classic_is_key_found(
const MfClassicData* data,
uint8_t sector_num,
MfClassicKeyType key_type) {
furi_assert(data);
furi_check(data);
bool key_found = false;
if(key_type == MfClassicKeyTypeA) {
@@ -490,7 +498,7 @@ void mf_classic_set_key_found(
uint8_t sector_num,
MfClassicKeyType key_type,
uint64_t key) {
furi_assert(data);
furi_check(data);
uint8_t key_arr[6] = {};
MfClassicSectorTrailer* sec_trailer =
@@ -509,7 +517,7 @@ void mf_classic_set_key_not_found(
MfClassicData* data,
uint8_t sector_num,
MfClassicKeyType key_type) {
furi_assert(data);
furi_check(data);
if(key_type == MfClassicKeyTypeA) {
FURI_BIT_CLEAR(data->key_a_mask, sector_num);
@@ -519,13 +527,14 @@ void mf_classic_set_key_not_found(
}
bool mf_classic_is_block_read(const MfClassicData* data, uint8_t block_num) {
furi_assert(data);
furi_check(data);
return (FURI_BIT(data->block_read_mask[block_num / 32], block_num % 32) == 1);
}
void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data) {
furi_assert(data);
furi_check(data);
furi_check(block_data);
if(mf_classic_is_sector_trailer(block_num)) {
memcpy(&data->block[block_num].data[6], &block_data->data[6], 4);
@@ -536,7 +545,7 @@ void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassic
}
uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector) {
furi_assert(sector < 40);
furi_check(sector < 40);
uint8_t block = 0;
if(sector < 32) {
@@ -549,7 +558,8 @@ uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector) {
}
uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector) {
furi_assert(sector < 40);
furi_check(sector < 40);
return sector < 32 ? 4 : 16;
}
@@ -557,9 +567,9 @@ void mf_classic_get_read_sectors_and_keys(
const MfClassicData* data,
uint8_t* sectors_read,
uint8_t* keys_found) {
furi_assert(data);
furi_assert(sectors_read);
furi_assert(keys_found);
furi_check(data);
furi_check(sectors_read);
furi_check(keys_found);
*sectors_read = 0;
*keys_found = 0;
@@ -585,7 +595,7 @@ void mf_classic_get_read_sectors_and_keys(
}
bool mf_classic_is_card_read(const MfClassicData* data) {
furi_assert(data);
furi_check(data);
uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type);
uint8_t sectors_read = 0;
@@ -597,7 +607,7 @@ bool mf_classic_is_card_read(const MfClassicData* data) {
}
bool mf_classic_is_sector_read(const MfClassicData* data, uint8_t sector_num) {
furi_assert(data);
furi_check(data);
bool sector_read = false;
do {
@@ -662,7 +672,7 @@ bool mf_classic_is_allowed_access_data_block(
uint8_t block_num,
MfClassicKeyType key_type,
MfClassicAction action) {
furi_assert(sec_tr);
furi_check(sec_tr);
uint8_t* access_bits_arr = sec_tr->access_bits.data;
@@ -732,7 +742,7 @@ bool mf_classic_is_allowed_access(
uint8_t block_num,
MfClassicKeyType key_type,
MfClassicAction action) {
furi_assert(data);
furi_check(data);
bool access_allowed = false;
if(mf_classic_is_sector_trailer(block_num)) {
@@ -749,7 +759,7 @@ bool mf_classic_is_allowed_access(
}
bool mf_classic_is_value_block(MfClassicSectorTrailer* sec_tr, uint8_t block_num) {
furi_assert(sec_tr);
furi_check(sec_tr);
// Check if key A can write, if it can, it's transport configuration, not data block
return !mf_classic_is_allowed_access_data_block(
+1 -1
View File
@@ -143,7 +143,7 @@ typedef struct {
extern const NfcDeviceBase nfc_device_mf_classic;
MfClassicData* mf_classic_alloc();
MfClassicData* mf_classic_alloc(void);
void mf_classic_free(MfClassicData* data);
@@ -3,7 +3,7 @@
#include "mf_classic_listener.h"
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h>
#include <nfc/protocols/nfc_generic_event.h>
#include "crypto1.h"
#include <nfc/helpers/crypto1.h>
#ifdef __cplusplus
extern "C" {
@@ -315,6 +315,89 @@ MfClassicError mf_classic_poller_value_cmd(
*/
MfClassicError mf_classic_poller_value_transfer(MfClassicPoller* instance, uint8_t block_num);
/**
* @brief Transmit and receive Iso14443_3a standard frames in poller mode.
*
* Must ONLY be used inside the callback function.
*
* The rx_buffer will be filled with any data received as a response to data
* sent from tx_buffer, with a timeout defined by the fwt parameter.
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
* @param[in] fwt frame wait time (response timeout), in carrier cycles.
* @return MfClassicErrorNone on success, an error code on failure.
*/
MfClassicError mf_classic_poller_send_standard_frame(
MfClassicPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt_fc);
/**
* @brief Transmit and receive Iso14443_3a frames in poller mode.
*
* Must ONLY be used inside the callback function.
*
* The rx_buffer will be filled with any data received as a response to data
* sent from tx_buffer, with a timeout defined by the fwt parameter.
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
* @param[in] fwt frame wait time (response timeout), in carrier cycles.
* @return MfClassicErrorNone on success, an error code on failure.
*/
MfClassicError mf_classic_poller_send_frame(
MfClassicPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt_fc);
/**
* @brief Transmit and receive Iso14443_3a frames with custom parity bits in poller mode.
*
* Must ONLY be used inside the callback function.
*
* The rx_buffer will be filled with any data received as a response to data
* sent from tx_buffer, with a timeout defined by the fwt parameter.
*
* Custom parity bits must be set in the tx_buffer. The rx_buffer will contain
* the received data with the parity bits.
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
* @param[in] fwt frame wait time (response timeout), in carrier cycles.
* @return MfClassicErrorNone on success, an error code on failure.
*/
MfClassicError mf_classic_poller_send_custom_parity_frame(
MfClassicPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt_fc);
/**
* @brief Transmit and receive Mifare Classic encrypted frames with custom parity bits in poller mode.
*
* Must ONLY be used inside the callback function.
*
* The rx_buffer will be filled with any data received as a response to data
* sent from tx_buffer, with a timeout defined by the fwt parameter.
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] tx_buffer pointer to the buffer containing the plain data to be transmitted.
* @param[out] rx_buffer pointer to the buffer to be filled with decyphered received data.
* @param[in] fwt frame wait time (response timeout), in carrier cycles.
* @return MfClassicErrorNone on success, an error code on failure.
*/
MfClassicError mf_classic_poller_send_encrypted_frame(
MfClassicPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt_fc);
#ifdef __cplusplus
}
#endif
@@ -90,6 +90,8 @@ MfClassicError mf_classic_poller_get_nt(
uint8_t block_num,
MfClassicKeyType key_type,
MfClassicNt* nt) {
furi_check(instance);
return mf_classic_poller_get_nt_common(instance, block_num, key_type, nt, false);
}
@@ -98,6 +100,8 @@ MfClassicError mf_classic_poller_get_nt_nested(
uint8_t block_num,
MfClassicKeyType key_type,
MfClassicNt* nt) {
furi_check(instance);
return mf_classic_poller_get_nt_common(instance, block_num, key_type, nt, true);
}
@@ -179,6 +183,8 @@ MfClassicError mf_classic_poller_auth(
MfClassicKey* key,
MfClassicKeyType key_type,
MfClassicAuthContext* data) {
furi_check(instance);
furi_check(key);
return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, false);
}
@@ -188,10 +194,14 @@ MfClassicError mf_classic_poller_auth_nested(
MfClassicKey* key,
MfClassicKeyType key_type,
MfClassicAuthContext* data) {
furi_check(instance);
furi_check(key);
return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, true);
}
MfClassicError mf_classic_poller_halt(MfClassicPoller* instance) {
furi_check(instance);
MfClassicError ret = MfClassicErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -223,6 +233,9 @@ MfClassicError mf_classic_poller_read_block(
MfClassicPoller* instance,
uint8_t block_num,
MfClassicBlock* data) {
furi_check(instance);
furi_check(data);
MfClassicError ret = MfClassicErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -269,6 +282,9 @@ MfClassicError mf_classic_poller_write_block(
MfClassicPoller* instance,
uint8_t block_num,
MfClassicBlock* data) {
furi_check(instance);
furi_check(data);
MfClassicError ret = MfClassicErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -341,6 +357,8 @@ MfClassicError mf_classic_poller_value_cmd(
uint8_t block_num,
MfClassicValueCommand cmd,
int32_t data) {
furi_check(instance);
MfClassicError ret = MfClassicErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -407,6 +425,8 @@ MfClassicError mf_classic_poller_value_cmd(
}
MfClassicError mf_classic_poller_value_transfer(MfClassicPoller* instance, uint8_t block_num) {
furi_check(instance);
MfClassicError ret = MfClassicErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -445,3 +465,77 @@ MfClassicError mf_classic_poller_value_transfer(MfClassicPoller* instance, uint8
return ret;
}
MfClassicError mf_classic_poller_send_standard_frame(
MfClassicPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt_fc) {
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
instance->iso14443_3a_poller, tx_buffer, rx_buffer, fwt_fc);
return mf_classic_process_error(error);
}
MfClassicError mf_classic_poller_send_frame(
MfClassicPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt_fc) {
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
Iso14443_3aError error =
iso14443_3a_poller_txrx(instance->iso14443_3a_poller, tx_buffer, rx_buffer, fwt_fc);
return mf_classic_process_error(error);
}
MfClassicError mf_classic_poller_send_custom_parity_frame(
MfClassicPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt_fc) {
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
Iso14443_3aError error = iso14443_3a_poller_txrx_custom_parity(
instance->iso14443_3a_poller, tx_buffer, rx_buffer, fwt_fc);
return mf_classic_process_error(error);
}
MfClassicError mf_classic_poller_send_encrypted_frame(
MfClassicPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt_fc) {
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
MfClassicError ret = MfClassicErrorNone;
do {
crypto1_encrypt(instance->crypto, NULL, tx_buffer, instance->tx_encrypted_buffer);
Iso14443_3aError error = iso14443_3a_poller_txrx_custom_parity(
instance->iso14443_3a_poller,
instance->tx_encrypted_buffer,
instance->rx_encrypted_buffer,
fwt_fc);
if(error != Iso14443_3aErrorNone) {
ret = mf_classic_process_error(error);
break;
}
crypto1_decrypt(instance->crypto, instance->rx_encrypted_buffer, rx_buffer);
} while(false);
return ret;
}
@@ -3,7 +3,7 @@
#include "mf_classic_poller.h"
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h>
#include <bit_lib/bit_lib.h>
#include "crypto1.h"
#include <nfc/helpers/crypto1.h>
#ifdef __cplusplus
extern "C" {
@@ -225,7 +225,7 @@ MfClassicError mf_classic_poller_sync_collect_nt(
uint8_t block_num,
MfClassicKeyType key_type,
MfClassicNt* nt) {
furi_assert(nfc);
furi_check(nfc);
MfClassicPollerContext poller_context = {
.cmd_type = MfClassicPollerCmdTypeCollectNt,
@@ -250,8 +250,8 @@ MfClassicError mf_classic_poller_sync_auth(
MfClassicKey* key,
MfClassicKeyType key_type,
MfClassicAuthContext* data) {
furi_assert(nfc);
furi_assert(key);
furi_check(nfc);
furi_check(key);
MfClassicPollerContext poller_context = {
.cmd_type = MfClassicPollerCmdTypeAuth,
@@ -277,9 +277,9 @@ MfClassicError mf_classic_poller_sync_read_block(
MfClassicKey* key,
MfClassicKeyType key_type,
MfClassicBlock* data) {
furi_assert(nfc);
furi_assert(key);
furi_assert(data);
furi_check(nfc);
furi_check(key);
furi_check(data);
MfClassicPollerContext poller_context = {
.cmd_type = MfClassicPollerCmdTypeReadBlock,
@@ -303,9 +303,9 @@ MfClassicError mf_classic_poller_sync_write_block(
MfClassicKey* key,
MfClassicKeyType key_type,
MfClassicBlock* data) {
furi_assert(nfc);
furi_assert(key);
furi_assert(data);
furi_check(nfc);
furi_check(key);
furi_check(data);
MfClassicPollerContext poller_context = {
.cmd_type = MfClassicPollerCmdTypeWriteBlock,
@@ -326,9 +326,9 @@ MfClassicError mf_classic_poller_sync_read_value(
MfClassicKey* key,
MfClassicKeyType key_type,
int32_t* value) {
furi_assert(nfc);
furi_assert(key);
furi_assert(value);
furi_check(nfc);
furi_check(key);
furi_check(value);
MfClassicPollerContext poller_context = {
.cmd_type = MfClassicPollerCmdTypeReadValue,
@@ -353,9 +353,9 @@ MfClassicError mf_classic_poller_sync_change_value(
MfClassicKeyType key_type,
int32_t data,
int32_t* new_value) {
furi_assert(nfc);
furi_assert(key);
furi_assert(new_value);
furi_check(nfc);
furi_check(key);
furi_check(new_value);
MfClassicValueCommand command = MfClassicValueCommandRestore;
int32_t command_data = 0;
@@ -459,9 +459,9 @@ NfcCommand mf_classic_poller_read_callback(NfcGenericEvent event, void* context)
MfClassicError
mf_classic_poller_sync_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data) {
furi_assert(nfc);
furi_assert(keys);
furi_assert(data);
furi_check(nfc);
furi_check(keys);
furi_check(data);
MfClassicError error = MfClassicErrorNone;
MfClassicPollerContext poller_context = {};
@@ -493,8 +493,8 @@ MfClassicError
}
MfClassicError mf_classic_poller_sync_detect_type(Nfc* nfc, MfClassicType* type) {
furi_assert(nfc);
furi_assert(type);
furi_check(nfc);
furi_check(type);
MfClassicError error = MfClassicErrorNone;
+28 -13
View File
@@ -20,7 +20,7 @@ const NfcDeviceBase nfc_device_mf_desfire = {
.get_base_data = (NfcDeviceGetBaseData)mf_desfire_get_base_data,
};
MfDesfireData* mf_desfire_alloc() {
MfDesfireData* mf_desfire_alloc(void) {
MfDesfireData* data = malloc(sizeof(MfDesfireData));
data->iso14443_4a_data = iso14443_4a_alloc();
data->master_key_versions = simple_array_alloc(&mf_desfire_key_version_array_config);
@@ -31,7 +31,7 @@ MfDesfireData* mf_desfire_alloc() {
}
void mf_desfire_free(MfDesfireData* data) {
furi_assert(data);
furi_check(data);
mf_desfire_reset(data);
simple_array_free(data->applications);
@@ -42,7 +42,7 @@ void mf_desfire_free(MfDesfireData* data) {
}
void mf_desfire_reset(MfDesfireData* data) {
furi_assert(data);
furi_check(data);
iso14443_4a_reset(data->iso14443_4a_data);
@@ -55,8 +55,8 @@ void mf_desfire_reset(MfDesfireData* data) {
}
void mf_desfire_copy(MfDesfireData* data, const MfDesfireData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
mf_desfire_reset(data);
@@ -77,7 +77,8 @@ bool mf_desfire_verify(MfDesfireData* data, const FuriString* device_type) {
}
bool mf_desfire_load(MfDesfireData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
FuriString* prefix = furi_string_alloc();
@@ -143,7 +144,8 @@ bool mf_desfire_load(MfDesfireData* data, FlipperFormat* ff, uint32_t version) {
}
bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
FuriString* prefix = furi_string_alloc();
@@ -208,12 +210,15 @@ bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff) {
}
bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
return iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data) &&
memcmp(&data->version, &other->version, sizeof(MfDesfireVersion)) == 0 &&
memcmp(&data->free_memory, &other->free_memory, sizeof(MfDesfireFreeMemory)) == 0 &&
memcmp( //-V1103
&data->free_memory,
&other->free_memory,
sizeof(MfDesfireFreeMemory)) == 0 &&
memcmp(
&data->master_key_settings,
&other->master_key_settings,
@@ -230,25 +235,29 @@ const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcDeviceNameT
}
const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) {
furi_assert(data);
furi_check(data);
furi_check(uid_len);
return iso14443_4a_get_uid(data->iso14443_4a_data, uid_len);
}
bool mf_desfire_set_uid(MfDesfireData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
return iso14443_4a_set_uid(data->iso14443_4a_data, uid, uid_len);
}
Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data) {
furi_assert(data);
furi_check(data);
return data->iso14443_4a_data;
}
const MfDesfireApplication*
mf_desfire_get_application(const MfDesfireData* data, const MfDesfireApplicationId* app_id) {
furi_check(data);
furi_check(app_id);
MfDesfireApplication* app = NULL;
for(uint32_t i = 0; i < simple_array_get_count(data->application_ids); ++i) {
@@ -263,6 +272,9 @@ const MfDesfireApplication*
const MfDesfireFileSettings*
mf_desfire_get_file_settings(const MfDesfireApplication* data, const MfDesfireFileId* file_id) {
furi_check(data);
furi_check(file_id);
MfDesfireFileSettings* file_settings = NULL;
for(uint32_t i = 0; i < simple_array_get_count(data->file_ids); ++i) {
@@ -277,6 +289,9 @@ const MfDesfireFileSettings*
const MfDesfireFileData*
mf_desfire_get_file_data(const MfDesfireApplication* data, const MfDesfireFileId* file_id) {
furi_check(data);
furi_check(file_id);
MfDesfireFileData* file_data = NULL;
for(uint32_t i = 0; i < simple_array_get_count(data->file_ids); ++i) {
+4 -9
View File
@@ -21,8 +21,6 @@ extern "C" {
#define MF_DESFIRE_CMD_GET_VALUE (0x6C)
#define MF_DESFIRE_CMD_READ_RECORDS (0xBB)
#define MF_DESFIRE_FLAG_HAS_NEXT (0xAF)
#define MF_DESFIRE_MAX_KEYS (14)
#define MF_DESFIRE_MAX_FILES (32)
@@ -71,11 +69,6 @@ typedef struct {
typedef uint8_t MfDesfireKeyVersion;
typedef struct {
MfDesfireKeySettings key_settings;
SimpleArray* key_versions;
} MfDesfireKeyConfiguration;
typedef enum {
MfDesfireFileTypeStandard = 0,
MfDesfireFileTypeBackup = 1,
@@ -96,7 +89,8 @@ typedef uint16_t MfDesfireFileAccessRights;
typedef struct {
MfDesfireFileType type;
MfDesfireFileCommunicationSettings comm;
MfDesfireFileAccessRights access_rights;
MfDesfireFileAccessRights access_rights[MF_DESFIRE_MAX_KEYS];
uint8_t access_rights_len;
union {
struct {
uint32_t size;
@@ -136,6 +130,7 @@ typedef enum {
MfDesfireErrorNotPresent,
MfDesfireErrorProtocol,
MfDesfireErrorTimeout,
MfDesfireErrorAuthentication,
} MfDesfireError;
typedef struct {
@@ -152,7 +147,7 @@ extern const NfcDeviceBase nfc_device_mf_desfire;
// Virtual methods
MfDesfireData* mf_desfire_alloc();
MfDesfireData* mf_desfire_alloc(void);
void mf_desfire_free(MfDesfireData* data);
+91 -56
View File
@@ -1,5 +1,7 @@
#include "mf_desfire_i.h"
#define TAG "MfDesfire"
#define BITS_IN_BYTE (8U)
#define MF_DESFIRE_FFF_VERSION_KEY \
@@ -175,59 +177,88 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer
};
} MfDesfireFileSettingsLayout;
MfDesfireFileSettings file_settings_temp = {};
do {
const size_t data_size = bit_buffer_get_size_bytes(buf);
const uint8_t* data_ptr = bit_buffer_get_data(buf);
const size_t min_data_size =
sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsData);
const size_t max_data_size =
sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsValue);
if(data_size < min_data_size) break;
if(data_size <= max_data_size) {
MfDesfireFileSettingsLayout layout;
bit_buffer_write_bytes(buf, &layout, sizeof(MfDesfireFileSettingsLayout));
data->type = layout.header.type;
data->comm = layout.header.comm;
data->access_rights = layout.header.access_rights;
if(data->type == MfDesfireFileTypeStandard || data->type == MfDesfireFileTypeBackup) {
if(data_size != min_data_size) break;
data->data.size = layout.data.size;
} else if(data->type == MfDesfireFileTypeValue) {
if(data_size !=
sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsValue))
break;
data->value.lo_limit = layout.value.lo_limit;
data->value.hi_limit = layout.value.hi_limit;
data->value.limited_credit_value = layout.value.limited_credit_value;
data->value.limited_credit_enabled = layout.value.limited_credit_enabled;
} else if(
data->type == MfDesfireFileTypeLinearRecord ||
data->type == MfDesfireFileTypeCyclicRecord) {
if(data_size !=
sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsRecord))
break;
data->record.size = layout.record.size;
data->record.max = layout.record.max;
data->record.cur = layout.record.cur;
} else {
break;
}
} else {
// TODO FL-3750: process HID Desfire command response here
// Set default fields for now
data->type = 0;
data->comm = 0;
data->access_rights = 0;
data->data.size = 0;
if(data_size < min_data_size) {
FURI_LOG_E(
TAG, "File settings size %zu less than minimum %zu", data_size, min_data_size);
break;
}
size_t bytes_processed = sizeof(MfDesfireFileSettingsHeader);
MfDesfireFileSettingsLayout layout = {};
memcpy(&layout.header, data_ptr, sizeof(MfDesfireFileSettingsHeader));
bool has_additional_access_rights = (layout.header.comm & 0x80) != 0;
file_settings_temp.type = layout.header.type;
file_settings_temp.comm = layout.header.comm & 0x03;
file_settings_temp.access_rights_len = 1;
file_settings_temp.access_rights[0] = layout.header.access_rights;
if(file_settings_temp.type == MfDesfireFileTypeStandard ||
file_settings_temp.type == MfDesfireFileTypeBackup) {
memcpy(
&layout.data,
&data_ptr[sizeof(MfDesfireFileSettingsHeader)],
sizeof(MfDesfireFileSettingsData));
file_settings_temp.data.size = layout.data.size;
bytes_processed += sizeof(MfDesfireFileSettingsData);
} else if(file_settings_temp.type == MfDesfireFileTypeValue) {
memcpy(
&layout.value,
&data_ptr[sizeof(MfDesfireFileSettingsHeader)],
sizeof(MfDesfireFileSettingsValue));
file_settings_temp.value.lo_limit = layout.value.lo_limit;
file_settings_temp.value.hi_limit = layout.value.hi_limit;
file_settings_temp.value.limited_credit_value = layout.value.limited_credit_value;
file_settings_temp.value.limited_credit_enabled = layout.value.limited_credit_enabled;
bytes_processed += sizeof(MfDesfireFileSettingsValue);
} else if(
file_settings_temp.type == MfDesfireFileTypeLinearRecord ||
file_settings_temp.type == MfDesfireFileTypeCyclicRecord) {
memcpy(
&layout.record,
&data_ptr[sizeof(MfDesfireFileSettingsHeader)],
sizeof(MfDesfireFileSettingsRecord));
file_settings_temp.record.size = layout.record.size;
file_settings_temp.record.max = layout.record.max;
file_settings_temp.record.cur = layout.record.cur;
bytes_processed += sizeof(MfDesfireFileSettingsRecord);
} else {
FURI_LOG_W(TAG, "Unknown file type: %02x", file_settings_temp.type);
break;
}
if(has_additional_access_rights) {
uint8_t additional_access_rights_len = bit_buffer_get_byte(buf, bytes_processed);
FURI_LOG_D(TAG, "Has additional rights: %d", additional_access_rights_len);
if(data_size != bytes_processed +
additional_access_rights_len * sizeof(MfDesfireFileAccessRights) +
1) {
FURI_LOG_W(TAG, "Unexpected command length: %zu", data_size);
for(size_t i = 0; i < bit_buffer_get_size_bytes(buf); i++) {
printf("%02X ", bit_buffer_get_byte(buf, i));
}
printf("\r\n");
break;
}
if(additional_access_rights_len >
MF_DESFIRE_MAX_KEYS * sizeof(MfDesfireFileAccessRights))
break;
memcpy(
&file_settings_temp.access_rights[1],
&data_ptr[bytes_processed],
additional_access_rights_len * sizeof(MfDesfireFileAccessRights));
file_settings_temp.access_rights_len += additional_access_rights_len;
}
*data = file_settings_temp;
parsed = true;
} while(false);
@@ -392,18 +423,19 @@ bool mf_desfire_file_settings_load(
break;
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_ACCESS_RIGHTS_KEY);
if(!flipper_format_read_hex(
ff,
furi_string_get_cstr(key),
(uint8_t*)&data->access_rights,
sizeof(MfDesfireFileAccessRights)))
uint32_t access_rights_len = 0;
if(!flipper_format_get_value_count(ff, furi_string_get_cstr(key), &access_rights_len))
break;
if((access_rights_len == 0) || ((access_rights_len % 2) != 0)) break;
if(!flipper_format_read_hex(
ff, furi_string_get_cstr(key), (uint8_t*)&data->access_rights, access_rights_len))
break;
data->access_rights_len = access_rights_len / sizeof(MfDesfireFileAccessRights);
if(data->type == MfDesfireFileTypeStandard || data->type == MfDesfireFileTypeBackup) {
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_SIZE_KEY);
if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->data.size, 1))
break;
} else if(data->type == MfDesfireFileTypeValue) {
furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_HI_LIMIT_KEY);
if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->value.hi_limit, 1))
@@ -641,8 +673,8 @@ bool mf_desfire_file_settings_save(
if(!flipper_format_write_hex(
ff,
furi_string_get_cstr(key),
(const uint8_t*)&data->access_rights,
sizeof(MfDesfireFileAccessRights)))
(const uint8_t*)data->access_rights,
data->access_rights_len * sizeof(MfDesfireFileAccessRights)))
break;
if(data->type == MfDesfireFileTypeStandard || data->type == MfDesfireFileTypeBackup) {
@@ -737,8 +769,11 @@ bool mf_desfire_application_save(
if(i != key_version_count) break;
const uint32_t file_count = simple_array_get_count(data->file_ids);
if(!mf_desfire_file_ids_save(simple_array_get_data(data->file_ids), file_count, prefix, ff))
break;
if(file_count > 0) {
if(!mf_desfire_file_ids_save(
simple_array_get_data(data->file_ids), file_count, prefix, ff))
break;
}
for(i = 0; i < file_count; ++i) {
const MfDesfireFileId* file_id = simple_array_cget(data->file_ids, i);
@@ -5,6 +5,52 @@
#define MF_DESFIRE_FFF_PICC_PREFIX "PICC"
#define MF_DESFIRE_FFF_APP_PREFIX "Application"
// Successful operation
#define MF_DESFIRE_STATUS_OPERATION_OK (0x00)
// No changes done to backup files, CommitTransaction / AbortTransaction not necessary
#define MF_DESFIRE_STATUS_NO_CHANGES (0x0C)
// Insufficient NV-Memory to complete command
#define MF_DESFIRE_STATUS_OUT_OF_EEPROM_ERROR (0x0E)
// Command code not supported
#define MF_DESFIRE_STATUS_ILLEGAL_COMMAND_CODE (0x1C)
// CRC or MAC does not match data Padding bytes not valid
#define MF_DESFIRE_STATUS_INTEGRITY_ERROR (0x1E)
// Invalid key number specified
#define MF_DESFIRE_STATUS_NO_SUCH_KEY (0x40)
// Length of command string invalid
#define MF_DESFIRE_STATUS_LENGTH_ERROR (0x7E)
// Current configuration / status does not allow the requested command
#define MF_DESFIRE_STATUS_PERMISSION_DENIED (0x9D)
// Value of the parameter(s) invalid
#define MF_DESFIRE_STATUS_PARAMETER_ERROR (0x9E)
// Requested AID not present on PICC
#define MF_DESFIRE_STATUS_APPLICATION_NOT_FOUND (0xA0)
// Unrecoverable error within application, application will be disabled
#define MF_DESFIRE_STATUS_APPL_INTEGRITY_ERROR (0xA1)
// Current authentication status does not allow the requested command
#define MF_DESFIRE_STATUS_AUTHENTICATION_ERROR (0xAE)
// Additional data frame is expected to be sent
#define MF_DESFIRE_STATUS_ADDITIONAL_FRAME (0xAF)
// Attempt to read/write data from/to beyond the file's/record's limits
// Attempt to exceed the limits of a value file.
#define MF_DESFIRE_STATUS_BOUNDARY_ERROR (0xBE)
// Unrecoverable error within PICC, PICC will be disabled
#define MF_DESFIRE_STATUS_PICC_INTEGRITY_ERROR (0xC1)
// Previous Command was not fully completed. Not all Frames were requested or provided by the PCD
#define MF_DESFIRE_STATUS_COMMAND_ABORTED (0xCA)
// PICC was disabled by an unrecoverable error
#define MF_DESFIRE_STATUS_PICC_DISABLED_ERROR (0xCD)
// Number of Applications limited to 28, no additional CreateApplication possible
#define MF_DESFIRE_STATUS_COUNT_ERROR (0xCE)
// Creation of file/application failed because file/application with same number already exists
#define MF_DESFIRE_STATUS_DUBLICATE_ERROR (0xDE)
// Could not complete NV-write operation due to loss of power, internal backup/rollback mechanism activated
#define MF_DESFIRE_STATUS_EEPROM_ERROR (0xEE)
// Specified file number does not exist
#define MF_DESFIRE_STATUS_FILE_NOT_FOUND (0xF0)
// Unrecoverable error within file, file will be disabled
#define MF_DESFIRE_STATUS_FILE_INTEGRITY_ERROR (0xF1)
// SimpleArray configurations
extern const SimpleArrayConfig mf_desfire_key_version_array_config;
@@ -75,17 +75,23 @@ static NfcCommand mf_desfire_poller_handler_read_version(MfDesfirePoller* instan
}
static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* instance) {
NfcCommand command = NfcCommandContinue;
instance->error = mf_desfire_poller_read_free_memory(instance, &instance->data->free_memory);
if(instance->error == MfDesfireErrorNone) {
FURI_LOG_D(TAG, "Read free memory success");
instance->state = MfDesfirePollerStateReadMasterKeySettings;
} else if(instance->error == MfDesfireErrorNotPresent) {
FURI_LOG_D(TAG, "Read free memoty is unsupported");
instance->state = MfDesfirePollerStateReadMasterKeySettings;
command = NfcCommandReset;
} else {
FURI_LOG_E(TAG, "Failed to read free memory");
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
instance->state = MfDesfirePollerStateReadFailed;
}
return NfcCommandContinue;
return command;
}
static NfcCommand mf_desfire_poller_handler_read_master_key_settings(MfDesfirePoller* instance) {
@@ -94,6 +100,11 @@ static NfcCommand mf_desfire_poller_handler_read_master_key_settings(MfDesfirePo
if(instance->error == MfDesfireErrorNone) {
FURI_LOG_D(TAG, "Read master key settings success");
instance->state = MfDesfirePollerStateReadMasterKeyVersion;
} else if(instance->error == MfDesfireErrorAuthentication) {
FURI_LOG_D(TAG, "Auth is required to read master key settings and app ids");
instance->data->master_key_settings.is_free_directory_list = false;
instance->data->master_key_settings.max_keys = 1;
instance->state = MfDesfirePollerStateReadMasterKeyVersion;
} else {
FURI_LOG_E(TAG, "Failed to read master key settings");
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
@@ -110,7 +121,11 @@ static NfcCommand mf_desfire_poller_handler_read_master_key_version(MfDesfirePol
instance->data->master_key_settings.max_keys);
if(instance->error == MfDesfireErrorNone) {
FURI_LOG_D(TAG, "Read master key version success");
instance->state = MfDesfirePollerStateReadApplicationIds;
if(instance->data->master_key_settings.is_free_directory_list) {
instance->state = MfDesfirePollerStateReadApplicationIds;
} else {
instance->state = MfDesfirePollerStateReadSuccess;
}
} else {
FURI_LOG_E(TAG, "Failed to read master key version");
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
@@ -126,6 +141,9 @@ static NfcCommand mf_desfire_poller_handler_read_application_ids(MfDesfirePoller
if(instance->error == MfDesfireErrorNone) {
FURI_LOG_D(TAG, "Read application ids success");
instance->state = MfDesfirePollerStateReadApplications;
} else if(instance->error == MfDesfireErrorAuthentication) {
FURI_LOG_D(TAG, "Read application ids impossible without authentication");
instance->state = MfDesfirePollerStateReadSuccess;
} else {
FURI_LOG_E(TAG, "Failed to read application ids");
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
@@ -225,9 +243,17 @@ static bool mf_desfire_poller_detect(NfcGenericEvent event, void* context) {
bool protocol_detected = false;
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
MfDesfireVersion version = {};
const MfDesfireError error = mf_desfire_poller_read_version(instance, &version);
protocol_detected = (error == MfDesfireErrorNone);
do {
MfDesfireKeyVersion key_version = 0;
MfDesfireError error = mf_desfire_poller_read_key_version(instance, 0, &key_version);
if(error != MfDesfireErrorNone) break;
MfDesfireVersion version = {};
error = mf_desfire_poller_read_version(instance, &version);
if(error != MfDesfireErrorNone) break;
protocol_detected = true;
} while(false);
}
return protocol_detected;
@@ -91,6 +91,21 @@ MfDesfireError
MfDesfireError
mf_desfire_poller_read_key_settings(MfDesfirePoller* instance, MfDesfireKeySettings* data);
/**
* @brief Read key version on MfDesfire card.
*
* Must ONLY be used inside the callback function.
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[out] key_num key number.
* @param[in] data pointer to the MfDesfireKeyVersion structure to be filled with key version data.
* @return MfDesfireErrorNone on success, an error code on failure.
*/
MfDesfireError mf_desfire_poller_read_key_version(
MfDesfirePoller* instance,
uint8_t key_num,
MfDesfireKeyVersion* data);
/**
* @brief Read key versions on MfDesfire card.
*
@@ -19,16 +19,27 @@ MfDesfireError mf_desfire_process_error(Iso14443_4aError error) {
}
}
MfDesfireError mf_desfire_process_status_code(uint8_t status_code) {
switch(status_code) {
case MF_DESFIRE_STATUS_OPERATION_OK:
return MfDesfireErrorNone;
case MF_DESFIRE_STATUS_AUTHENTICATION_ERROR:
return MfDesfireErrorAuthentication;
default:
return MfDesfireErrorProtocol;
}
}
MfDesfireError mf_desfire_send_chunks(
MfDesfirePoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer) {
furi_assert(instance);
furi_assert(instance->iso14443_4a_poller);
furi_assert(instance->tx_buffer);
furi_assert(instance->rx_buffer);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
furi_check(instance);
furi_check(instance->iso14443_4a_poller);
furi_check(instance->tx_buffer);
furi_check(instance->rx_buffer);
furi_check(tx_buffer);
furi_check(rx_buffer);
MfDesfireError error = MfDesfireErrorNone;
@@ -42,7 +53,7 @@ MfDesfireError mf_desfire_send_chunks(
}
bit_buffer_reset(instance->tx_buffer);
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_FLAG_HAS_NEXT);
bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_STATUS_ADDITIONAL_FRAME);
if(bit_buffer_get_size_bytes(instance->rx_buffer) > sizeof(uint8_t)) {
bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t));
@@ -50,7 +61,8 @@ MfDesfireError mf_desfire_send_chunks(
bit_buffer_reset(rx_buffer);
}
while(bit_buffer_starts_with_byte(instance->rx_buffer, MF_DESFIRE_FLAG_HAS_NEXT)) {
while(
bit_buffer_starts_with_byte(instance->rx_buffer, MF_DESFIRE_STATUS_ADDITIONAL_FRAME)) {
Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block(
instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer);
@@ -71,11 +83,16 @@ MfDesfireError mf_desfire_send_chunks(
}
} while(false);
if(error == MfDesfireErrorNone) {
uint8_t err_code = bit_buffer_get_byte(instance->rx_buffer, 0);
error = mf_desfire_process_status_code(err_code);
}
return error;
}
MfDesfireError mf_desfire_poller_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) {
furi_assert(instance);
furi_check(instance);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_VERSION);
@@ -97,7 +114,7 @@ MfDesfireError mf_desfire_poller_read_version(MfDesfirePoller* instance, MfDesfi
MfDesfireError
mf_desfire_poller_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data) {
furi_assert(instance);
furi_check(instance);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_FREE_MEMORY);
@@ -110,7 +127,7 @@ MfDesfireError
if(error != MfDesfireErrorNone) break;
if(!mf_desfire_free_memory_parse(data, instance->result_buffer)) {
error = MfDesfireErrorProtocol;
error = MfDesfireErrorNotPresent;
}
} while(false);
@@ -119,7 +136,7 @@ MfDesfireError
MfDesfireError
mf_desfire_poller_read_key_settings(MfDesfirePoller* instance, MfDesfireKeySettings* data) {
furi_assert(instance);
furi_check(instance);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_KEY_SETTINGS);
@@ -139,31 +156,42 @@ MfDesfireError
return error;
}
MfDesfireError mf_desfire_poller_read_key_version(
MfDesfirePoller* instance,
uint8_t key_num,
MfDesfireKeyVersion* data) {
furi_check(instance);
furi_check(data);
bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t) * 2);
bit_buffer_set_byte(instance->input_buffer, 0, MF_DESFIRE_CMD_GET_KEY_VERSION);
bit_buffer_set_byte(instance->input_buffer, 1, key_num);
MfDesfireError error =
mf_desfire_send_chunks(instance, instance->input_buffer, instance->result_buffer);
if(error == MfDesfireErrorNone) {
if(!mf_desfire_key_version_parse(data, instance->result_buffer)) {
error = MfDesfireErrorProtocol;
}
}
return error;
}
MfDesfireError mf_desfire_poller_read_key_versions(
MfDesfirePoller* instance,
SimpleArray* data,
uint32_t count) {
furi_assert(instance);
furi_assert(count > 0);
furi_check(instance);
furi_check(count > 0);
simple_array_init(data, count);
bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t) * 2);
bit_buffer_set_byte(instance->input_buffer, 0, MF_DESFIRE_CMD_GET_KEY_VERSION);
MfDesfireError error = MfDesfireErrorNone;
for(uint32_t i = 0; i < count; ++i) {
bit_buffer_set_byte(instance->input_buffer, 1, i);
error = mf_desfire_send_chunks(instance, instance->input_buffer, instance->result_buffer);
error = mf_desfire_poller_read_key_version(instance, i, simple_array_get(data, i));
if(error != MfDesfireErrorNone) break;
if(!mf_desfire_key_version_parse(simple_array_get(data, i), instance->result_buffer)) {
error = MfDesfireErrorProtocol;
break;
}
}
return error;
@@ -171,7 +199,8 @@ MfDesfireError mf_desfire_poller_read_key_versions(
MfDesfireError
mf_desfire_poller_read_application_ids(MfDesfirePoller* instance, SimpleArray* data) {
furi_assert(instance);
furi_check(instance);
furi_check(data);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_APPLICATION_IDS);
@@ -204,7 +233,7 @@ MfDesfireError
MfDesfireError mf_desfire_poller_select_application(
MfDesfirePoller* instance,
const MfDesfireApplicationId* id) {
furi_assert(instance);
furi_check(instance);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_SELECT_APPLICATION);
@@ -218,7 +247,8 @@ MfDesfireError mf_desfire_poller_select_application(
}
MfDesfireError mf_desfire_poller_read_file_ids(MfDesfirePoller* instance, SimpleArray* data) {
furi_assert(instance);
furi_check(instance);
furi_check(data);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_FILE_IDS);
@@ -251,7 +281,8 @@ MfDesfireError mf_desfire_poller_read_file_settings(
MfDesfirePoller* instance,
MfDesfireFileId id,
MfDesfireFileSettings* data) {
furi_assert(instance);
furi_check(instance);
furi_check(data);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_FILE_SETTINGS);
@@ -276,7 +307,9 @@ MfDesfireError mf_desfire_poller_read_file_settings_multi(
MfDesfirePoller* instance,
const SimpleArray* file_ids,
SimpleArray* data) {
furi_assert(instance);
furi_check(instance);
furi_check(file_ids);
furi_check(data);
MfDesfireError error = MfDesfireErrorNone;
@@ -300,7 +333,8 @@ MfDesfireError mf_desfire_poller_read_file_data(
uint32_t offset,
size_t size,
MfDesfireFileData* data) {
furi_assert(instance);
furi_check(instance);
furi_check(data);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_READ_DATA);
@@ -327,7 +361,8 @@ MfDesfireError mf_desfire_poller_read_file_value(
MfDesfirePoller* instance,
MfDesfireFileId id,
MfDesfireFileData* data) {
furi_assert(instance);
furi_check(instance);
furi_check(data);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_VALUE);
@@ -354,7 +389,8 @@ MfDesfireError mf_desfire_poller_read_file_records(
uint32_t offset,
size_t size,
MfDesfireFileData* data) {
furi_assert(instance);
furi_check(instance);
furi_check(data);
bit_buffer_reset(instance->input_buffer);
bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_READ_RECORDS);
@@ -382,8 +418,11 @@ MfDesfireError mf_desfire_poller_read_file_data_multi(
const SimpleArray* file_ids,
const SimpleArray* file_settings,
SimpleArray* data) {
furi_assert(instance);
furi_assert(simple_array_get_count(file_ids) == simple_array_get_count(file_settings));
furi_check(instance);
furi_check(file_ids);
furi_check(file_settings);
furi_check(data);
furi_check(simple_array_get_count(file_ids) == simple_array_get_count(file_settings));
MfDesfireError error = MfDesfireErrorNone;
@@ -392,13 +431,25 @@ MfDesfireError mf_desfire_poller_read_file_data_multi(
simple_array_init(data, file_id_count);
}
for(uint32_t i = 0; i < file_id_count; ++i) {
for(size_t i = 0; i < file_id_count; ++i) {
const MfDesfireFileId file_id = *(const MfDesfireFileId*)simple_array_cget(file_ids, i);
const MfDesfireFileSettings* file_settings_cur = simple_array_cget(file_settings, i);
const MfDesfireFileType file_type = file_settings_cur->type;
MfDesfireFileData* file_data = simple_array_get(data, i);
bool can_read_data = false;
for(size_t j = 0; j < file_settings_cur->access_rights_len; j++) {
uint8_t read_access = (file_settings_cur->access_rights[j] >> 12) & 0x0f;
uint8_t read_write_access = (file_settings_cur->access_rights[j] >> 4) & 0x0f;
can_read_data = (read_access == 0x0e) || (read_write_access == 0x0e);
if(can_read_data) break;
}
if(!can_read_data) {
FURI_LOG_D(TAG, "Can't read file %zu data without authentication", i);
continue;
}
if(file_type == MfDesfireFileTypeStandard || file_type == MfDesfireFileTypeBackup) {
error = mf_desfire_poller_read_file_data(
instance, file_id, 0, file_settings_cur->data.size, file_data);
@@ -410,8 +461,6 @@ MfDesfireError mf_desfire_poller_read_file_data_multi(
error = mf_desfire_poller_read_file_records(
instance, file_id, 0, file_settings_cur->data.size, file_data);
}
if(error != MfDesfireErrorNone) break;
}
return error;
@@ -419,29 +468,43 @@ MfDesfireError mf_desfire_poller_read_file_data_multi(
MfDesfireError
mf_desfire_poller_read_application(MfDesfirePoller* instance, MfDesfireApplication* data) {
furi_assert(instance);
furi_assert(data);
furi_check(instance);
furi_check(data);
MfDesfireError error;
do {
error = mf_desfire_poller_read_key_settings(instance, &data->key_settings);
if(error == MfDesfireErrorAuthentication) {
FURI_LOG_D(TAG, "Auth is required to read master key settings and app ids");
data->key_settings.is_free_directory_list = false;
error = MfDesfireErrorNone;
break;
}
if(error != MfDesfireErrorNone) break;
error = mf_desfire_poller_read_key_versions(
instance, data->key_versions, data->key_settings.max_keys);
if(error != MfDesfireErrorNone) break;
if(error != MfDesfireErrorNone) {
FURI_LOG_E(TAG, "Failed to read key version: %d", error);
break;
}
error = mf_desfire_poller_read_file_ids(instance, data->file_ids);
if(error != MfDesfireErrorNone) break;
if(error != MfDesfireErrorNone) {
FURI_LOG_E(TAG, "Failed to read file ids: %d", error);
break;
}
error = mf_desfire_poller_read_file_settings_multi(
instance, data->file_ids, data->file_settings);
if(error != MfDesfireErrorNone) break;
if(error != MfDesfireErrorNone) {
FURI_LOG_E(TAG, "Failed to read file settings: %d", error);
break;
}
error = mf_desfire_poller_read_file_data_multi(
instance, data->file_ids, data->file_settings, data->file_data);
if(error != MfDesfireErrorNone) break;
} while(false);
@@ -452,7 +515,8 @@ MfDesfireError mf_desfire_poller_read_applications(
MfDesfirePoller* instance,
const SimpleArray* app_ids,
SimpleArray* data) {
furi_assert(instance);
furi_check(instance);
furi_check(data);
MfDesfireError error = MfDesfireErrorNone;
@@ -461,11 +525,13 @@ MfDesfireError mf_desfire_poller_read_applications(
simple_array_init(data, app_id_count);
}
for(uint32_t i = 0; i < app_id_count; ++i) {
for(size_t i = 0; i < app_id_count; ++i) {
do {
FURI_LOG_D(TAG, "Selecting app %zu", i);
error = mf_desfire_poller_select_application(instance, simple_array_cget(app_ids, i));
if(error != MfDesfireErrorNone) break;
FURI_LOG_D(TAG, "Reading app %zu", i);
MfDesfireApplication* current_app = simple_array_get(data, i);
error = mf_desfire_poller_read_application(instance, current_app);
@@ -47,6 +47,8 @@ struct MfDesfirePoller {
MfDesfireError mf_desfire_process_error(Iso14443_4aError error);
MfDesfireError mf_desfire_process_status_code(uint8_t status_code);
const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance);
#ifdef __cplusplus
+33 -19
View File
@@ -168,28 +168,28 @@ const NfcDeviceBase nfc_device_mf_ultralight = {
.get_base_data = (NfcDeviceGetBaseData)mf_ultralight_get_base_data,
};
MfUltralightData* mf_ultralight_alloc() {
MfUltralightData* mf_ultralight_alloc(void) {
MfUltralightData* data = malloc(sizeof(MfUltralightData));
data->iso14443_3a_data = iso14443_3a_alloc();
return data;
}
void mf_ultralight_free(MfUltralightData* data) {
furi_assert(data);
furi_check(data);
iso14443_3a_free(data->iso14443_3a_data);
free(data);
}
void mf_ultralight_reset(MfUltralightData* data) {
furi_assert(data);
furi_check(data);
iso14443_3a_reset(data->iso14443_3a_data);
}
void mf_ultralight_copy(MfUltralightData* data, const MfUltralightData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data);
for(size_t i = 0; i < COUNT_OF(data->counter); i++) {
@@ -222,7 +222,8 @@ static const char*
}
bool mf_ultralight_verify(MfUltralightData* data, const FuriString* device_type) {
furi_assert(data);
furi_check(data);
furi_check(device_type);
bool verified = false;
@@ -239,7 +240,8 @@ bool mf_ultralight_verify(MfUltralightData* data, const FuriString* device_type)
}
bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
FuriString* temp_str = furi_string_alloc();
bool parsed = false;
@@ -338,7 +340,8 @@ bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t vers
}
bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
FuriString* temp_str = furi_string_alloc();
bool saved = false;
@@ -419,6 +422,9 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff) {
}
bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData* other) {
furi_check(data);
furi_check(other);
bool is_equal = false;
bool data_array_is_equal = true;
@@ -467,20 +473,20 @@ bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData
const char*
mf_ultralight_get_device_name(const MfUltralightData* data, NfcDeviceNameType name_type) {
furi_assert(data);
furi_assert(data->type < MfUltralightTypeNum);
furi_check(data);
furi_check(data->type < MfUltralightTypeNum);
return mf_ultralight_get_device_name_by_type(data->type, name_type);
}
const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len) {
furi_assert(data);
furi_check(data);
return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len);
}
bool mf_ultralight_set_uid(MfUltralightData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
bool uid_valid = iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len);
@@ -498,13 +504,13 @@ bool mf_ultralight_set_uid(MfUltralightData* data, const uint8_t* uid, size_t ui
}
Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data) {
furi_assert(data);
furi_check(data);
return data->iso14443_3a_data;
}
MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) {
furi_assert(version);
furi_check(version);
MfUltralightType type = MfUltralightTypeUnknown;
@@ -538,15 +544,19 @@ MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version)
}
uint16_t mf_ultralight_get_pages_total(MfUltralightType type) {
furi_check(type < MfUltralightTypeNum);
return mf_ultralight_features[type].total_pages;
}
uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type) {
furi_check(type < MfUltralightTypeNum);
return mf_ultralight_features[type].feature_set;
}
bool mf_ultralight_detect_protocol(const Iso14443_3aData* iso14443_3a_data) {
furi_assert(iso14443_3a_data);
furi_check(iso14443_3a_data);
bool mfu_detected = (iso14443_3a_data->atqa[0] == 0x44) &&
(iso14443_3a_data->atqa[1] == 0x00) && (iso14443_3a_data->sak == 0x00);
@@ -555,10 +565,14 @@ bool mf_ultralight_detect_protocol(const Iso14443_3aData* iso14443_3a_data) {
}
uint16_t mf_ultralight_get_config_page_num(MfUltralightType type) {
furi_check(type < MfUltralightTypeNum);
return mf_ultralight_features[type].config_page;
}
uint8_t mf_ultralight_get_pwd_page_num(MfUltralightType type) {
furi_check(type < MfUltralightTypeNum);
uint8_t config_page = mf_ultralight_features[type].config_page;
return (config_page != 0) ? config_page + 2 : 0;
}
@@ -574,8 +588,8 @@ bool mf_ultralight_support_feature(const uint32_t feature_set, const uint32_t fe
}
bool mf_ultralight_get_config_page(const MfUltralightData* data, MfUltralightConfigPages** config) {
furi_assert(data);
furi_assert(config);
furi_check(data);
furi_check(config);
bool config_pages_found = false;
@@ -589,7 +603,7 @@ bool mf_ultralight_get_config_page(const MfUltralightData* data, MfUltralightCon
}
bool mf_ultralight_is_all_data_read(const MfUltralightData* data) {
furi_assert(data);
furi_check(data);
bool all_read = false;
if(data->pages_read == data->pages_total ||
@@ -616,7 +630,7 @@ bool mf_ultralight_is_all_data_read(const MfUltralightData* data) {
}
bool mf_ultralight_is_counter_configured(const MfUltralightData* data) {
furi_assert(data);
furi_check(data);
MfUltralightConfigPages* config = NULL;
bool configured = false;
@@ -177,7 +177,7 @@ typedef struct {
extern const NfcDeviceBase nfc_device_mf_ultralight;
MfUltralightData* mf_ultralight_alloc();
MfUltralightData* mf_ultralight_alloc(void);
void mf_ultralight_free(MfUltralightData* data);
@@ -33,6 +33,9 @@ MfUltralightError mf_ultralight_process_error(Iso14443_3aError error) {
MfUltralightError mf_ultralight_poller_auth_pwd(
MfUltralightPoller* instance,
MfUltralightPollerAuthContext* data) {
furi_check(instance);
furi_check(data);
uint8_t auth_cmd[5] = {MF_ULTRALIGHT_CMD_PWD_AUTH}; //-V1009
memccpy(&auth_cmd[1], data->password.data, 0, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE);
bit_buffer_copy_bytes(instance->tx_buffer, auth_cmd, sizeof(auth_cmd));
@@ -60,6 +63,8 @@ MfUltralightError mf_ultralight_poller_auth_pwd(
}
MfUltralightError mf_ultralight_poller_authenticate(MfUltralightPoller* instance) {
furi_check(instance);
uint8_t auth_cmd[2] = {MF_ULTRALIGHT_CMD_AUTH, 0x00};
bit_buffer_copy_bytes(instance->tx_buffer, auth_cmd, sizeof(auth_cmd));
@@ -91,6 +96,9 @@ MfUltralightError mf_ultralight_poller_read_page_from_sector(
uint8_t sector,
uint8_t tag,
MfUltralightPageReadCommandData* data) {
furi_check(instance);
furi_check(data);
MfUltralightError ret = MfUltralightErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -132,6 +140,9 @@ MfUltralightError mf_ultralight_poller_read_page(
MfUltralightPoller* instance,
uint8_t start_page,
MfUltralightPageReadCommandData* data) {
furi_check(instance);
furi_check(data);
MfUltralightError ret = MfUltralightErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -162,6 +173,9 @@ MfUltralightError mf_ultralight_poller_write_page(
MfUltralightPoller* instance,
uint8_t page,
const MfUltralightPage* data) {
furi_check(instance);
furi_check(data);
MfUltralightError ret = MfUltralightErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -193,6 +207,9 @@ MfUltralightError mf_ultralight_poller_write_page(
MfUltralightError
mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data) {
furi_check(instance);
furi_check(data);
MfUltralightError ret = MfUltralightErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -222,6 +239,9 @@ MfUltralightError
MfUltralightError
mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data) {
furi_check(instance);
furi_check(data);
MfUltralightError ret = MfUltralightErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -251,6 +271,9 @@ MfUltralightError mf_ultralight_poller_read_counter(
MfUltralightPoller* instance,
uint8_t counter_num,
MfUltralightCounter* data) {
furi_check(instance);
furi_check(data);
MfUltralightError ret = MfUltralightErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -280,6 +303,9 @@ MfUltralightError mf_ultralight_poller_read_tearing_flag(
MfUltralightPoller* instance,
uint8_t tearing_falg_num,
MfUltralightTearingFlag* data) {
furi_check(instance);
furi_check(data);
MfUltralightError ret = MfUltralightErrorNone;
Iso14443_3aError error = Iso14443_3aErrorNone;
@@ -119,8 +119,8 @@ static MfUltralightError
MfUltralightError
mf_ultralight_poller_sync_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) {
furi_assert(nfc);
furi_assert(data);
furi_check(nfc);
furi_check(data);
MfUltralightPollerContext poller_context = {
.cmd_type = MfUltralightPollerCmdTypeReadPage,
@@ -138,8 +138,8 @@ MfUltralightError
MfUltralightError
mf_ultralight_poller_sync_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) {
furi_assert(nfc);
furi_assert(data);
furi_check(nfc);
furi_check(data);
MfUltralightPollerContext poller_context = {
.cmd_type = MfUltralightPollerCmdTypeWritePage,
@@ -156,8 +156,8 @@ MfUltralightError
}
MfUltralightError mf_ultralight_poller_sync_read_version(Nfc* nfc, MfUltralightVersion* data) {
furi_assert(nfc);
furi_assert(data);
furi_check(nfc);
furi_check(data);
MfUltralightPollerContext poller_context = {
.cmd_type = MfUltralightPollerCmdTypeReadVersion,
@@ -173,8 +173,8 @@ MfUltralightError mf_ultralight_poller_sync_read_version(Nfc* nfc, MfUltralightV
}
MfUltralightError mf_ultralight_poller_sync_read_signature(Nfc* nfc, MfUltralightSignature* data) {
furi_assert(nfc);
furi_assert(data);
furi_check(nfc);
furi_check(data);
MfUltralightPollerContext poller_context = {
.cmd_type = MfUltralightPollerCmdTypeReadSignature,
@@ -193,8 +193,8 @@ MfUltralightError mf_ultralight_poller_sync_read_counter(
Nfc* nfc,
uint8_t counter_num,
MfUltralightCounter* data) {
furi_assert(nfc);
furi_assert(data);
furi_check(nfc);
furi_check(data);
MfUltralightPollerContext poller_context = {
.cmd_type = MfUltralightPollerCmdTypeReadCounter,
@@ -214,8 +214,8 @@ MfUltralightError mf_ultralight_poller_sync_read_tearing_flag(
Nfc* nfc,
uint8_t flag_num,
MfUltralightTearingFlag* data) {
furi_assert(nfc);
furi_assert(data);
furi_check(nfc);
furi_check(data);
MfUltralightPollerContext poller_context = {
.cmd_type = MfUltralightPollerCmdTypeReadTearingFlag,
@@ -261,8 +261,8 @@ static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void
}
MfUltralightError mf_ultralight_poller_sync_read_card(Nfc* nfc, MfUltralightData* data) {
furi_assert(nfc);
furi_assert(data);
furi_check(nfc);
furi_check(data);
MfUltralightPollerContext poller_context = {};
poller_context.thread_id = furi_thread_get_current_id();
+1 -1
View File
@@ -20,7 +20,7 @@ extern "C" {
*
* @returns pointer to the allocated instance.
*/
typedef NfcDeviceData* (*NfcDeviceAlloc)();
typedef NfcDeviceData* (*NfcDeviceAlloc)(void);
/**
* @brief Delete the protocol-specific NFC device data instance.
+3 -3
View File
@@ -157,14 +157,14 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = {
};
NfcProtocol nfc_protocol_get_parent(NfcProtocol protocol) {
furi_assert(protocol < NfcProtocolNum);
furi_check(protocol < NfcProtocolNum);
return nfc_protocol_nodes[protocol].parent_protocol;
}
bool nfc_protocol_has_parent(NfcProtocol protocol, NfcProtocol parent_protocol) {
furi_assert(protocol < NfcProtocolNum);
furi_assert(parent_protocol < NfcProtocolNum);
furi_check(protocol < NfcProtocolNum);
furi_check(parent_protocol < NfcProtocolNum);
bool parent_found = false;
const NfcProtocolTreeNode* iter = &nfc_protocol_nodes[protocol];
+30 -21
View File
@@ -78,8 +78,8 @@ typedef struct {
static const SlixPasswordConfig slix_password_configs[] = {
[SlixPasswordTypeRead] = {SLIX_PASSWORD_READ_KEY, SLIX_TYPE_FEATURE_READ, 0x00000000U},
[SlixPasswordTypeWrite] = {SLIX_PASSWORD_WRITE_KEY, SLIX_TYPE_FEATURE_WRITE, 0x00000000U},
[SlixPasswordTypePrivacy] = {SLIX_PASSWORD_PRIVACY_KEY, SLIX_TYPE_FEATURE_PRIVACY, 0xFFFFFFFFU},
[SlixPasswordTypeDestroy] = {SLIX_PASSWORD_DESTROY_KEY, SLIX_TYPE_FEATURE_DESTROY, 0xFFFFFFFFU},
[SlixPasswordTypePrivacy] = {SLIX_PASSWORD_PRIVACY_KEY, SLIX_TYPE_FEATURE_PRIVACY, 0x0F0F0F0FU},
[SlixPasswordTypeDestroy] = {SLIX_PASSWORD_DESTROY_KEY, SLIX_TYPE_FEATURE_DESTROY, 0x0F0F0F0FU},
[SlixPasswordTypeEasAfi] = {SLIX_PASSWORD_EAS_KEY, SLIX_TYPE_FEATURE_EAS, 0x00000000U},
};
@@ -89,7 +89,7 @@ static void slix_password_set_defaults(SlixPassword* passwords) {
}
}
SlixData* slix_alloc() {
SlixData* slix_alloc(void) {
SlixData* data = malloc(sizeof(SlixData));
data->iso15693_3_data = iso15693_3_alloc();
@@ -99,7 +99,7 @@ SlixData* slix_alloc() {
}
void slix_free(SlixData* data) {
furi_assert(data);
furi_check(data);
iso15693_3_free(data->iso15693_3_data);
@@ -107,7 +107,7 @@ void slix_free(SlixData* data) {
}
void slix_reset(SlixData* data) {
furi_assert(data);
furi_check(data);
iso15693_3_reset(data->iso15693_3_data);
slix_password_set_defaults(data->passwords);
@@ -119,8 +119,8 @@ void slix_reset(SlixData* data) {
}
void slix_copy(SlixData* data, const SlixData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
iso15693_3_copy(data->iso15693_3_data, other->iso15693_3_data);
@@ -160,7 +160,8 @@ static bool slix_load_passwords(SlixPassword* passwords, SlixType slix_type, Fli
}
bool slix_load(SlixData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool loaded = false;
@@ -238,7 +239,8 @@ static bool
}
bool slix_save(const SlixData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool saved = false;
@@ -303,6 +305,9 @@ bool slix_save(const SlixData* data, FlipperFormat* ff) {
}
bool slix_is_equal(const SlixData* data, const SlixData* other) {
furi_check(data);
furi_check(other);
return iso15693_3_is_equal(data->iso15693_3_data, other->iso15693_3_data) &&
memcmp(&data->system_info, &other->system_info, sizeof(SlixSystemInfo)) == 0 &&
memcmp(
@@ -313,6 +318,7 @@ bool slix_is_equal(const SlixData* data, const SlixData* other) {
}
const char* slix_get_device_name(const SlixData* data, NfcDeviceNameType name_type) {
furi_check(data);
UNUSED(name_type);
const SlixType slix_type = slix_get_type(data);
@@ -322,22 +328,25 @@ const char* slix_get_device_name(const SlixData* data, NfcDeviceNameType name_ty
}
const uint8_t* slix_get_uid(const SlixData* data, size_t* uid_len) {
furi_check(data);
return iso15693_3_get_uid(data->iso15693_3_data, uid_len);
}
bool slix_set_uid(SlixData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
return iso15693_3_set_uid(data->iso15693_3_data, uid, uid_len);
}
const Iso15693_3Data* slix_get_base_data(const SlixData* data) {
furi_assert(data);
furi_check(data);
return data->iso15693_3_data;
}
SlixType slix_get_type(const SlixData* data) {
furi_check(data);
SlixType type = SlixTypeUnknown;
do {
@@ -364,14 +373,14 @@ SlixType slix_get_type(const SlixData* data) {
}
SlixPassword slix_get_password(const SlixData* data, SlixPasswordType password_type) {
furi_assert(data);
furi_assert(password_type < SlixPasswordTypeCount);
furi_check(data);
furi_check(password_type < SlixPasswordTypeCount);
return data->passwords[password_type];
}
uint16_t slix_get_counter(const SlixData* data) {
furi_assert(data);
furi_check(data);
const SlixCounter* counter = (const SlixCounter*)iso15693_3_get_block_data(
data->iso15693_3_data, SLIX_COUNTER_BLOCK_NUM);
@@ -379,7 +388,7 @@ uint16_t slix_get_counter(const SlixData* data) {
}
bool slix_is_privacy_mode(const SlixData* data) {
furi_assert(data);
furi_check(data);
return data->privacy;
}
@@ -388,8 +397,8 @@ bool slix_is_block_protected(
const SlixData* data,
SlixPasswordType password_type,
uint8_t block_num) {
furi_assert(data);
furi_assert(password_type < SlixPasswordTypeCount);
furi_check(data);
furi_check(password_type < SlixPasswordTypeCount);
bool ret = false;
@@ -411,7 +420,7 @@ bool slix_is_block_protected(
}
bool slix_is_counter_increment_protected(const SlixData* data) {
furi_assert(data);
furi_check(data);
const SlixCounter* counter = (const SlixCounter*)iso15693_3_get_block_data(
data->iso15693_3_data, SLIX_COUNTER_BLOCK_NUM);
@@ -420,14 +429,14 @@ bool slix_is_counter_increment_protected(const SlixData* data) {
}
bool slix_type_has_features(SlixType slix_type, SlixTypeFeatures features) {
furi_assert(slix_type < SlixTypeCount);
furi_check(slix_type < SlixTypeCount);
return (slix_type_features[slix_type] & features) == features;
}
bool slix_type_supports_password(SlixType slix_type, SlixPasswordType password_type) {
furi_assert(slix_type < SlixTypeCount);
furi_assert(password_type < SlixPasswordTypeCount);
furi_check(slix_type < SlixTypeCount);
furi_check(password_type < SlixPasswordTypeCount);
return slix_type_features[slix_type] & slix_password_configs[password_type].feature_flag;
}
+1 -1
View File
@@ -99,7 +99,7 @@ typedef struct {
SlixPrivacy privacy;
} SlixData;
SlixData* slix_alloc();
SlixData* slix_alloc(void);
void slix_free(SlixData* data);
+49 -2
View File
@@ -73,17 +73,62 @@ static NfcCommand slix_poller_handler_read_signature(SlixPoller* instance) {
if(slix_type_has_features(instance->type, SLIX_TYPE_FEATURE_SIGNATURE)) {
instance->error = slix_poller_read_signature(instance, &instance->data->signature);
if(instance->error == SlixErrorNone) {
instance->poller_state = SlixPollerStateReady;
instance->poller_state = SlixPollerStateCheckPrivacyPassword;
} else {
instance->poller_state = SlixPollerStateError;
}
} else {
instance->poller_state = SlixPollerStateReady;
instance->poller_state = SlixPollerStateCheckPrivacyPassword;
}
return NfcCommandContinue;
}
static NfcCommand slix_poller_handler_check_privacy_password(SlixPoller* instance) {
NfcCommand command = NfcCommandContinue;
do {
if(!slix_type_has_features(instance->type, SLIX_TYPE_FEATURE_PRIVACY)) {
instance->poller_state = SlixPollerStateReady;
break;
}
if(instance->privacy_password_checked) {
instance->poller_state = SlixPollerStateReady;
break;
}
instance->slix_event.type = SlixPollerEventTypePrivacyUnlockRequest;
command = instance->callback(instance->general_event, instance->context);
if(!instance->slix_event_data.privacy_password.password_set) {
instance->poller_state = SlixPollerStateReady;
break;
}
SlixPassword pwd = instance->slix_event_data.privacy_password.password;
FURI_LOG_I(TAG, "Trying to check privacy password: %08lX", pwd);
instance->error = slix_poller_get_random_number(instance, &instance->random_number);
if(instance->error != SlixErrorNone) {
instance->poller_state = SlixPollerStateReady;
break;
}
instance->error = slix_poller_set_password(instance, SlixPasswordTypePrivacy, pwd);
if(instance->error != SlixErrorNone) {
command = NfcCommandReset;
break;
}
FURI_LOG_I(TAG, "Found privacy password");
instance->data->passwords[SlixPasswordTypePrivacy] = pwd;
instance->privacy_password_checked = true;
instance->poller_state = SlixPollerStateReady;
} while(false);
return command;
}
static NfcCommand slix_poller_handler_privacy_unlock(SlixPoller* instance) {
NfcCommand command = NfcCommandContinue;
instance->poller_state = SlixPollerStateError;
@@ -108,6 +153,7 @@ static NfcCommand slix_poller_handler_privacy_unlock(SlixPoller* instance) {
FURI_LOG_I(TAG, "Privacy mode disabled");
instance->data->passwords[SlixPasswordTypePrivacy] = pwd;
instance->privacy_password_checked = true;
instance->poller_state = SlixPollerStateIdle;
slix_unlocked = true;
} while(false);
@@ -140,6 +186,7 @@ static const SlixPollerStateHandler slix_poller_state_handler[SlixPollerStateNum
[SlixPollerStateError] = slix_poller_handler_error,
[SlixPollerStateGetNxpSysInfo] = slix_poller_handler_get_nfc_system_info,
[SlixPollerStateReadSignature] = slix_poller_handler_read_signature,
[SlixPollerStateCheckPrivacyPassword] = slix_poller_handler_check_privacy_password,
[SlixPollerStatePrivacyUnlock] = slix_poller_handler_privacy_unlock,
[SlixPollerStateReady] = slix_poller_handler_ready,
};
+2
View File
@@ -14,6 +14,7 @@ typedef enum {
SlixPollerStateIdle,
SlixPollerStateGetNxpSysInfo,
SlixPollerStateReadSignature,
SlixPollerStateCheckPrivacyPassword,
SlixPollerStatePrivacyUnlock,
SlixPollerStateReady,
SlixPollerStateError,
@@ -27,6 +28,7 @@ struct SlixPoller {
SlixPollerState poller_state;
SlixError error;
SlixRandomNumber random_number;
bool privacy_password_checked;
BitBuffer* tx_buffer;
BitBuffer* rx_buffer;
+23 -13
View File
@@ -79,35 +79,39 @@ const NfcDeviceBase nfc_device_st25tb = {
.get_base_data = (NfcDeviceGetBaseData)st25tb_get_base_data,
};
St25tbData* st25tb_alloc() {
St25tbData* st25tb_alloc(void) {
St25tbData* data = malloc(sizeof(St25tbData));
return data;
}
void st25tb_free(St25tbData* data) {
furi_assert(data);
furi_check(data);
free(data);
}
void st25tb_reset(St25tbData* data) {
furi_check(data);
memset(data, 0, sizeof(St25tbData));
}
void st25tb_copy(St25tbData* data, const St25tbData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
*data = *other;
}
bool st25tb_verify(St25tbData* data, const FuriString* device_type) {
furi_check(device_type);
UNUSED(data);
return furi_string_equal_str(device_type, ST25TB_PROTOCOL_NAME);
}
bool st25tb_load(St25tbData* data, FlipperFormat* ff, uint32_t version) {
furi_assert(data);
furi_check(data);
furi_check(ff);
bool parsed = false;
@@ -150,7 +154,8 @@ bool st25tb_load(St25tbData* data, FlipperFormat* ff, uint32_t version) {
}
bool st25tb_save(const St25tbData* data, FlipperFormat* ff) {
furi_assert(data);
furi_check(data);
furi_check(ff);
FuriString* temp_str = furi_string_alloc();
bool saved = false;
@@ -184,19 +189,21 @@ bool st25tb_save(const St25tbData* data, FlipperFormat* ff) {
}
bool st25tb_is_equal(const St25tbData* data, const St25tbData* other) {
furi_assert(data);
furi_assert(other);
furi_check(data);
furi_check(other);
return memcmp(data, other, sizeof(St25tbData)) == 0;
return memcmp(data, other, sizeof(St25tbData)) == 0; //-V1103
}
uint8_t st25tb_get_block_count(St25tbType type) {
furi_check(type < St25tbTypeNum);
return st25tb_features[type].blocks_total;
}
const char* st25tb_get_device_name(const St25tbData* data, NfcDeviceNameType name_type) {
furi_assert(data);
furi_assert(data->type < St25tbTypeNum);
furi_check(data);
furi_check(data->type < St25tbTypeNum);
if(name_type == NfcDeviceNameTypeFull) {
return st25tb_features[data->type].full_name;
@@ -206,7 +213,7 @@ const char* st25tb_get_device_name(const St25tbData* data, NfcDeviceNameType nam
}
const uint8_t* st25tb_get_uid(const St25tbData* data, size_t* uid_len) {
furi_assert(data);
furi_check(data);
if(uid_len) {
*uid_len = ST25TB_UID_SIZE;
@@ -216,7 +223,8 @@ const uint8_t* st25tb_get_uid(const St25tbData* data, size_t* uid_len) {
}
bool st25tb_set_uid(St25tbData* data, const uint8_t* uid, size_t uid_len) {
furi_assert(data);
furi_check(data);
furi_check(uid);
const bool uid_valid = uid_len == ST25TB_UID_SIZE;
@@ -233,6 +241,8 @@ St25tbData* st25tb_get_base_data(const St25tbData* data) {
}
St25tbType st25tb_get_type_from_uid(const uint8_t* uid) {
furi_check(uid);
switch(uid[2] >> 2) {
case 0x0:
case 0x3:
+1 -1
View File
@@ -48,7 +48,7 @@ typedef struct {
extern const NfcDeviceBase nfc_device_st25tb;
St25tbData* st25tb_alloc();
St25tbData* st25tb_alloc(void);
void st25tb_free(St25tbData* data);
+18 -15
View File
@@ -20,7 +20,9 @@ St25tbError st25tb_poller_send_frame(
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
furi_assert(instance);
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
const size_t tx_bytes = bit_buffer_get_size_bytes(tx_buffer);
furi_assert(
@@ -54,8 +56,8 @@ St25tbError st25tb_poller_send_frame(
St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id_ptr) {
// Send Initiate()
furi_assert(instance);
furi_assert(instance->nfc);
furi_check(instance);
furi_check(instance->nfc);
bit_buffer_reset(instance->tx_buffer);
bit_buffer_reset(instance->rx_buffer);
@@ -86,8 +88,8 @@ St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id_ptr)
}
St25tbError st25tb_poller_select(St25tbPoller* instance, uint8_t* chip_id_ptr) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_check(instance);
furi_check(instance->nfc);
St25tbError ret;
@@ -169,8 +171,9 @@ St25tbError st25tb_poller_read(St25tbPoller* instance, St25tbData* data) {
}
St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_check(instance);
furi_check(instance->nfc);
furi_check(uid);
St25tbError ret;
@@ -213,10 +216,10 @@ St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) {
St25tbError
st25tb_poller_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_assert(block);
furi_assert(
furi_check(instance);
furi_check(instance->nfc);
furi_check(block);
furi_check(
(block_number <= st25tb_get_block_count(instance->data->type)) ||
block_number == ST25TB_SYSTEM_OTP_BLOCK);
FURI_LOG_T(TAG, "reading block %d", block_number);
@@ -248,9 +251,9 @@ St25tbError
St25tbError
st25tb_poller_write_block(St25tbPoller* instance, uint32_t block, uint8_t block_number) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_assert(
furi_check(instance);
furi_check(instance->nfc);
furi_check(
(block_number <= st25tb_get_block_count(instance->data->type)) ||
block_number == ST25TB_SYSTEM_OTP_BLOCK);
FURI_LOG_T(TAG, "writing block %d", block_number);
@@ -292,7 +295,7 @@ St25tbError
}
St25tbError st25tb_poller_halt(St25tbPoller* instance) {
furi_assert(instance);
furi_check(instance);
bit_buffer_reset(instance->tx_buffer);
bit_buffer_reset(instance->rx_buffer);
@@ -109,7 +109,8 @@ static St25tbError st25tb_poller_cmd_execute(Nfc* nfc, St25tbPollerSyncContext*
}
St25tbError st25tb_poller_sync_read_block(Nfc* nfc, uint8_t block_num, uint32_t* block) {
furi_assert(block);
furi_check(nfc);
furi_check(block);
St25tbPollerSyncContext poller_context = {
.cmd_type = St25tbPollerCmdTypeReadBlock,
.cmd_data =
@@ -125,6 +126,7 @@ St25tbError st25tb_poller_sync_read_block(Nfc* nfc, uint8_t block_num, uint32_t*
}
St25tbError st25tb_poller_sync_write_block(Nfc* nfc, uint8_t block_num, uint32_t block) {
furi_check(nfc);
St25tbPollerSyncContext poller_context = {
.cmd_type = St25tbPollerCmdTypeWriteBlock,
.cmd_data =
@@ -140,7 +142,8 @@ St25tbError st25tb_poller_sync_write_block(Nfc* nfc, uint8_t block_num, uint32_t
}
St25tbError st25tb_poller_sync_detect_type(Nfc* nfc, St25tbType* type) {
furi_assert(type);
furi_check(nfc);
furi_check(type);
St25tbPollerSyncContext poller_context = {
.cmd_type = St25tbPollerCmdTypeDetectType,
.cmd_data =
@@ -185,8 +188,8 @@ static NfcCommand nfc_scene_read_poller_callback_st25tb(NfcGenericEvent event, v
}
St25tbError st25tb_poller_sync_read(Nfc* nfc, St25tbData* data) {
furi_assert(nfc);
furi_assert(data);
furi_check(nfc);
furi_check(data);
St25tbPollerSyncContext poller_context = {
.thread_id = furi_thread_get_current_id(),