Skip to content

Commit 97423fc

Browse files
bettseskotopes
andauthored
Picopass: Save unknown blocks with ?? (#196)
Co-authored-by: あく <[email protected]>
1 parent 5e7ae5b commit 97423fc

File tree

8 files changed

+82
-26
lines changed

8 files changed

+82
-26
lines changed

picopass_device.c

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <picopass_icons.h>
66

77
#include <toolbox/protocols/protocol_dict.h>
8+
#include <toolbox/hex.h>
89
#include <lfrfid/protocols/lfrfid_protocols.h>
910
#include <lfrfid/lfrfid_dict_file.h>
1011

@@ -15,6 +16,7 @@ static const uint32_t picopass_file_version = 1;
1516

1617
const uint8_t picopass_iclass_decryptionkey[] =
1718
{0xb4, 0x21, 0x2c, 0xca, 0xb7, 0xed, 0x21, 0x0f, 0x7b, 0x93, 0xd4, 0x59, 0x39, 0xc7, 0xdd, 0x36};
19+
const char unknown_block[] = "?? ?? ?? ?? ?? ?? ?? ??";
1820

1921
PicopassDevice* picopass_device_alloc() {
2022
PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice));
@@ -169,6 +171,7 @@ static bool picopass_device_save_file(
169171
if(dev->format == PicopassDeviceSaveFormatPartial) {
170172
// Clear key that may have been set when doing key tests for legacy
171173
memset(card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0, PICOPASS_BLOCK_LEN);
174+
card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid = false;
172175
}
173176

174177
do {
@@ -203,13 +206,21 @@ static bool picopass_device_save_file(
203206
PICOPASS_MAX_APP_LIMIT;
204207
for(size_t i = 0; i < app_limit; i++) {
205208
furi_string_printf(temp_str, "Block %d", i);
206-
if(!flipper_format_write_hex(
207-
file,
208-
furi_string_get_cstr(temp_str),
209-
card_data[i].data,
210-
PICOPASS_BLOCK_LEN)) {
211-
block_saved = false;
212-
break;
209+
if(card_data[i].valid) {
210+
if(!flipper_format_write_hex(
211+
file,
212+
furi_string_get_cstr(temp_str),
213+
card_data[i].data,
214+
PICOPASS_BLOCK_LEN)) {
215+
block_saved = false;
216+
break;
217+
}
218+
} else {
219+
if(!flipper_format_write_string_cstr(
220+
file, furi_string_get_cstr(temp_str), unknown_block)) {
221+
block_saved = false;
222+
break;
223+
}
213224
}
214225
}
215226
if(!block_saved) break;
@@ -246,6 +257,19 @@ bool picopass_device_save(PicopassDevice* dev, const char* dev_name) {
246257
return false;
247258
}
248259

260+
bool picopass_hex_str_to_uint8(const char* value_str, uint8_t* value) {
261+
furi_check(value_str);
262+
furi_check(value);
263+
264+
bool parse_success = false;
265+
while(*value_str && value_str[1]) {
266+
parse_success = hex_char_to_uint8(*value_str, value_str[1], value++);
267+
if(!parse_success) break;
268+
value_str += 3;
269+
}
270+
return parse_success;
271+
}
272+
249273
static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, bool show_dialog) {
250274
bool parsed = false;
251275
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
@@ -260,43 +284,69 @@ static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, boo
260284
}
261285

262286
do {
287+
picopass_device_data_clear(&dev->dev_data);
263288
if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break;
264289

265290
// Read and verify file header
266291
uint32_t version = 0;
267292
if(!flipper_format_read_header(file, temp_str, &version)) break;
268-
if(furi_string_cmp_str(temp_str, picopass_file_header) ||
293+
if(!furi_string_equal_str(temp_str, picopass_file_header) ||
269294
(version != picopass_file_version)) {
270295
deprecated_version = true;
271296
break;
272297
}
273298

299+
FuriString* block_str = furi_string_alloc();
274300
// Parse header blocks
275301
bool block_read = true;
276302
for(size_t i = 0; i < 6; i++) {
277303
furi_string_printf(temp_str, "Block %d", i);
278-
if(!flipper_format_read_hex(
279-
file, furi_string_get_cstr(temp_str), card_data[i].data, PICOPASS_BLOCK_LEN)) {
304+
if(!flipper_format_read_string(file, furi_string_get_cstr(temp_str), block_str)) {
280305
block_read = false;
281306
break;
282307
}
308+
if(furi_string_equal_str(block_str, unknown_block)) {
309+
FURI_LOG_D(TAG, "Block %i: %s (unknown)", i, furi_string_get_cstr(block_str));
310+
card_data[i].valid = false;
311+
memset(card_data[i].data, 0, PICOPASS_BLOCK_LEN);
312+
} else {
313+
FURI_LOG_D(TAG, "Block %i: %s (hex)", i, furi_string_get_cstr(block_str));
314+
if(!picopass_hex_str_to_uint8(furi_string_get_cstr(block_str), card_data[i].data)) {
315+
block_read = false;
316+
break;
317+
}
318+
card_data[i].valid = true;
319+
}
283320
}
284321

285322
size_t app_limit = card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[0];
286323
// Fix for unpersonalized cards that have app_limit set to 0xFF
287324
if(app_limit > PICOPASS_MAX_APP_LIMIT) app_limit = PICOPASS_MAX_APP_LIMIT;
288325
for(size_t i = 6; i < app_limit; i++) {
289326
furi_string_printf(temp_str, "Block %d", i);
290-
if(!flipper_format_read_hex(
291-
file, furi_string_get_cstr(temp_str), card_data[i].data, PICOPASS_BLOCK_LEN)) {
327+
if(!flipper_format_read_string(file, furi_string_get_cstr(temp_str), block_str)) {
292328
block_read = false;
293329
break;
294330
}
331+
if(furi_string_equal_str(block_str, unknown_block)) {
332+
FURI_LOG_D(TAG, "Block %i: %s (unknown)", i, furi_string_get_cstr(block_str));
333+
card_data[i].valid = false;
334+
memset(card_data[i].data, 0, PICOPASS_BLOCK_LEN);
335+
} else {
336+
FURI_LOG_D(TAG, "Block %i: %s (hex)", i, furi_string_get_cstr(block_str));
337+
if(!picopass_hex_str_to_uint8(furi_string_get_cstr(block_str), card_data[i].data)) {
338+
block_read = false;
339+
break;
340+
}
341+
card_data[i].valid = true;
342+
}
295343
}
296344
if(!block_read) break;
297345

298-
picopass_device_parse_credential(card_data, pacs);
299-
picopass_device_parse_wiegand(pacs->credential, pacs);
346+
if(card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].valid) {
347+
picopass_device_parse_credential(card_data, pacs);
348+
picopass_device_parse_wiegand(pacs);
349+
}
300350

301351
parsed = true;
302352
} while(false);
@@ -371,10 +421,14 @@ void picopass_device_data_clear(PicopassDeviceData* dev_data) {
371421
memset(dev_data->card_data[i].data, 0, sizeof(dev_data->card_data[i].data));
372422
dev_data->card_data[i].valid = false;
373423
}
424+
425+
memset(dev_data->pacs.credential, 0, sizeof(dev_data->pacs.credential));
374426
dev_data->pacs.legacy = false;
375427
dev_data->pacs.se_enabled = false;
376428
dev_data->pacs.elite_kdf = false;
429+
dev_data->pacs.sio = false;
377430
dev_data->pacs.pin_length = 0;
431+
dev_data->pacs.bitLength = 0;
378432
}
379433

380434
bool picopass_device_delete(PicopassDevice* dev, bool use_load_path) {
@@ -450,7 +504,8 @@ void picopass_device_parse_credential(PicopassBlock* card_data, PicopassPacs* pa
450504
pacs->sio = (card_data[10].data[0] == 0x30); // rough check
451505
}
452506

453-
void picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs) {
507+
void picopass_device_parse_wiegand(PicopassPacs* pacs) {
508+
uint8_t* credential = pacs->credential;
454509
uint32_t* halves = (uint32_t*)credential;
455510
if(halves[0] == 0) {
456511
uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1]));

picopass_device.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,5 @@ void picopass_device_set_loading_callback(
150150
void* context);
151151

152152
void picopass_device_parse_credential(PicopassBlock* card_data, PicopassPacs* pacs);
153-
void picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs);
153+
void picopass_device_parse_wiegand(PicopassPacs* pacs);
154154
bool picopass_device_hid_csn(PicopassDevice* dev);

protocol/picopass_listener.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ PicopassListenerCommand
378378
uint8_t rmac[4] = {};
379379
uint8_t tmac[4] = {};
380380
const uint8_t* key = instance->data->card_data[instance->key_block_num].data;
381-
bool no_key = picopass_is_memset(key, 0x00, PICOPASS_BLOCK_LEN);
381+
bool no_key = !instance->data->card_data[instance->key_block_num].valid;
382382
const uint8_t* rx_data = bit_buffer_get_data(buf);
383383

384384
if(no_key) {

protocol/picopass_poller.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ NfcCommand picopass_poller_parse_credential_handler(PicopassPoller* instance) {
463463
NfcCommand picopass_poller_parse_wiegand_handler(PicopassPoller* instance) {
464464
NfcCommand command = NfcCommandContinue;
465465

466-
picopass_device_parse_wiegand(instance->data->pacs.credential, &instance->data->pacs);
466+
picopass_device_parse_wiegand(&instance->data->pacs);
467467
instance->state = PicopassPollerStateSuccess;
468468
return command;
469469
}

scenes/picopass_scene_card_menu.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ void picopass_scene_card_menu_on_enter(void* context) {
2828
bool zero_config = picopass_is_memset(
2929
card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0x00, PICOPASS_BLOCK_LEN);
3030
bool no_credential = picopass_is_memset(pacs->credential, 0x00, sizeof(pacs->credential));
31-
bool no_key = picopass_is_memset(
32-
card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN);
31+
bool no_key = !card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid;
3332

3433
if(secured && zero_config) {
3534
submenu_add_item(

scenes/picopass_scene_device_info.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ bool picopass_scene_device_info_on_event(void* context, SceneManagerEvent event)
102102
consumed = true;
103103
}
104104
} else if(event.type == SceneManagerEventTypeBack) {
105-
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
106-
consumed = true;
105+
consumed = scene_manager_previous_scene(picopass->scene_manager);
107106
}
108107
return consumed;
109108
}

scenes/picopass_scene_more_info.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ void picopass_scene_more_info_on_enter(void* context) {
1919

2020
for(size_t i = 0; i < app_limit; i++) {
2121
for(size_t j = 0; j < PICOPASS_BLOCK_LEN; j += 2) {
22-
furi_string_cat_printf(
23-
str, "%02X%02X ", card_data[i].data[j], card_data[i].data[j + 1]);
22+
if(card_data[i].valid) {
23+
furi_string_cat_printf(
24+
str, "%02X%02X ", card_data[i].data[j], card_data[i].data[j + 1]);
25+
} else {
26+
furi_string_cat_printf(str, "???? ");
27+
}
2428
}
2529
}
2630

scenes/picopass_scene_read_card_success.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ void picopass_scene_read_card_success_on_enter(void* context) {
133133
furi_string_cat_printf(credential_str, " +SIO");
134134
}
135135

136-
bool no_key = picopass_is_memset(
137-
card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN);
136+
bool no_key = !card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid;
138137

139138
if(no_key) {
140139
furi_string_cat_printf(key_str, "No Key: used NR-MAC");

0 commit comments

Comments
 (0)