Просмотр исходного кода

Picopass block tracking (#125)

Co-authored-by: あく <alleteam@gmail.com>
Eric Betts 1 год назад
Родитель
Сommit
5e7ae5b218

+ 1 - 0
picopass_device.c

@@ -369,6 +369,7 @@ bool picopass_file_select(PicopassDevice* dev) {
 void picopass_device_data_clear(PicopassDeviceData* dev_data) {
 void picopass_device_data_clear(PicopassDeviceData* dev_data) {
     for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
     for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
         memset(dev_data->card_data[i].data, 0, sizeof(dev_data->card_data[i].data));
         memset(dev_data->card_data[i].data, 0, sizeof(dev_data->card_data[i].data));
+        dev_data->card_data[i].valid = false;
     }
     }
     dev_data->pacs.legacy = false;
     dev_data->pacs.legacy = false;
     dev_data->pacs.se_enabled = false;
     dev_data->pacs.se_enabled = false;

+ 1 - 0
picopass_device.h

@@ -99,6 +99,7 @@ typedef struct {
 
 
 typedef struct {
 typedef struct {
     uint8_t data[PICOPASS_BLOCK_LEN];
     uint8_t data[PICOPASS_BLOCK_LEN];
+    bool valid;
 } PicopassBlock;
 } PicopassBlock;
 
 
 typedef struct {
 typedef struct {

+ 11 - 13
protocol/picopass_listener.c

@@ -43,14 +43,12 @@ static void picopass_listener_loclass_update_csn(PicopassListener* instance) {
     // collect LOCLASS_NUM_PER_CSN nonces in a row for each CSN
     // collect LOCLASS_NUM_PER_CSN nonces in a row for each CSN
     const uint8_t* csn =
     const uint8_t* csn =
         loclass_csns[(instance->key_block_num / LOCLASS_NUM_PER_CSN) % LOCLASS_NUM_CSNS];
         loclass_csns[(instance->key_block_num / LOCLASS_NUM_PER_CSN) % LOCLASS_NUM_CSNS];
-    memcpy(instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data, csn, sizeof(PicopassBlock));
+    memcpy(instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data, csn, PICOPASS_BLOCK_LEN);
 
 
     uint8_t key[PICOPASS_BLOCK_LEN] = {};
     uint8_t key[PICOPASS_BLOCK_LEN] = {};
     loclass_iclass_calc_div_key(csn, picopass_iclass_key, key, false);
     loclass_iclass_calc_div_key(csn, picopass_iclass_key, key, false);
     memcpy(
     memcpy(
-        instance->data->card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data,
-        key,
-        sizeof(PicopassBlock));
+        instance->data->card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data, key, PICOPASS_BLOCK_LEN);
 
 
     picopass_listener_init_cipher_state_key(instance, key);
     picopass_listener_init_cipher_state_key(instance, key);
 }
 }
@@ -122,7 +120,7 @@ PicopassListenerCommand
             bit_buffer_copy_bytes(
             bit_buffer_copy_bytes(
                 instance->tmp_buffer,
                 instance->tmp_buffer,
                 instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
                 instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
-                sizeof(PicopassBlock));
+                PICOPASS_BLOCK_LEN);
         } else {
         } else {
             picopass_listener_write_anticoll_csn(instance, instance->tmp_buffer);
             picopass_listener_write_anticoll_csn(instance, instance->tmp_buffer);
         }
         }
@@ -143,7 +141,7 @@ PicopassListenerCommand
         bit_buffer_copy_bytes(
         bit_buffer_copy_bytes(
             instance->tx_buffer,
             instance->tx_buffer,
             instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
             instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
-            sizeof(PicopassBlock));
+            PICOPASS_BLOCK_LEN);
 
 
         PicopassError error = picopass_listener_send_frame(instance, instance->tx_buffer);
         PicopassError error = picopass_listener_send_frame(instance, instance->tx_buffer);
         if(error != PicopassErrorNone) {
         if(error != PicopassErrorNone) {
@@ -181,7 +179,7 @@ PicopassListenerCommand
             bit_buffer_copy_bytes(
             bit_buffer_copy_bytes(
                 instance->tx_buffer,
                 instance->tx_buffer,
                 instance->data->card_data[block_num].data,
                 instance->data->card_data[block_num].data,
-                sizeof(PicopassBlock));
+                PICOPASS_BLOCK_LEN);
         }
         }
         PicopassError error = picopass_listener_send_frame(instance, instance->tx_buffer);
         PicopassError error = picopass_listener_send_frame(instance, instance->tx_buffer);
         if(error != PicopassErrorNone) {
         if(error != PicopassErrorNone) {
@@ -216,7 +214,7 @@ static PicopassListenerCommand
 
 
         // DATA(8)
         // DATA(8)
         bit_buffer_copy_bytes(
         bit_buffer_copy_bytes(
-            instance->tx_buffer, instance->data->card_data[block_num].data, sizeof(PicopassBlock));
+            instance->tx_buffer, instance->data->card_data[block_num].data, PICOPASS_BLOCK_LEN);
         NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer);
         NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer);
         if(error != NfcErrorNone) {
         if(error != NfcErrorNone) {
             FURI_LOG_D(TAG, "Failed to tx read check response: %d", error);
             FURI_LOG_D(TAG, "Failed to tx read check response: %d", error);
@@ -508,7 +506,7 @@ PicopassListenerCommand
         case PICOPASS_SECURE_KC_BLOCK_INDEX:
         case PICOPASS_SECURE_KC_BLOCK_INDEX:
             if(!pers_mode && secured) {
             if(!pers_mode && secured) {
                 new_block = instance->data->card_data[block_num];
                 new_block = instance->data->card_data[block_num];
-                for(size_t i = 0; i < sizeof(PicopassBlock); i++) {
+                for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
                     new_block.data[i] ^= rx_data[i + 2];
                     new_block.data[i] ^= rx_data[i + 2];
                 }
                 }
                 break;
                 break;
@@ -516,7 +514,7 @@ PicopassListenerCommand
             // Use default case when in personalisation mode
             // Use default case when in personalisation mode
             // fallthrough
             // fallthrough
         default:
         default:
-            memcpy(new_block.data, &rx_data[2], sizeof(PicopassBlock));
+            memcpy(new_block.data, &rx_data[2], PICOPASS_BLOCK_LEN);
             break;
             break;
         }
         }
 
 
@@ -537,7 +535,7 @@ PicopassListenerCommand
             bit_buffer_copy_bytes(
             bit_buffer_copy_bytes(
                 instance->tx_buffer,
                 instance->tx_buffer,
                 instance->data->card_data[block_num].data,
                 instance->data->card_data[block_num].data,
-                sizeof(PicopassBlock));
+                PICOPASS_BLOCK_LEN);
         }
         }
 
 
         PicopassError error = picopass_listener_send_frame(instance, instance->tx_buffer);
         PicopassError error = picopass_listener_send_frame(instance, instance->tx_buffer);
@@ -572,12 +570,12 @@ PicopassListenerCommand
         for(uint8_t i = block_start; i < block_start + 4; i++) {
         for(uint8_t i = block_start; i < block_start + 4; i++) {
             if(secured &&
             if(secured &&
                ((i == PICOPASS_SECURE_KD_BLOCK_INDEX) || (i == PICOPASS_SECURE_KC_BLOCK_INDEX))) {
                ((i == PICOPASS_SECURE_KD_BLOCK_INDEX) || (i == PICOPASS_SECURE_KC_BLOCK_INDEX))) {
-                for(size_t j = 0; j < sizeof(PicopassBlock); j++) {
+                for(size_t j = 0; j < PICOPASS_BLOCK_LEN; j++) {
                     bit_buffer_append_byte(instance->tx_buffer, 0xff);
                     bit_buffer_append_byte(instance->tx_buffer, 0xff);
                 }
                 }
             } else {
             } else {
                 bit_buffer_append_bytes(
                 bit_buffer_append_bytes(
-                    instance->tx_buffer, instance->data->card_data[i].data, sizeof(PicopassBlock));
+                    instance->tx_buffer, instance->data->card_data[i].data, PICOPASS_BLOCK_LEN);
             }
             }
         }
         }
 
 

+ 2 - 2
protocol/picopass_listener_i.c

@@ -23,14 +23,14 @@ void picopass_listener_init_cipher_state_key(PicopassListener* instance, const u
     memcpy(
     memcpy(
         cc,
         cc,
         instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data,
         instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data,
-        sizeof(PicopassBlock));
+        PICOPASS_BLOCK_LEN);
 
 
     instance->cipher_state = loclass_opt_doTagMAC_1(cc, key);
     instance->cipher_state = loclass_opt_doTagMAC_1(cc, key);
 }
 }
 
 
 void picopass_listener_init_cipher_state(PicopassListener* instance) {
 void picopass_listener_init_cipher_state(PicopassListener* instance) {
     uint8_t key[PICOPASS_BLOCK_LEN] = {};
     uint8_t key[PICOPASS_BLOCK_LEN] = {};
-    memcpy(key, instance->data->card_data[instance->key_block_num].data, sizeof(PicopassBlock));
+    memcpy(key, instance->data->card_data[instance->key_block_num].data, PICOPASS_BLOCK_LEN);
 
 
     picopass_listener_init_cipher_state_key(instance, key);
     picopass_listener_init_cipher_state_key(instance, key);
 }
 }

