[FL-2876] MFC Improvements Part 2/2 (#1868)
* Remove keys incorrectly added by the key cache * Improve responsiveness while checking for re-used keys and fix skipping keys when card is removed * Actually check if the card is completely read * Discard incorrect keys on a lower level * nfc: clean up Co-authored-by: gornekich <n.gorbadey@gmail.com>
This commit is contained in:
		
							parent
							
								
									e46e6f8ee9
								
							
						
					
					
						commit
						55f8beef9f
					
				| @ -191,7 +191,7 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont | ||||
|             uint8_t sectors_total = | ||||
|                 mf_classic_get_total_sectors_num(nfc_worker->dev_data->mf_classic_data.type); | ||||
|             FURI_LOG_I(TAG, "Read %d sectors out of %d total", sectors_read, sectors_total); | ||||
|             read_success = (sectors_read == sectors_total); | ||||
|             read_success = mf_classic_is_card_read(&nfc_worker->dev_data->mf_classic_data); | ||||
|         } | ||||
|     } while(false); | ||||
| 
 | ||||
| @ -480,6 +480,9 @@ static void nfc_worker_mf_classic_key_attack( | ||||
|     uint16_t start_sector) { | ||||
|     furi_assert(nfc_worker); | ||||
| 
 | ||||
|     bool card_found_notified = true; | ||||
|     bool card_removed_notified = false; | ||||
| 
 | ||||
|     MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; | ||||
|     uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type); | ||||
| 
 | ||||
