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
1617const 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
1921PicopassDevice * 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+
249273static 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
380434bool 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 ]));
0 commit comments