+ 35 - 47
protocol/picopass_poller.c

@@ -70,6 +70,20 @@ NfcCommand picopass_poller_select_handler(PicopassPoller* instance) {
     return command;
     return command;
 }
 }
 
 
+void picopass_poller_print_block(char* str, PicopassBlock block) {
+    FURI_LOG_D(
+        TAG,
+        str,
+        block.data[0],
+        block.data[1],
+        block.data[2],
+        block.data[3],
+        block.data[4],
+        block.data[5],
+        block.data[6],
+        block.data[7]);
+}
+
 NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
 NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
     NfcCommand command = NfcCommandContinue;
     NfcCommand command = NfcCommandContinue;
     PicopassError error = PicopassErrorNone;
     PicopassError error = PicopassErrorNone;
@@ -79,17 +93,10 @@ NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
             instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
             instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
             instance->serial_num.data,
             instance->serial_num.data,
             sizeof(PicopassSerialNum));
             sizeof(PicopassSerialNum));
-        FURI_LOG_D(
-            TAG,
+        instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].valid = true;
+        picopass_poller_print_block(
             "csn %02x%02x%02x%02x%02x%02x%02x%02x",
             "csn %02x%02x%02x%02x%02x%02x%02x%02x",
-            instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data[0],
-            instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data[1],
-            instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data[2],
-            instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data[3],
-            instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data[4],
-            instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data[5],
-            instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data[6],
-            instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data[7]);
+            instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX]);
 
 
         PicopassBlock block = {};
         PicopassBlock block = {};
         error = picopass_poller_read_block(instance, PICOPASS_CONFIG_BLOCK_INDEX, &block);
         error = picopass_poller_read_block(instance, PICOPASS_CONFIG_BLOCK_INDEX, &block);
