Skip to content

Commit b4b697f

Browse files
committed
NFC FeliCa: Add card generator for FeliCa Lite-S
The IDm is generated by setting the first 2 bytes of the IDm (i.e. the Manufacturer Code) to 012E, then fill the rest of the 6 bytes with random data. All 8 bytes of the generated IDm are changable with the Edit UID option before saving. The PMm and default register values are copied from FeliCa Lite-S User's Manual v1.31 and cross-checked with a blank (post-0th Issuance) Lite-S.
1 parent c9ab2b6 commit b4b697f

5 files changed

Lines changed: 103 additions & 12 deletions

File tree

applications/main/nfc/helpers/protocol_support/felica/felica.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,13 @@ static void nfc_scene_read_menu_on_enter_felica(NfcApp* instance) {
155155

156156
static bool nfc_scene_read_menu_on_event_felica(NfcApp* instance, SceneManagerEvent event) {
157157
if(event.type == SceneManagerEventTypeCustom) {
158-
if(event.event == SubmenuIndexUnlock) {
158+
switch(event.event) {
159+
case SubmenuIndexUnlock:
159160
scene_manager_next_scene(instance->scene_manager, NfcSceneDesAuthKeyInput);
160161
return true;
162+
case SubmenuIndexCommonEdit:
163+
scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid);
164+
return true;
161165
}
162166
}
163167
return false;

applications/main/nfc/scenes/nfc_scene_generate_info.c

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,38 @@ void nfc_scene_generate_info_on_enter(void* context) {
1414
NfcApp* instance = context;
1515

1616
NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device);
17-
furi_assert((protocol == NfcProtocolMfUltralight) || (protocol == NfcProtocolMfClassic));
1817

19-
const Iso14443_3aData* iso14443_3a_data =
20-
nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_3a);
18+
const char* type_cstr;
19+
FuriString* id_str;
20+
21+
switch(protocol) {
22+
case NfcProtocolMfUltralight:
23+
case NfcProtocolMfClassic: {
24+
const Iso14443_3aData* iso14443_3a_data =
25+
nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_3a);
26+
type_cstr = "NFC-A";
27+
id_str = furi_string_alloc_printf("UID:");
28+
// Append UID
29+
for(int i = 0; i < iso14443_3a_data->uid_len; i++) {
30+
furi_string_cat_printf(id_str, " %02X", iso14443_3a_data->uid[i]);
31+
}
32+
break;
33+
}
34+
35+
case NfcProtocolFelica: {
36+
const FelicaData* felica_data =
37+
nfc_device_get_data(instance->nfc_device, NfcProtocolFelica);
38+
type_cstr = "FeliCa";
39+
id_str = furi_string_alloc_printf("IDm:");
40+
for(unsigned int i = 0; i < FELICA_IDM_SIZE; i++) {
41+
furi_string_cat_printf(id_str, " %02X", felica_data->idm.data[i]);
42+
}
43+
break;
44+
}
45+
46+
default:
47+
furi_crash("NFC: Unhandled protocol.");
48+
}
2149

2250
// Setup dialog view
2351
Widget* widget = instance->widget;
@@ -29,16 +57,11 @@ void nfc_scene_generate_info_on_enter(void* context) {
2957
scene_manager_get_scene_state(instance->scene_manager, NfcSceneGenerateInfo);
3058
const char* name = nfc_data_generator_get_name(type);
3159
widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, name);
32-
widget_add_string_element(widget, 0, 13, AlignLeft, AlignTop, FontSecondary, "NFC-A");
60+
widget_add_string_element(widget, 0, 13, AlignLeft, AlignTop, FontSecondary, type_cstr);
3361

34-
FuriString* temp_str = furi_string_alloc_printf("UID:");
35-
// Append UID
36-
for(int i = 0; i < iso14443_3a_data->uid_len; i++) {
37-
furi_string_cat_printf(temp_str, " %02X", iso14443_3a_data->uid[i]);
38-
}
3962
widget_add_string_element(
40-
widget, 0, 25, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str));
41-
furi_string_free(temp_str);
63+
widget, 0, 25, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(id_str));
64+
furi_string_free(id_str);
4265

4366
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
4467
}

