cogs-mykey-public/nfc_srix.c

153 lines
4.8 KiB
C

#include "cogs_mikai.h"
#include <furi.h>
#include <machine/endian.h>
#include <nfc/nfc.h>
#include <nfc/protocols/st25tb/st25tb.h>
#include <nfc/protocols/st25tb/st25tb_poller_sync.h>
bool mykey_read_from_nfc(COGSMyKaiApp* app) {
FURI_LOG_I(TAG, "Reading SRIX4K from NFC...");
bool success = false;
Nfc* nfc = nfc_alloc();
// Detect ST25TB card type
St25tbType type;
St25tbError error = st25tb_poller_sync_detect_type(nfc, &type);
if(error != St25tbErrorNone) {
FURI_LOG_E(TAG, "Failed to detect ST25TB card: %d", error);
nfc_free(nfc);
return false;
}
// Check if it's SRIX4K (ST25TBX512 or ST25TB04K or ST25TBX4K)
if(type != St25tbTypeX512 && type != St25tbType04k && type != St25tbTypeX4k) {
FURI_LOG_E(TAG, "Card is not SRIX4K compatible, type: %d", type);
nfc_free(nfc);
return false;
}
FURI_LOG_I(TAG, "Detected ST25TB card type: %d", type);
// Allocate ST25TB data structure
St25tbData* st25tb_data = st25tb_alloc();
// Read entire card
error = st25tb_poller_sync_read(nfc, st25tb_data);
if(error != St25tbErrorNone) {
FURI_LOG_E(TAG, "Failed to read ST25TB card: %d", error);
st25tb_free(st25tb_data);
nfc_free(nfc);
return false;
}
// Extract UID (8 bytes for ST25TB)
// ST25TB UID bytes are in order [0..7], we need to assemble them big-endian
// to match libmikai: uid[0] is MSB (bits 56-63), uid[7] is LSB (bits 0-7)
app->mykey.uid = 0;
for(size_t i = 0; i < ST25TB_UID_SIZE && i < 8; i++) {
app->mykey.uid |= ((uint64_t)st25tb_data->uid[i]) << ((7 - i) * 8);
}
FURI_LOG_I(TAG, "Card UID (big-endian): %016llX", app->mykey.uid);
FURI_LOG_I(TAG, "UID bytes: %02X %02X %02X %02X %02X %02X %02X %02X",
st25tb_data->uid[0], st25tb_data->uid[1], st25tb_data->uid[2], st25tb_data->uid[3],
st25tb_data->uid[4], st25tb_data->uid[5], st25tb_data->uid[6], st25tb_data->uid[7]);
// Copy blocks to MyKey data structure
// ST25TB stores data in blocks, we need to read all 128 blocks (512 bytes total)
size_t num_blocks = st25tb_get_block_count(type);
if(num_blocks > SRIX4K_BLOCKS) {
num_blocks = SRIX4K_BLOCKS;
}
// ST25TB blocks need byte-swapping to match libmikai's big-endian format
// Flipper SDK stores blocks in little-endian, libmikai expects big-endian
for(size_t i = 0; i < num_blocks; i++) {
app->mykey.eeprom[i] = __bswap32(st25tb_data->blocks[i]);
}
FURI_LOG_I(TAG, "Blocks byte-swapped to big-endian format");
// Calculate encryption key from UID
mykey_calculate_encryption_key(&app->mykey);
// Update cached values
app->mykey.is_loaded = true;
app->mykey.is_modified = false; // Fresh read from card
app->mykey.is_reset = mykey_is_reset(&app->mykey);
app->mykey.current_credit = mykey_get_current_credit(&app->mykey);
FURI_LOG_I(TAG, "Card loaded successfully. Credit: %d cents, Reset: %s",
app->mykey.current_credit,
app->mykey.is_reset ? "Yes" : "No");
success = true;
st25tb_free(st25tb_data);
nfc_free(nfc);
return success;
}
bool mykey_write_to_nfc(COGSMyKaiApp* app) {
FURI_LOG_I(TAG, "Writing to SRIX4K via NFC...");
if(!app->mykey.is_loaded) {
FURI_LOG_E(TAG, "No card data loaded, cannot write");
return false;
}
bool success = true;
Nfc* nfc = nfc_alloc();
// Detect ST25TB card type
St25tbType type;
St25tbError error = st25tb_poller_sync_detect_type(nfc, &type);
if(error != St25tbErrorNone) {
FURI_LOG_E(TAG, "Failed to detect ST25TB card: %d", error);
nfc_free(nfc);
return false;
}
// Check if it's SRIX4K
if(type != St25tbTypeX512 && type != St25tbType04k && type != St25tbTypeX4k) {
FURI_LOG_E(TAG, "Card is not SRIX4K compatible, type: %d", type);
nfc_free(nfc);
return false;
}
size_t num_blocks = st25tb_get_block_count(type);
if(num_blocks > SRIX4K_BLOCKS) {
num_blocks = SRIX4K_BLOCKS;
}
// Write each block
// Note: Block 0 (UID) is typically read-only, so we skip it
for(size_t i = 1; i < num_blocks; i++) {
// Byte-swap block back to little-endian for ST25TB card
// Our internal format is big-endian, ST25TB expects little-endian
uint32_t block_to_write = __bswap32(app->mykey.eeprom[i]);
error = st25tb_poller_sync_write_block(nfc, i, block_to_write);
if(error != St25tbErrorNone) {
FURI_LOG_E(TAG, "Failed to write block %zu: %d", i, error);
success = false;
// Continue trying to write remaining blocks
}
}
if(success) {
FURI_LOG_I(TAG, "Card written successfully");
} else {
FURI_LOG_W(TAG, "Card write completed with errors");
}
nfc_free(nfc);
return success;
}