@@ -100,18 +107,11 @@ NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
         memcpy(
         memcpy(
             instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data,
             instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data,
             block.data,
             block.data,
-            sizeof(PicopassBlock));
-        FURI_LOG_D(
-            TAG,
+            PICOPASS_BLOCK_LEN);
+        instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].valid = true;
+        picopass_poller_print_block(
             "config %02x%02x%02x%02x%02x%02x%02x%02x",
             "config %02x%02x%02x%02x%02x%02x%02x%02x",
-            instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[0],
-            instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[1],
-            instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[2],
-            instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[3],
-            instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[4],
-            instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[5],
-            instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[6],
-            instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[7]);
+            instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX]);
 
 
         error = picopass_poller_read_block(instance, PICOPASS_SECURE_EPURSE_BLOCK_INDEX, &block);
         error = picopass_poller_read_block(instance, PICOPASS_SECURE_EPURSE_BLOCK_INDEX, &block);
         if(error != PicopassErrorNone) {
         if(error != PicopassErrorNone) {
@@ -121,18 +121,11 @@ NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
         memcpy(
         memcpy(
             instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data,
             instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data,
             block.data,
             block.data,
-            sizeof(PicopassBlock));
-        FURI_LOG_D(
-            TAG,
+            PICOPASS_BLOCK_LEN);
+        instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].valid = true;
+        picopass_poller_print_block(
             "epurse %02x%02x%02x%02x%02x%02x%02x%02x",
             "epurse %02x%02x%02x%02x%02x%02x%02x%02x",
-            instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[0],
-            instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[1],
-            instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[2],
-            instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[3],
-            instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[4],
-            instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[5],
-            instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[6],
-            instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data[7]);
+            instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX]);
 
 
         error = picopass_poller_read_block(instance, PICOPASS_SECURE_AIA_BLOCK_INDEX, &block);
         error = picopass_poller_read_block(instance, PICOPASS_SECURE_AIA_BLOCK_INDEX, &block);
         if(error != PicopassErrorNone) {
         if(error != PicopassErrorNone) {
@@ -142,18 +135,11 @@ NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
         memcpy(
         memcpy(
             instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
             instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
             block.data,
             block.data,
-            sizeof(PicopassBlock));
-        FURI_LOG_D(
-            TAG,
+            PICOPASS_BLOCK_LEN);
+        instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].valid = true;
+        picopass_poller_print_block(
             "aia %02x%02x%02x%02x%02x%02x%02x%02x",
             "aia %02x%02x%02x%02x%02x%02x%02x%02x",
-            instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[0],
-            instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[1],
-            instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[2],
-            instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[3],
-            instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[4],
-            instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[5],
-            instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[6],
-            instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[7]);
+            instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX]);
 
 
         instance->state = PicopassPollerStateCheckSecurity;
         instance->state = PicopassPollerStateCheckSecurity;
     } while(false);
     } while(false);
