[FL-3772] Felica poller (#3570)

* New types for felica poller
* New functions for felica data transmissions
* Felica memory map extended with new fields
* Init/deinit of mbedtls context added for felica encryption
* Functions for session key and mac calculations added
* Raw felica_poller implementation added
* Removed MAC type parameter from check_mac function
* Replaced all data fields needed for auth with context structure
* Clean up felica_poller.c
* Now RC block is filled with random numbers
* New parameter for counting well-read blocks
* Some cleanups
* Felica file save and load logic added
* Now we use card key from context for session key calculation
* Copying card key to card block from auth context when both authentications succeeded, otherwise decrement blocks count by 1
* New felica poller event added
* Moved some data structions to public namespace
* FelicaAuthenticationContext struct moved to felica.h
* Field type and name changed for better ones
* Helper functions for felica_auth added to the app
* New scene for felica card key input added
* Logic for felica key input added
* Auth context request processing added
* Added block index definitions and replaced all index numbers with them
* More macro defines
* Replace nesting with do while block
* New function for write operations mac calculation added
* Replace nesting with do while block
* Make functions static for now because they are used internally
* Wrote some comments
* Raw felica render implementation
* New felica scenes
* Adjusted felica dump rendering according design requirements
* New felica scene added
* Helper for switching scene during unlock added
* Added warning scene and transfer to it
* Moved unlock scene logic to separate files
* Magic number changed
* New felica render logic
* Felica scenes adjusted according to design requirements
* Felica poller cleanups
* Some asserts added and some fixed
* Replcaed asserts to checks in public api
* Fixed pvs warnings in felica_poller
* New event for felica_poller added for incomplete read actions
* Handling of new poller event added
* Update SConscript with felica files
* Update api_symbols.csv with felica functions
* Sync API versions

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
RebornedBrain
2024-04-10 12:51:36 +03:00
committed by GitHub
parent db14ca964b
commit fb9728d570
22 changed files with 1186 additions and 85 deletions

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 {