mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-29 02:08:10 -07:00
Merge branch 'nfcf' of https://github.com/nullableVoidPtr/flipperzero-firmware into xfw-dev
This commit is contained in:
+229
-27
@@ -20,6 +20,7 @@ static const uint32_t nfc_keys_file_version = 1;
|
||||
// Protocols format versions
|
||||
static const uint32_t nfc_mifare_classic_data_format_version = 2;
|
||||
static const uint32_t nfc_mifare_ultralight_data_format_version = 1;
|
||||
static const uint32_t nfc_felica_data_format_version = 1;
|
||||
|
||||
NfcDevice* nfc_device_alloc() {
|
||||
NfcDevice* nfc_dev = malloc(sizeof(NfcDevice));
|
||||
@@ -60,6 +61,8 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, FuriString* format_
|
||||
furi_string_set(format_string, "Mifare DESFire");
|
||||
} else if(dev->format == NfcDeviceSaveFormatNfcV) {
|
||||
furi_string_set(format_string, "ISO15693");
|
||||
} else if(dev->format == NfcDeviceSaveFormatFelica) {
|
||||
furi_string_set(format_string, "FeliCa");
|
||||
} else {
|
||||
furi_string_set(format_string, "Unknown");
|
||||
}
|
||||
@@ -1114,6 +1117,201 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice*
|
||||
return saved;
|
||||
}
|
||||
|
||||
static bool nfc_device_save_felica_lite(FlipperFormat* file, FelicaLiteInfo* info) {
|
||||
bool saved = false;
|
||||
FuriString* key = furi_string_alloc();
|
||||
|
||||
do {
|
||||
flipper_format_write_comment_cstr(file, "Lite(-S) System");
|
||||
flipper_format_write_hex(
|
||||
file, "Data Format Code", info->data_format_code, sizeof(uint16_t));
|
||||
flipper_format_write_hex(file, "ID Arbitrary Value", info->ID_value, 6);
|
||||
flipper_format_write_hex(file, "Memory Config", info->memory_config, FELICA_BLOCK_SIZE);
|
||||
|
||||
for(uint8_t block_num = 0; block_num < 14; block_num++) {
|
||||
FuriString* spad_str = furi_string_alloc();
|
||||
for(size_t i = 0; i < FELICA_BLOCK_SIZE; i++) {
|
||||
if(info->S_PAD[block_num] != NULL) {
|
||||
furi_string_cat_printf(spad_str, "%02X ", info->S_PAD[block_num][i]);
|
||||
} else {
|
||||
furi_string_cat_printf(spad_str, "?? ");
|
||||
}
|
||||
}
|
||||
|
||||
furi_string_printf(key, "S_PAD%d", block_num);
|
||||
flipper_format_write_string(file, furi_string_get_cstr(key), spad_str);
|
||||
}
|
||||
|
||||
FuriString* reg_str = furi_string_alloc();
|
||||
for(size_t i = 0; i < FELICA_BLOCK_SIZE; i++) {
|
||||
if(info->REG != NULL) {
|
||||
furi_string_cat_printf(reg_str, "%02X ", info->REG[i]);
|
||||
} else {
|
||||
furi_string_cat_printf(reg_str, "?? ");
|
||||
}
|
||||
}
|
||||
flipper_format_write_string(file, "REG", reg_str);
|
||||
|
||||
flipper_format_write_hex(
|
||||
file, "Card Key Version", &info->card_key_version, sizeof(uint16_t));
|
||||
FuriString* ck1_str = furi_string_alloc();
|
||||
for(size_t i = 0; i < FELICA_BLOCK_SIZE; i++) {
|
||||
if(info->REG != NULL) {
|
||||
furi_string_cat_printf(ck1_str, "%02X ", info->card_key_1[i]);
|
||||
} else {
|
||||
furi_string_cat_printf(ck1_str, "?? ");
|
||||
}
|
||||
}
|
||||
flipper_format_write_string(file, "Card Key 1", ck1_str);
|
||||
|
||||
FuriString* ck2_str = furi_string_alloc();
|
||||
for(size_t i = 0; i < FELICA_BLOCK_SIZE; i++) {
|
||||
if(info->REG != NULL) {
|
||||
furi_string_cat_printf(ck2_str, "%02X ", info->card_key_2[i]);
|
||||
} else {
|
||||
furi_string_cat_printf(ck2_str, "?? ");
|
||||
}
|
||||
}
|
||||
flipper_format_write_string(file, "Card Key 2", ck2_str);
|
||||
|
||||
flipper_format_write_hex(file, "Fixed Challenge MAC Response", info->MAC, 8);
|
||||
|
||||
flipper_format_write_bool(file, "Is Lite-S", &info->is_lite_s, 1);
|
||||
if(info->is_lite_s) {
|
||||
flipper_format_write_hex(file, "Fixed Challenge MAC-A Response", info->MAC_A, 8);
|
||||
flipper_format_write_uint32(file, "Write Count", &info->write_count, 1);
|
||||
}
|
||||
|
||||
} while(false);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
static bool nfc_device_save_felica_area(FlipperFormat* file, FelicaArea* area) {
|
||||
bool saved = false;
|
||||
FuriString* prefix = furi_string_alloc_printf("Area %d", area->number);
|
||||
FuriString* key = furi_string_alloc();
|
||||
|
||||
do {
|
||||
furi_string_printf(key, "%s Can Create Subareas", prefix);
|
||||
flipper_format_write_bool(file, furi_string_get_cstr(key), &area->can_create_subareas, 1);
|
||||
furi_string_printf(key, "%s End Service Code", prefix);
|
||||
flipper_format_write_hex(
|
||||
file, furi_string_get_cstr(key), (uint8_t*)&area->end_service_code, sizeof(uint16_t));
|
||||
|
||||
bool node_saved = true;
|
||||
for
|
||||
M_EACH(node, area->nodes, FelicaNodeArray_t) {
|
||||
if(nfc_device_save_felica_node(file, node)) {
|
||||
node_saved = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!node_saved) break;
|
||||
saved = true;
|
||||
} while(false);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
static bool nfc_device_save_felica_service(FlipperFormat* file, FelicaService* service) {
|
||||
bool saved = false;
|
||||
FuriString* prefix = furi_string_alloc_printf("Service %d", service->number);
|
||||
FuriString* key = furi_string_alloc();
|
||||
|
||||
do {
|
||||
furi_string_printf(key, "%s Is Extended Overlap", prefix);
|
||||
flipper_format_write_bool(
|
||||
file, furi_string_get_cstr(key), &service->is_extended_overlap, 1);
|
||||
if(service->is_extended_overlap) {
|
||||
furi_string_printf(key, "%s Overlap Target", prefix);
|
||||
flipper_format_write_hex(
|
||||
file,
|
||||
furi_string_get_cstr(key),
|
||||
(uint8_t*)&service->overlap_target,
|
||||
sizeof(uint16_t));
|
||||
|
||||
furi_string_printf(key, "%s Block Start", prefix);
|
||||
const uint32_t block_start = service->block_start;
|
||||
flipper_format_write_uint32(file, furi_string_get_cstr(key), &block_start, 1);
|
||||
|
||||
furi_string_printf(key, "%s Block Count", prefix);
|
||||
const uint32_t block_count = service->block_count;
|
||||
flipper_format_write_uint32(file, furi_string_get_cstr(key), &block_count, 1);
|
||||
|
||||
uint32_t i = 0;
|
||||
for
|
||||
M_EACH(block, service->blocks, FelicaBlockArray_t) {
|
||||
furi_string_printf(key, "%s Block %d", prefix, i);
|
||||
flipper_format_write_hex(
|
||||
file, furi_string_get_cstr(key), block->data, FELICA_BLOCK_SIZE);
|
||||
}
|
||||
} else {
|
||||
furi_string_printf(key, "%s Block Count", prefix);
|
||||
uint32_t block_count = FelicaBlockArray_size(service->blocks);
|
||||
flipper_format_write_uint32(file, furi_string_get_cstr(key), &block_count, 1);
|
||||
uint32_t i = 0;
|
||||
for
|
||||
M_EACH(block, service->blocks, FelicaBlockArray_t) {
|
||||
furi_string_printf(key, "%s Block %d", prefix, i);
|
||||
flipper_format_write_hex(
|
||||
file, furi_string_get_cstr(key), block->data, FELICA_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
saved = true;
|
||||
} while(false);
|
||||
}
|
||||
|
||||
static bool nfc_device_save_felica_node(FlipperFormat* file, FelicaNode* node) {
|
||||
bool saved = false;
|
||||
FuriString* key = furi_string_alloc();
|
||||
|
||||
do {
|
||||
if(node->type == FelicaNodeTypeArea) {
|
||||
if(!nfc_device_save_felica_node(file, node->area)) {
|
||||
saved = false;
|
||||
break;
|
||||
}
|
||||
} else if(node->type == FelicaNodeTypeService) {
|
||||
if(!nfc_device_save_felica_service(file, node->area)) {
|
||||
saved = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
saved = true;
|
||||
} while(false);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
static bool nfc_device_save_felica_data(FlipperFormat* file, NfcDevice* dev) {
|
||||
bool saved = false;
|
||||
FelicaData* data = &dev->dev_data.felica_data;
|
||||
// Save FeliCa specific data
|
||||
do {
|
||||
if(!flipper_format_write_comment_cstr(file, "FeliCa specific data")) break;
|
||||
if(!flipper_format_write_uint32(
|
||||
file, "Data format version", &nfc_felica_data_format_version, 1))
|
||||
break;
|
||||
|
||||
for
|
||||
M_EACH(system, data->systems, FelicaSystemArray_t) {
|
||||
flipper_format_write_hex(file, "System", &system->number, sizeof(uint8_t));
|
||||
flipper_format_write_hex(file, "Code", (uint8_t*)&system->code, sizeof(uint16_t));
|
||||
if(system->code == LITE_SYSTEM_CODE) {
|
||||
nfc_device_save_felica_lite(file, &system->lite_info);
|
||||
} else {
|
||||
nfc_device_save_felica_node(file, &system->root);
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
static void nfc_device_load_mifare_classic_block(
|
||||
FuriString* block_str,
|
||||
MfClassicData* data,
|
||||
@@ -1402,39 +1600,43 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
|
||||
if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break;
|
||||
// Write nfc device type
|
||||
if(!flipper_format_write_comment_cstr(
|
||||
file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic or ISO15693"))
|
||||
file,
|
||||
"Nfc device type can be UID, Mifare Ultralight, Mifare Classic, FeliCa or ISO15693"))
|
||||
break;
|
||||
nfc_device_prepare_format_string(dev, temp_str);
|
||||
if(!flipper_format_write_string(file, "Device type", temp_str)) break;
|
||||
// Write UID
|
||||
if(!flipper_format_write_comment_cstr(file, "UID is common for all formats")) break;
|
||||
if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
|
||||
if(data->type == FuriHalNfcTypeA) {
|
||||
if(!flipper_format_write_comment_cstr(file, "UID is common for all formats")) break;
|
||||
if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
|
||||
|
||||
if(dev->format != NfcDeviceSaveFormatNfcV) {
|
||||
// Write ATQA, SAK
|
||||
if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields")) break;
|
||||
// Save ATQA in MSB order for correct companion apps display
|
||||
uint8_t atqa[2] = {data->a_data.atqa[1], data->a_data.atqa[0]};
|
||||
if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break;
|
||||
if(!flipper_format_write_hex(file, "SAK", &data->a_data.sak, 1)) break;
|
||||
}
|
||||
if(dev->format != NfcDeviceSaveFormatNfcV) {
|
||||
// Write ATQA, SAK
|
||||
if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields")) break;
|
||||
// Save ATQA in MSB order for correct companion apps display
|
||||
uint8_t atqa[2] = {data->a_data.atqa[1], data->a_data.atqa[0]};
|
||||
if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break;
|
||||
if(!flipper_format_write_hex(file, "SAK", &data->a_data.sak, 1)) break;
|
||||
}
|
||||
|
||||
// Save more data if necessary
|
||||
if(dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||
if(!nfc_device_save_mifare_ul_data(file, dev)) break;
|
||||
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
||||
if(!nfc_device_save_mifare_df_data(file, dev)) break;
|
||||
} else if(dev->format == NfcDeviceSaveFormatNfcV) {
|
||||
if(!nfc_device_save_nfcv_data(file, dev)) break;
|
||||
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
|
||||
if(!nfc_device_save_bank_card_data(file, dev)) break;
|
||||
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||
// Save data
|
||||
if(!nfc_device_save_mifare_classic_data(file, dev)) break;
|
||||
// Save keys cache
|
||||
if(!nfc_device_save_mifare_classic_keys(dev)) break;
|
||||
// Save more data if necessary
|
||||
if(dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||
if(!nfc_device_save_mifare_ul_data(file, dev)) break;
|
||||
} else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
||||
if(!nfc_device_save_mifare_df_data(file, dev)) break;
|
||||
} else if(dev->format == NfcDeviceSaveFormatNfcV) {
|
||||
if(!nfc_device_save_nfcv_data(file, dev)) break;
|
||||
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
|
||||
if(!nfc_device_save_bank_card_data(file, dev)) break;
|
||||
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||
// Save data
|
||||
if(!nfc_device_save_mifare_classic_data(file, dev)) break;
|
||||
// Save keys cache
|
||||
if(!nfc_device_save_mifare_classic_keys(dev)) break;
|
||||
}
|
||||
saved = true;
|
||||
} else if(data->type == FuriHalNfcTypeF) {
|
||||
if(!nfc_device_save_felica_data(file, dev)) break;
|
||||
}
|
||||
saved = true;
|
||||
} while(0);
|
||||
|
||||
if(!saved) { //-V547
|
||||
|
||||
+216
-4
@@ -1,4 +1,5 @@
|
||||
#include <limits.h>
|
||||
#include <mbedtls/des.h>
|
||||
#include <mbedtls/sha1.h>
|
||||
#include "felica.h"
|
||||
#include "nfc_util.h"
|
||||
@@ -151,6 +152,215 @@ FelicaICType felica_get_ic_type(uint8_t* PMm) {
|
||||
return FelicaICType2K;
|
||||
}
|
||||
|
||||
static void felica_lite_diversify_key(uint8_t* id_block, uint8_t* master_key, uint8_t* card_key) {
|
||||
uint8_t ZERO[8] = {0};
|
||||
uint8_t L[8];
|
||||
mbedtls_des3_context ctx;
|
||||
mbedtls_des3_init(&ctx);
|
||||
mbedtls_des3_set3key_enc(&ctx, master_key);
|
||||
mbedtls_des3_crypt_ecb(&ctx, ZERO, L);
|
||||
mbedtls_des3_free(&ctx);
|
||||
|
||||
uint8_t K1[8];
|
||||
for(int i = 0; i < 8; i++) {
|
||||
K1[i] = L[i] << 1;
|
||||
if(i < 7) {
|
||||
K1[i] |= (L[i + 1] >> 7);
|
||||
}
|
||||
}
|
||||
|
||||
if((L[0] ^ 0x80) == 0) {
|
||||
K1[7] ^= 0x1B;
|
||||
}
|
||||
|
||||
uint8_t M1[8];
|
||||
uint8_t M2[8];
|
||||
memcpy(M1, id_block, 8);
|
||||
memcpy(M2, id_block + 8, 8);
|
||||
for(int i = 0; i < 8; i++) {
|
||||
M2[i] ^= K1[i];
|
||||
}
|
||||
|
||||
uint8_t C1[8];
|
||||
mbedtls_des3_init(&ctx);
|
||||
mbedtls_des3_set3key_enc(&ctx, master_key);
|
||||
mbedtls_des3_crypt_ecb(&ctx, M1, C1);
|
||||
for(int i = 0; i < 8; i++) {
|
||||
C1[i] ^= M2[i];
|
||||
}
|
||||
|
||||
mbedtls_des3_crypt_ecb(&ctx, C1, card_key); // T
|
||||
|
||||
M1[0] ^= 0x80; // M'1
|
||||
mbedtls_des3_crypt_ecb(&ctx, M1, C1); // C'1
|
||||
for(int i = 0; i < 8; i++) {
|
||||
C1[i] ^= M2[i];
|
||||
}
|
||||
|
||||
mbedtls_des3_crypt_ecb(&ctx, C1, card_key + 8); // T'
|
||||
mbedtls_des3_free(&ctx);
|
||||
}
|
||||
|
||||
static void felica_lite_generate_session_key(
|
||||
uint8_t* random_challenge,
|
||||
uint8_t* card_key,
|
||||
uint8_t* session_key) {
|
||||
uint8_t RC1[8];
|
||||
uint8_t RC2[8];
|
||||
uint8_t CK[16];
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
RC1[i] = random_challenge[7 - i];
|
||||
RC2[i] = random_challenge[i];
|
||||
CK[i] = card_key[7 - i];
|
||||
CK[i + 8] = card_key[15 - i];
|
||||
}
|
||||
|
||||
mbedtls_des3_context ctx;
|
||||
|
||||
uint8_t SK1[8];
|
||||
mbedtls_des3_init(&ctx);
|
||||
mbedtls_des3_set2key_enc(&ctx, CK);
|
||||
mbedtls_des3_crypt_ecb(&ctx, RC1, SK1);
|
||||
|
||||
uint8_t SK2[8];
|
||||
for(int i = 0; i < 8; i++) {
|
||||
RC2[i] ^= SK1[i];
|
||||
}
|
||||
mbedtls_des3_crypt_ecb(&ctx, RC2, SK2);
|
||||
mbedtls_des3_free(&ctx);
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
session_key[i] = SK1[7 - i];
|
||||
session_key[i + 8] = SK2[7 - i];
|
||||
}
|
||||
}
|
||||
|
||||
static void felica_lite_calculate_mac(
|
||||
uint8_t* random_challenge,
|
||||
uint8_t* session_key,
|
||||
uint8_t* block_data,
|
||||
size_t block_count,
|
||||
uint8_t* MAC) {
|
||||
uint8_t SK[16];
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
MAC[i] = random_challenge[7 - i];
|
||||
SK[i] = session_key[7 - i];
|
||||
SK[i + 8] = session_key[15 - i];
|
||||
}
|
||||
|
||||
mbedtls_des3_context ctx;
|
||||
mbedtls_des3_init(&ctx);
|
||||
mbedtls_des3_set3key_enc(&ctx, SK);
|
||||
|
||||
for(size_t block_num = 0; block_num < block_count; block_num++) {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
MAC[i] ^= block_data[block_num * FELICA_BLOCK_SIZE + 7 - i];
|
||||
}
|
||||
|
||||
uint8_t intermediate[8];
|
||||
mbedtls_des3_crypt_ecb(&ctx, MAC, intermediate);
|
||||
for(int i = 0; i < 8; i++) {
|
||||
intermediate[i] ^= block_data[block_num * FELICA_BLOCK_SIZE + 15 - i];
|
||||
}
|
||||
|
||||
mbedtls_des3_crypt_ecb(&ctx, intermediate, MAC);
|
||||
}
|
||||
|
||||
mbedtls_des3_free(&ctx);
|
||||
}
|
||||
|
||||
static void felica_lite_calculate_mac_a(
|
||||
uint8_t* random_challenge,
|
||||
uint8_t* session_key,
|
||||
uint8_t* iv,
|
||||
uint8_t* block_data,
|
||||
size_t block_count,
|
||||
uint8_t* MAC_A) {
|
||||
uint8_t SK[16];
|
||||
uint8_t intermediate_a[8];
|
||||
uint8_t intermediate_b[8];
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
intermediate_a[i] = iv[7 - 1] ^ random_challenge[7 - i];
|
||||
SK[i] = session_key[7 - i];
|
||||
SK[i + 8] = session_key[15 - i];
|
||||
}
|
||||
|
||||
mbedtls_des3_context ctx;
|
||||
mbedtls_des3_init(&ctx);
|
||||
mbedtls_des3_set3key_enc(&ctx, SK);
|
||||
mbedtls_des3_crypt_ecb(&ctx, intermediate_a, intermediate_b);
|
||||
|
||||
for(size_t block_num = 0; block_num < block_count; block_num++) {
|
||||
for(int i = 0; i < 8; i++) {
|
||||
intermediate_b[i] ^= block_data[block_num * FELICA_BLOCK_SIZE + 7 - i];
|
||||
}
|
||||
|
||||
mbedtls_des3_crypt_ecb(&ctx, intermediate_b, intermediate_a);
|
||||
for(int i = 0; i < 8; i++) {
|
||||
intermediate_a[i] ^= block_data[block_num * FELICA_BLOCK_SIZE + 7 - i];
|
||||
}
|
||||
|
||||
mbedtls_des3_crypt_ecb(&ctx, intermediate_a, intermediate_b);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
MAC_A[i] = intermediate_b[7 - 1];
|
||||
}
|
||||
}
|
||||
|
||||
static void felica_lite_calculate_mac_a_for_write(
|
||||
uint8_t* random_challenge,
|
||||
uint8_t* session_key,
|
||||
uint32_t write_count,
|
||||
uint8_t block_number,
|
||||
uint8_t* block_data,
|
||||
uint8_t* MAC_A) {
|
||||
uint8_t iv[8];
|
||||
nfc_util_num2bytes(write_count, 3, iv);
|
||||
iv[3] = 0x00;
|
||||
iv[4] = block_number;
|
||||
iv[5] = 0x00;
|
||||
iv[6] = 0x91;
|
||||
iv[7] = 0x00;
|
||||
|
||||
uint8_t SK[16];
|
||||
for(int i = 0; i < 8; i++) {
|
||||
SK[i] = session_key[i + 8];
|
||||
SK[i + 8] = session_key[i];
|
||||
}
|
||||
|
||||
felica_lite_calculate_mac_a(random_challenge, SK, iv, block_data, 1, MAC_A);
|
||||
}
|
||||
|
||||
static void felica_lite_calculate_mac_a_for_read(
|
||||
uint8_t* random_challenge,
|
||||
uint8_t* session_key,
|
||||
uint8_t* block_list,
|
||||
uint8_t block_list_count,
|
||||
uint8_t* block_data,
|
||||
uint8_t block_count,
|
||||
uint8_t* MAC_A) {
|
||||
uint8_t iv[8] = {0};
|
||||
|
||||
uint8_t block_list_to_write = MIN(block_list_count, 4);
|
||||
for(int i = 0; i < block_list_to_write; i++) {
|
||||
iv[i * 2] = block_list[i];
|
||||
}
|
||||
if(block_list_to_write < 4) {
|
||||
iv[6] = 0xFF;
|
||||
iv[7] = 0xFF;
|
||||
}
|
||||
if(block_list_to_write < 3) {
|
||||
iv[4] = 0xFF;
|
||||
iv[5] = 0xFF;
|
||||
}
|
||||
|
||||
felica_lite_calculate_mac_a(random_challenge, session_key, iv, block_data, block_count, MAC_A);
|
||||
}
|
||||
|
||||
/** Parse common FeliCa response headers.
|
||||
*
|
||||
* This parses and validates the most commonly occurring response header types.
|
||||
@@ -165,7 +375,7 @@ FelicaICType felica_get_ic_type(uint8_t* PMm) {
|
||||
* @param always_succeed When set to true, skip status flags (sf1 and sf2) parsing.
|
||||
* @return The number of bytes parsed, or 0 when response is invalid or status flags are set.
|
||||
*/
|
||||
static uint8_t felica_consume_header(
|
||||
static uint8_t felica_consume_unencrypted_header(
|
||||
uint8_t* buf,
|
||||
uint8_t len,
|
||||
FelicaReader* reader,
|
||||
@@ -261,7 +471,8 @@ uint16_t felica_parse_unencrypted_read(
|
||||
FelicaReader* reader,
|
||||
uint8_t* out,
|
||||
uint16_t out_len) {
|
||||
uint8_t consumed = felica_consume_header(buf, len, reader, FELICA_UNENCRYPTED_READ_RES, false);
|
||||
uint8_t consumed =
|
||||
felica_consume_unencrypted_header(buf, len, reader, FELICA_UNENCRYPTED_READ_RES, false);
|
||||
if(!consumed) {
|
||||
return 0;
|
||||
}
|
||||
@@ -345,7 +556,7 @@ uint8_t felica_lite_prepare_unencrypted_write(
|
||||
|
||||
bool felica_parse_unencrypted_write(uint8_t* buf, uint8_t len, FelicaReader* reader) {
|
||||
uint8_t consumed =
|
||||
felica_consume_header(buf, len, reader, FELICA_UNENCRYPTED_WRITE_RES, false);
|
||||
felica_consume_unencrypted_header(buf, len, reader, FELICA_UNENCRYPTED_WRITE_RES, false);
|
||||
if(!consumed) {
|
||||
return false;
|
||||
}
|
||||
@@ -364,7 +575,7 @@ bool felica_parse_request_system_code(
|
||||
FelicaReader* reader,
|
||||
FelicaSystemArray_t* systems) {
|
||||
uint8_t consumed =
|
||||
felica_consume_header(buf, len, reader, FELICA_REQUEST_SYSTEM_CODE_RES, true);
|
||||
felica_consume_unencrypted_header(buf, len, reader, FELICA_REQUEST_SYSTEM_CODE_RES, true);
|
||||
if(consumed == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -588,6 +799,7 @@ bool felica_lite_dump_data(
|
||||
}
|
||||
}
|
||||
if(data->type == FelicaICTypeLiteS) {
|
||||
lite_info->is_lite_s = true;
|
||||
const uint8_t fixed_s_blocks[] = {
|
||||
CARD_KEY_LITE_BLOCK,
|
||||
MAC_A_LITE_BLOCK,
|
||||
|
||||
@@ -206,6 +206,7 @@ typedef struct {
|
||||
uint16_t card_key_version;
|
||||
uint8_t memory_config[FELICA_BLOCK_SIZE];
|
||||
|
||||
bool is_lite_s;
|
||||
// Lite-S only
|
||||
uint8_t MAC_A[8];
|
||||
uint32_t write_count;
|
||||
@@ -294,8 +295,6 @@ uint8_t felica_lite_prepare_unencrypted_write(
|
||||
const uint8_t* block_data);
|
||||
bool felica_parse_unencrypted_write(uint8_t* buf, uint8_t len, FelicaReader* reader);
|
||||
|
||||
bool felica_lite_can_read_without_mac(uint8_t* mc_r_restr, uint8_t block_number);
|
||||
|
||||
void felica_define_normal_block(FelicaService* service, uint16_t number, uint8_t* data);
|
||||
void felica_push_normal_block(FelicaService* service, uint8_t* data);
|
||||
|
||||
|
||||
@@ -11,6 +11,20 @@ uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t uni
|
||||
return TIME_CONSTANT_US * scale * (base_cost_factor + unit_cost_factor * units);
|
||||
}
|
||||
|
||||
bool felica_lite_is_issued(FelicaLiteInfo* lite_info) {
|
||||
// System blocks aren't writable?
|
||||
if(lite_info->memory_config[2] == 0x00) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// MC is not writable?
|
||||
if(lite_info->memory_config[1] & 0x80) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FuriString* felica_get_system_name(FelicaSystem* system) {
|
||||
uint16_t code = system->code;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "./felica.h"
|
||||
|
||||
uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t units);
|
||||
bool felica_lite_is_issued(FelicaLiteInfo* lite_info);
|
||||
FuriString* felica_get_system_name(FelicaSystem* system);
|
||||
FuriString* felica_get_service_name(FelicaService* service);
|
||||
Reference in New Issue
Block a user