@@ -188,12 +174,12 @@ NfcCommand picopass_poller_check_security(PicopassPoller* instance) {
 
 
     // Thank you proxmark!
     // Thank you proxmark!
     PicopassBlock temp_block = {};
     PicopassBlock temp_block = {};
-    memset(temp_block.data, 0xff, sizeof(PicopassBlock));
+    memset(temp_block.data, 0xff, PICOPASS_BLOCK_LEN);
     instance->data->pacs.legacy =
     instance->data->pacs.legacy =
         (memcmp(
         (memcmp(
              instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
              instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
              temp_block.data,
              temp_block.data,
-             sizeof(PicopassBlock)) == 0);
+             PICOPASS_BLOCK_LEN) == 0);
 
 
     temp_block.data[3] = 0x00;
     temp_block.data[3] = 0x00;
     temp_block.data[4] = 0x06;
     temp_block.data[4] = 0x06;
@@ -201,7 +187,7 @@ NfcCommand picopass_poller_check_security(PicopassPoller* instance) {
         (memcmp(
         (memcmp(
              instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
              instance->data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
              temp_block.data,
              temp_block.data,
-             sizeof(PicopassBlock)) == 0);
+             PICOPASS_BLOCK_LEN) == 0);
 
 
     if(instance->data->pacs.se_enabled) {
     if(instance->data->pacs.se_enabled) {
         FURI_LOG_D(TAG, "SE enabled");
         FURI_LOG_D(TAG, "SE enabled");
@@ -401,6 +387,7 @@ NfcCommand picopass_poller_auth_handler(PicopassPoller* instance) {
             if(instance->mode == PicopassPollerModeRead) {
             if(instance->mode == PicopassPollerModeRead) {
                 memcpy(
                 memcpy(
                     instance->data->pacs.key, instance->event_data.req_key.key, PICOPASS_KEY_LEN);
                     instance->data->pacs.key, instance->event_data.req_key.key, PICOPASS_KEY_LEN);
+                instance->data->card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid = true;
                 instance->data->pacs.elite_kdf = instance->event_data.req_key.is_elite_key;
                 instance->data->pacs.elite_kdf = instance->event_data.req_key.is_elite_key;
                 picopass_poller_prepare_read(instance);
                 picopass_poller_prepare_read(instance);
                 instance->state = PicopassPollerStateReadBlock;
                 instance->state = PicopassPollerStateReadBlock;
@@ -457,7 +444,8 @@ NfcCommand picopass_poller_read_block_handler(PicopassPoller* instance) {
         memcpy(
         memcpy(
             instance->data->card_data[instance->current_block].data,
             instance->data->card_data[instance->current_block].data,
             block.data,
             block.data,
-            sizeof(PicopassBlock));
+            PICOPASS_BLOCK_LEN);
+        instance->data->card_data[instance->current_block].valid = true;
         instance->current_block++;
         instance->current_block++;
     } while(false);
     } while(false);
 
 

+ 3 - 3
protocol/picopass_poller_i.c

@@ -122,11 +122,11 @@ PicopassError
             instance, instance->tx_buffer, instance->rx_buffer, PICOPASS_POLLER_FWT_FC);
             instance, instance->tx_buffer, instance->rx_buffer, PICOPASS_POLLER_FWT_FC);
         if(ret != PicopassErrorNone) break;
         if(ret != PicopassErrorNone) break;
 
 
-        if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(PicopassBlock)) {
+        if(bit_buffer_get_size_bytes(instance->rx_buffer) != PICOPASS_BLOCK_LEN) {
             ret = PicopassErrorProtocol;
             ret = PicopassErrorProtocol;
             break;
             break;
         }
         }
-        bit_buffer_write_bytes(instance->rx_buffer, block->data, sizeof(PicopassBlock));
+        bit_buffer_write_bytes(instance->rx_buffer, block->data, PICOPASS_BLOCK_LEN);
     } while(false);
     } while(false);
 
 
     return ret;
     return ret;
@@ -206,7 +206,7 @@ PicopassError picopass_poller_write_block(
         bit_buffer_reset(instance->tx_buffer);
         bit_buffer_reset(instance->tx_buffer);
         bit_buffer_append_byte(instance->tx_buffer, RFAL_PICOPASS_CMD_UPDATE);
         bit_buffer_append_byte(instance->tx_buffer, RFAL_PICOPASS_CMD_UPDATE);
         bit_buffer_append_byte(instance->tx_buffer, block_num);
         bit_buffer_append_byte(instance->tx_buffer, block_num);
-        bit_buffer_append_bytes(instance->tx_buffer, block->data, sizeof(PicopassBlock));
+        bit_buffer_append_bytes(instance->tx_buffer, block->data, PICOPASS_BLOCK_LEN);
         bit_buffer_append_bytes(instance->tx_buffer, mac->data, sizeof(PicopassMac));
         bit_buffer_append_bytes(instance->tx_buffer, mac->data, sizeof(PicopassMac));
 
 
         NfcError error = nfc_poller_trx(
         NfcError error = nfc_poller_trx(

+ 4 - 1
scenes/picopass_scene_loclass.c

@@ -44,12 +44,15 @@ void picopass_scene_loclass_on_enter(void* context) {
     const uint8_t config_block[PICOPASS_BLOCK_LEN] = {
     const uint8_t config_block[PICOPASS_BLOCK_LEN] = {
         0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C};
         0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C};
     memcpy(data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data, config_block, sizeof(config_block));
     memcpy(data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data, config_block, sizeof(config_block));
+    data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].valid = true;
 
 
     const uint8_t epurse[PICOPASS_BLOCK_LEN] = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
     const uint8_t epurse[PICOPASS_BLOCK_LEN] = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
     memcpy(data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data, epurse, sizeof(epurse));
     memcpy(data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data, epurse, sizeof(epurse));
+    data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].valid = true;
 
 
     const uint8_t aia[PICOPASS_BLOCK_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
     const uint8_t aia[PICOPASS_BLOCK_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
     memcpy(data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data, aia, sizeof(aia));
     memcpy(data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].data, aia, sizeof(aia));
+    data->card_data[PICOPASS_SECURE_AIA_BLOCK_INDEX].valid = true;
 
 
     picopass->listener = picopass_listener_alloc(picopass->nfc, data);
     picopass->listener = picopass_listener_alloc(picopass->nfc, data);
     free(data);
     free(data);
@@ -100,4 +103,4 @@ void picopass_scene_loclass_on_exit(void* context) {
     picopass_blink_stop(picopass);
     picopass_blink_stop(picopass);
 
 
     loclass_reset(picopass->loclass);
     loclass_reset(picopass->loclass);
-}
+}