| @ -487,36 +490,52 @@ static void nfc_worker_mf_classic_key_attack( | ||||
| 
 | ||||
|     // Check every sector's A and B keys with the given key
 | ||||
|     for(size_t i = start_sector; i < total_sectors; i++) { | ||||
|         uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i); | ||||
|         if(mf_classic_is_sector_read(data, i)) continue; | ||||
|         if(!mf_classic_is_key_found(data, i, MfClassicKeyA)) { | ||||
|             FURI_LOG_D( | ||||
|                 TAG, | ||||
|                 "Trying A key for sector %d, key: %04lx%08lx", | ||||
|                 i, | ||||
|                 (uint32_t)(key >> 32), | ||||
|                 (uint32_t)key); | ||||
|             if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) { | ||||
|                 mf_classic_set_key_found(data, i, MfClassicKeyA, key); | ||||
|                 FURI_LOG_D(TAG, "Key found"); | ||||
|                 nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); | ||||
|         furi_hal_nfc_sleep(); | ||||
|         if(furi_hal_nfc_activate_nfca(200, NULL)) { | ||||
|             furi_hal_nfc_sleep(); | ||||
|             if(!card_found_notified) { | ||||
|                 nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); | ||||
|                 card_found_notified = true; | ||||
|                 card_removed_notified = false; | ||||
|             } | ||||
|             uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i); | ||||
|             if(mf_classic_is_sector_read(data, i)) continue; | ||||
|             if(!mf_classic_is_key_found(data, i, MfClassicKeyA)) { | ||||
|                 FURI_LOG_D( | ||||
|                     TAG, | ||||
|                     "Trying A key for sector %d, key: %04lx%08lx", | ||||
|                     i, | ||||
|                     (uint32_t)(key >> 32), | ||||
|                     (uint32_t)key); | ||||
|                 if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) { | ||||
|                     mf_classic_set_key_found(data, i, MfClassicKeyA, key); | ||||
|                     FURI_LOG_D(TAG, "Key found"); | ||||
|                     nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); | ||||
|                 } | ||||
|             } | ||||
|             if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) { | ||||
|                 FURI_LOG_D( | ||||
|                     TAG, | ||||
|                     "Trying B key for sector %d, key: %04lx%08lx", | ||||
|                     i, | ||||
|                     (uint32_t)(key >> 32), | ||||
|                     (uint32_t)key); | ||||
|                 if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) { | ||||
|                     mf_classic_set_key_found(data, i, MfClassicKeyB, key); | ||||
|                     FURI_LOG_D(TAG, "Key found"); | ||||
|                     nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if(mf_classic_is_sector_read(data, i)) continue; | ||||
|             mf_classic_read_sector(tx_rx, data, i); | ||||
|         } else { | ||||
|             if(!card_removed_notified) { | ||||
|                 nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); | ||||
|                 card_removed_notified = true; | ||||
|                 card_found_notified = false; | ||||
|             } | ||||
|         } | ||||
|         if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) { | ||||
|             FURI_LOG_D( | ||||
|                 TAG, | ||||
|                 "Trying B key for sector %d, key: %04lx%08lx", | ||||
|                 i, | ||||
|                 (uint32_t)(key >> 32), | ||||
|                 (uint32_t)key); | ||||
|             if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) { | ||||
|                 mf_classic_set_key_found(data, i, MfClassicKeyB, key); | ||||
|                 FURI_LOG_D(TAG, "Key found"); | ||||
|                 nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); | ||||
|             } | ||||
|         } | ||||
|         if(mf_classic_is_sector_read(data, i)) continue; | ||||
|         mf_classic_read_sector(tx_rx, data, i); | ||||
|         if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; | ||||
|     } | ||||
| } | ||||
| @ -530,6 +549,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { | ||||
|         &nfc_worker->dev_data->mf_classic_dict_attack_data; | ||||
|     uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type); | ||||
|     uint64_t key = 0; | ||||
|     uint64_t prev_key = 0; | ||||
|     FuriHalNfcTxRxContext tx_rx = {}; | ||||
|     bool card_found_notified = true; | ||||
|     bool card_removed_notified = false; | ||||
| @ -564,6 +584,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { | ||||
|                     nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); | ||||
|                     card_found_notified = true; | ||||
|                     card_removed_notified = false; | ||||
|                     nfc_worker_mf_classic_key_attack(nfc_worker, prev_key, &tx_rx, i); | ||||
|                 } | ||||
|                 FURI_LOG_D( | ||||
|                     TAG, | ||||
| @ -600,6 +621,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { | ||||
|                 } | ||||
|                 if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; | ||||
|             } | ||||
|             memcpy(&prev_key, &key, sizeof(key)); | ||||
|         } | ||||
|         if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; | ||||
|         mf_classic_read_sector(&tx_rx, data, i); | ||||
|  | ||||
| @ -155,6 +155,16 @@ void mf_classic_set_key_found( | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { | ||||
|     furi_assert(data); | ||||
| 
 | ||||
|     if(key_type == MfClassicKeyA) { | ||||
|         FURI_BIT_CLEAR(data->key_a_mask, sector_num); | ||||
|     } else if(key_type == MfClassicKeyB) { | ||||
|         FURI_BIT_CLEAR(data->key_b_mask, sector_num); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) { | ||||
|     furi_assert(data); | ||||
| 
 | ||||
| @ -203,6 +213,18 @@ void mf_classic_get_read_sectors_and_keys( | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool mf_classic_is_card_read(MfClassicData* data) { | ||||
|     furi_assert(data); | ||||
| 
 | ||||
|     uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); | ||||
|     uint8_t sectors_read = 0; | ||||
|     uint8_t keys_found = 0; | ||||
|     mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); | ||||
|     bool card_read = (sectors_read == sectors_total) && (keys_found == sectors_total * 2); | ||||
| 
 | ||||
|     return card_read; | ||||
| } | ||||
| 
 | ||||
| static bool mf_classic_is_allowed_access_sector_trailer( | ||||
|     MfClassicEmulator* emulator, | ||||
|     uint8_t block_num, | ||||
| @ -612,7 +634,15 @@ static bool mf_classic_read_sector_with_reader( | ||||
|         } | ||||
| 
 | ||||
|         // Auth to first block in sector
 | ||||
|         if(!mf_classic_auth(tx_rx, first_block, key, key_type, crypto)) break; | ||||
|         if(!mf_classic_auth(tx_rx, first_block, key, key_type, crypto)) { | ||||
|             // Set key to MF_CLASSIC_NO_KEY to prevent further attempts
 | ||||
|             if(key_type == MfClassicKeyA) { | ||||
|                 sector_reader->key_a = MF_CLASSIC_NO_KEY; | ||||
|             } else { | ||||
|                 sector_reader->key_b = MF_CLASSIC_NO_KEY; | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|         sector->total_blocks = mf_classic_get_blocks_num_in_sector(sector_reader->sector_num); | ||||
| 
 | ||||
|         // Read blocks
 | ||||
| @ -711,6 +741,13 @@ uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data | ||||
|                     mf_classic_set_block_read(data, first_block + j, &temp_sector.block[j]); | ||||
|                 } | ||||
|                 sectors_read++; | ||||
|             } else { | ||||
|                 // Invalid key, set it to not found
 | ||||
|                 if(key_a != MF_CLASSIC_NO_KEY) { | ||||
|                     mf_classic_set_key_not_found(data, i, MfClassicKeyA); | ||||
|                 } else { | ||||
|                     mf_classic_set_key_not_found(data, i, MfClassicKeyB); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -98,12 +98,16 @@ void mf_classic_set_key_found( | ||||
|     MfClassicKey key_type, | ||||
|     uint64_t key); | ||||
| 
 | ||||
| void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); | ||||
| 
 | ||||
| bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num); | ||||
| 
 | ||||
| void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); | ||||
| 
 | ||||
| bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num); | ||||
| 
 | ||||
| bool mf_classic_is_card_read(MfClassicData* data); | ||||
| 
 | ||||
| void mf_classic_get_read_sectors_and_keys( | ||||
|     MfClassicData* data, | ||||
|     uint8_t* sectors_read, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Astra
						Astra