1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 04:34:43 +04:00
Files
unleashed-firmware/lib/nfc/protocols/felica/felica.h
RebornedBrain eea53491de [FL-3569] NFC CLI commands (#4158)
* feat: FuriThread stdin

* ci: fix f18

* feat: stdio callback context

* feat: FuriPipe

* POTENTIALLY EXPLOSIVE pipe welding

* fix: non-explosive welding

* Revert welding

* docs: furi_pipe

* feat: pipe event loop integration

* update f18 sdk

* f18

* docs: make doxygen happy

* fix: event loop not triggering when pipe attached to stdio

* fix: partial stdout in pipe

* allow simultaneous in and out subscription in event loop

* feat: vcp i/o

* feat: cli ansi stuffs and history

* feat: more line editing

* working but slow cli rewrite

* restore previous speed after 4 days of debugging 🥲

* fix: cli_app_should_stop

* fix: cli and event_loop memory leaks

* style: remove commented out code

* ci: fix pvs warnings

* fix: unit tests, event_loop crash

* ci: fix build

* ci: silence pvs warning

* feat: cli gpio

* ci: fix formatting

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* feat: cli completions

* Merge remote-tracking branch 'origin/dev' into portasynthinca3/3928-cli-threads

* merge fixups

* temporarily exclude speaker_debug app

* pvs and unit tests fixups

* feat: commands in fals

* move commands out of flash, code cleanup

* ci: fix errors

* fix: run commands in buffer when stopping session

* speedup cli file transfer

* fix f18

* separate cli_shell into modules

* fix pvs warning

* fix qflipper refusing to connect

* remove temp debug logs

* remove erroneous conclusion

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* unit test for the fix

* improve thread stdio callback signatures

* pipe stdout timeout

* update api symbols

* fix f18, formatting

* fix pvs warnings

* increase stack size, hope to fix unit tests

* cli completions

* more key combos

* commands in fals

* move commands out of flash

* ci: fix errors

* speedup cli file transfer

* merge fixups

* fix f18

* cli: revert flag changes

* cli: fix formatting

* cli, fbt: loopback perf benchmark

* thread, event_loop: subscribing to thread flags

* cli: signal internal events using thread flags, improve performance

* fix f18, formatting

* event_loop: fix crash

* storage_cli: increase write_chunk buffer size again

* cli: explanation for order=0

* thread, event_loop: thread flags callback refactor

* cli: increase stack size

* cli: rename cli_app_should_stop -> cli_is_pipe_broken_or_is_etx_next_char

* cli: use plain array instead of mlib for history

* cli: prepend file name to static fns

* cli: fix formatting

* cli_shell: increase stack size

* Now cli_shell can be customized with another motd and another command set

* Added custom motd callback definition

* Now user can alloc and free his own cli command set

* cli_vcp can now restart shell with another command set

* Help command modified to show available commands from different command sets

* Api adjustement

* Reworked nfc_cli to start new shell with another command set

* Revert custom shell changes from vcp

* Custom motd callback moved to cli_shell

* Cli Shell now can be started from ongoing cli command

* Help command moved to a separate function so it can be used for custom shell

* Now nfc command spawns separate shell for further nfc commands

* cli_shell: give up pipe to command thread

* fix formatting

* cli_shell: separate into toolbox

* speaker_debug: fix

* fix: format

* Merge branch 'portasynthinca3/3928-3929-cli-fals-threads' into portasynthinca3/3965-cli_shell-toolbox

* fix merge

* fix. merge.

* fix formatting

* fix: cmd flags

* fix: formatting

* Added basic command descriptor structs and macros

* Basic nfc commands definitions added

* Nfc cli commands collection and functions added

* Raw skeleton of nfc cli processor added

* cli: increase default stack depth

* New callbacks for ctx alloc / free added

* nfc_cli moved to cli folder

* Some more logic for command processor

* Scanner command no works via command_processor

* plugin manifest adj

* Argument descriptors were removed, now only keys left

* Some helper command function implemented

* Command processor logic now mostly works

* Added all parsers and dummy implementation of raw cmd

* Now processor checks duplicated keys and treat them as errors

* Some renamings

* Arguments processing moved to separate function

* Now command processor can reuse context of previuos command for the next one if it's allowed

* can_reuse callback added for checking if context can be reused

* command processor is now freed on nfc cli exit

* Some cleanups

* First working version of raw command

* Now input data are placed directly to bit buffer

* Added tag

* Introduced request/response structs

* Moved raw command to a separate folder

* Moved some common types to header

* Added protocol specific handlers for iso14a and felica

* Opened felica crc header for referencing

* Added handler for iso14443_3b

* Opened iso15693_3_poller for referencing

* Added iso15693_3 handler for raw command

* NfcCliRawError enum introduced for response result

* Refactored handlers implementation

* Formatting functions now added as helpers

* New printing result logic

* Not present error value added to enum

* Timeout added to raw command

* Command processor now supports multivalue keys

* Apdu command implementation added

* NfcScanner moved to helpers and command now uses it

* Helper now can format protocol names

* Dump command added

* Added some more functions to scanner helper

* Dump main logic simplified

* Dump handlers moved to protocols folder

* Protocol parser added to simplify searching protocol by name

* Protocol and key arguments added to dump command

* Cleanups

* Apdu now parses protocol using helper parser

* Raw now parses protocol using helper parser

* Wrong naming fix

* Emulate command added to cli

* Description added to action descriptor and command macros

* Description field added to all commands

* Removed unnecessary enum for commands

* Added functions for formatting command and action info

* Proper error messages and help added

* Fix for unsupported single action command

* Function renamed to more appropriate

* Field command moved to all other commands

* Cleanups

* Nfc commands modified with new cli shell

* Removed previous nfc_cli.c after merge

* Removed nfc_cli.h header

* Some renamings and cleanups

* Some comments and instructions added

* Some comments and instructions added

* TODOs removed

* Fix for missing parse callback

* Added not implemented dummy for mfu actions, for now

* Fix name mismatch

* Remove unneeded header

* Mfu command moved to separate folder, also raw info action logic added

* Dictionary with id/vendors added to assets. It is used by nfc_cli_mfu_info_get_vendor function

* One more unneeded header removed

* Moved mfu info action to a separate file

* Info action now uses sync mfu poller

* mfu rdbl action added

* wrbl action added for mfu command

* Some formatting for rdbl command

* Function for formatting mfu errors added

* All mfu actions now show errors in the same way

* Fix error with sync poller. Previously when read failed function returned ErrorNone, now it processes iso14a error to get proper value

* Make PVS happy

* Nfc cli now doesn't start if desktop app is running

* Make action description look more common

* Scanner now has -t key and can show detected protocol hierarchies

* Apdu now checks max input payload data

* Proper format

* Proper error handling added to dump command

* Timeout key added dump command

* Fix merge issue

* formatting

* Pragma pack replaced with FURI_PACKED

* Fix felica memory leak

---------

Co-authored-by: Anna Antonenko <portasynthinca3@gmail.com>
Co-authored-by: Georgii Surkov <georgii.surkov@outlook.com>
Co-authored-by: あく <alleteam@gmail.com>
Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: hedger <hedger@nanode.su>
2025-09-29 14:34:49 +04:00

260 lines
7.2 KiB
C

#pragma once
#include <toolbox/bit_buffer.h>
#include <nfc/protocols/nfc_device_base_i.h>
#include <mbedtls/include/mbedtls/des.h>
#ifdef __cplusplus
extern "C" {
#endif
#define FELICA_IDM_SIZE (8U)
#define FELICA_PMM_SIZE (8U)
#define FELICA_DATA_BLOCK_SIZE (16U)
#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)
#define FELICA_BLOCKS_TOTAL_COUNT (28U)
#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)
#define FELICA_POLL_POLL_MIN_US (1280U)
#define FELICA_FDT_LISTEN_FC (0)
#define FELICA_SYSTEM_CODE_CODE (0xFFFFU)
#define FELICA_TIME_SLOT_1 (0x00U)
#define FELICA_TIME_SLOT_2 (0x01U)
#define FELICA_TIME_SLOT_4 (0x03U)
#define FELICA_TIME_SLOT_8 (0x07U)
#define FELICA_TIME_SLOT_16 (0x0FU)
/** @brief Type of possible Felica errors */
typedef enum {
FelicaErrorNone,
FelicaErrorNotPresent,
FelicaErrorColResFailed,
FelicaErrorBufferOverflow,
FelicaErrorCommunication,
FelicaErrorFieldOff,
FelicaErrorWrongCrc,
FelicaErrorProtocol,
FelicaErrorTimeout,
FelicaErrorFeatureUnsupported,
} FelicaError;
typedef struct {
uint8_t data[FELICA_DATA_BLOCK_SIZE];
} FelicaBlockData;
/** @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 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 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;
typedef struct FURI_PACKED {
uint8_t code;
FelicaIDm idm;
uint8_t service_num;
uint16_t service_code;
uint8_t block_count;
} FelicaCommandHeader;
typedef struct {
uint8_t length;
uint8_t response_code;
FelicaIDm idm;
uint8_t SF1;
uint8_t SF2;
} FelicaCommandResponseHeader;
typedef struct {
uint8_t service_code : 4;
uint8_t access_mode : 3;
uint8_t length : 1;
uint8_t block_number;
} FelicaBlockListElement;
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 {
FelicaCommandResponseHeader header;
uint8_t block_count;
uint8_t data[];
} FelicaListenerReadCommandResponse;
typedef FelicaCommandResponseHeader FelicaListenerWriteCommandResponse;
typedef FelicaCommandResponseHeader FelicaPollerWriteCommandResponse;
extern const NfcDeviceBase nfc_device_felica;
FelicaData* felica_alloc(void);
void felica_free(FelicaData* data);
void felica_reset(FelicaData* data);
void felica_copy(FelicaData* data, const FelicaData* other);
bool felica_verify(FelicaData* data, const FuriString* device_type);
bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version);
bool felica_save(const FelicaData* data, FlipperFormat* ff);
bool felica_is_equal(const FelicaData* data, const FelicaData* other);
const char* felica_get_device_name(const FelicaData* data, NfcDeviceNameType name_type);
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);
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_read(
mbedtls_des3_context* ctx,
const uint8_t* session_key,
const uint8_t* rc,
const uint8_t* blocks,
const uint8_t block_count,
const uint8_t* data,
uint8_t* mac);
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