lib/nfc/helpers/nfc_data_generator.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <furi/furi.h>
44
#include <furi_hal_random.h>
5+
#include <nfc/protocols/felica/felica.h>
56
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
67
#include <nfc/protocols/mf_classic/mf_classic.h>
78
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
@@ -24,6 +25,10 @@ static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x0
2425
static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE};
2526
static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE};
2627
static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00};
28+
static const uint8_t pmm_felica_lite_s[] = {0x00, 0xF1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00};
29+
static const uint8_t default_mc_felica_lite_s[] =
30+
{0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
31+
static const uint8_t default_wcnt_felica_lite_s[] = {0x00, 0xFE, 0xFF};
2732

2833
static void nfc_generate_mf_ul_uid(uint8_t* uid) {
2934
uid[0] = NXP_MANUFACTURER_ID;
@@ -314,6 +319,12 @@ static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) {
314319
uid[3] |= 0x01; // To avoid forbidden 0x88 value
315320
}
316321

322+
static void nfc_generate_felica_idm(uint8_t idm[8], uint16_t mfr_code) {
323+
idm[0] = mfr_code & 0xff;
324+
idm[1] = mfr_code >> 8;
325+
furi_hal_random_fill_buf(&idm[2], FELICA_IDM_SIZE - 2);
326+
}
327+
317328
static void
318329
nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) {
319330
data->iso14443_3a_data->uid_len = uid_len;
@@ -436,6 +447,47 @@ static void nfc_generate_mf_classic_4k_7b_uid(NfcDevice* nfc_device) {
436447
nfc_generate_mf_classic(nfc_device, 7, MfClassicType4k);
437448
}
438449

450+
static void nfc_generate_felica_lite_s(NfcDevice* nfc_device) {
451+
uint8_t idm[FELICA_IDM_SIZE];
452+
453+
FelicaData* felica_data = felica_alloc();
454+
felica_data->workflow_type = FelicaLite;
455+
456+
// All Lite-S cards I've seen have the manufacturer code of 0x2E01 although this could differ.
457+
// Hard-code this to be 0x2E01 for now.
458+
nfc_generate_felica_idm(idm, 0x2E01);
459+
460+
memcpy(felica_data->idm.data, idm, sizeof(idm));
461+
memcpy(felica_data->pmm.data, pmm_felica_lite_s, sizeof(pmm_felica_lite_s));
462+
463+
felica_data->blocks_total = 28;
464+
felica_data->blocks_read = 26;
465+
memset(felica_data->data.dump, 0, sizeof(felica_data->data.dump));
466+
467+
FelicaFileSystem* fs = &felica_data->data.fs;
468+
469+
memset(fs->reg.data, 0xFF, sizeof(fs->reg.data));
470+
471+
memcpy(fs->id.data, idm, sizeof(idm));
472+
memcpy(fs->d_id.data, idm, sizeof(idm));
473+
memcpy(&fs->d_id.data[8], pmm_felica_lite_s, sizeof(pmm_felica_lite_s));
474+
475+
fs->sys_c.data[0] = 0x88;
476+
fs->sys_c.data[1] = 0xB4;
477+
478+
memcpy(fs->mc.data, default_mc_felica_lite_s, sizeof(default_mc_felica_lite_s));
479+
memcpy(fs->wcnt.data, default_wcnt_felica_lite_s, sizeof(default_wcnt_felica_lite_s));
480+
481+
// When MAC_A is read casually by the current reader, status code 01B2 will always
482+
// be returned as the reader does not start authentication by default.
483+
// Simulate this behavior in the generator.
484+
fs->mac_a.SF1 = 0x01;
485+
fs->mac_a.SF2 = 0xB2;
486+
487+
nfc_device_set_data(nfc_device, NfcProtocolFelica, felica_data);
488+
felica_free(felica_data);
489+
}
490+
439491
static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = {
440492
[NfcDataGeneratorTypeMfUltralight] =
441493
{
@@ -527,6 +579,11 @@ static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = {
527579
.name = "Mifare Classic 4k 7byte UID",
528580
.handler = nfc_generate_mf_classic_4k_7b_uid,
529581
},
582+
[NfcDataGeneratorTypeFelicaLiteS] =
583+
{
584+
.name = "FeliCa Lite-S",
585+
.handler = nfc_generate_felica_lite_s,
586+
},
530587
};
531588

532589
const char* nfc_data_generator_get_name(NfcDataGeneratorType type) {

lib/nfc/helpers/nfc_data_generator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ typedef enum {
2727
NfcDataGeneratorTypeMfClassic4k_4b,
2828
NfcDataGeneratorTypeMfClassic4k_7b,
2929

30+
NfcDataGeneratorTypeFelicaLiteS,
31+
3032
NfcDataGeneratorTypeNum,
3133

3234
} NfcDataGeneratorType;

lib/nfc/protocols/felica/felica.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,11 @@ bool felica_set_uid(FelicaData* data, const uint8_t* uid, size_t uid_len) {
497497
const bool uid_valid = uid_len == FELICA_IDM_SIZE;
498498
if(uid_valid) {
499499
memcpy(data->idm.data, uid, uid_len);
500+
// Also sync ID and D_ID with IDm if system is FeliCa Lite.
501+
if(data->workflow_type == FelicaLite) {
502+
memcpy(data->data.fs.id.data, uid, uid_len);
503+
memcpy(data->data.fs.d_id.data, uid, uid_len);
504+
}
500505
}
501506

502507
return uid_valid;

0 commit comments

Comments
 (0)