NFC: Support reading Mifare Classic key B from sector trailer, reading sector with B key where A key can't read block, Nfc Magic app not using NFC folder by default (in file select) (#2437)
* NFC: Support reading Mifare Classic key B from sector trailer and reusing it for other sectors * NFC: Fix my pointer typo * NFC: Fix reading sector with B key where A key can't read block (fixes #2413) and fix Nfc Magic app not using NFC folder by default (in file select) * NFC: Fix strange bug Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									9819306731
								
							
						
					
					
						commit
						eb5dae1cda
					
				| @ -11,6 +11,10 @@ void nfc_magic_scene_file_select_on_enter(void* context) { | |||||||
|     // Process file_select return
 |     // Process file_select return
 | ||||||
|     nfc_device_set_loading_callback(nfc_magic->nfc_dev, nfc_magic_show_loading_popup, nfc_magic); |     nfc_device_set_loading_callback(nfc_magic->nfc_dev, nfc_magic_show_loading_popup, nfc_magic); | ||||||
| 
 | 
 | ||||||
|  |     if(!furi_string_size(nfc_magic->nfc_dev->load_path)) { | ||||||
|  |         furi_string_set_str(nfc_magic->nfc_dev->load_path, NFC_APP_FOLDER); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if(nfc_file_select(nfc_magic->nfc_dev)) { |     if(nfc_file_select(nfc_magic->nfc_dev)) { | ||||||
|         if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) { |         if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) { | ||||||
|             scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm); |             scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm); | ||||||
|  | |||||||
| @ -1892,7 +1892,7 @@ Function,+,menu_free,void,Menu* | |||||||
| Function,+,menu_get_view,View*,Menu* | Function,+,menu_get_view,View*,Menu* | ||||||
| Function,+,menu_reset,void,Menu* | Function,+,menu_reset,void,Menu* | ||||||
| Function,+,menu_set_selected_item,void,"Menu*, uint32_t" | Function,+,menu_set_selected_item,void,"Menu*, uint32_t" | ||||||
| Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, MfClassicAuthContext*, uint64_t" | Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, MfClassicAuthContext*, uint64_t" | ||||||
| Function,-,mf_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" | Function,-,mf_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" | ||||||
| Function,-,mf_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" | Function,-,mf_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" | ||||||
| Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" | Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" | ||||||
|  | |||||||
| 
 | 
| @ -569,6 +569,32 @@ void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool nfc_worker_mf_get_b_key_from_sector_trailer( | ||||||
|  |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|  |     uint16_t sector, | ||||||
|  |     uint64_t key, | ||||||
|  |     uint64_t* found_key) { | ||||||
|  |     // Some access conditions allow reading B key via A key
 | ||||||
|  | 
 | ||||||
|  |     uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); | ||||||
|  | 
 | ||||||
|  |     Crypto1 crypto = {}; | ||||||
|  |     MfClassicBlock block_tmp = {}; | ||||||
|  |     MfClassicAuthContext auth_context = {.sector = sector, .key_a = MF_CLASSIC_NO_KEY, .key_b = 0}; | ||||||
|  | 
 | ||||||
|  |     furi_hal_nfc_sleep(); | ||||||
|  | 
 | ||||||
|  |     if(mf_classic_auth_attempt(tx_rx, &crypto, &auth_context, key)) { | ||||||
|  |         if(mf_classic_read_block(tx_rx, &crypto, block, &block_tmp)) { | ||||||
|  |             *found_key = nfc_util_bytes2num(&block_tmp.value[10], sizeof(uint8_t) * 6); | ||||||
|  | 
 | ||||||
|  |             return *found_key; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void nfc_worker_mf_classic_key_attack( | static void nfc_worker_mf_classic_key_attack( | ||||||
|     NfcWorker* nfc_worker, |     NfcWorker* nfc_worker, | ||||||
|     uint64_t key, |     uint64_t key, | ||||||
| @ -614,6 +640,16 @@ static void nfc_worker_mf_classic_key_attack( | |||||||
|                     mf_classic_set_key_found(data, i, MfClassicKeyA, key); |                     mf_classic_set_key_found(data, i, MfClassicKeyA, key); | ||||||
|                     FURI_LOG_D(TAG, "Key found"); |                     FURI_LOG_D(TAG, "Key found"); | ||||||
|                     nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); |                     nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); | ||||||
|  | 
 | ||||||
|  |                     uint64_t found_key; | ||||||
|  |                     if(nfc_worker_mf_get_b_key_from_sector_trailer(tx_rx, i, key, &found_key)) { | ||||||
|  |                         FURI_LOG_D(TAG, "Found B key via reading sector %d", i); | ||||||
|  |                         mf_classic_set_key_found(data, i, MfClassicKeyB, found_key); | ||||||
|  | 
 | ||||||
|  |                         if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { | ||||||
|  |                             nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) { |             if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) { | ||||||
| @ -705,6 +741,19 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { | |||||||
|                         mf_classic_set_key_found(data, i, MfClassicKeyA, key); |                         mf_classic_set_key_found(data, i, MfClassicKeyA, key); | ||||||
|                         FURI_LOG_D(TAG, "Key found"); |                         FURI_LOG_D(TAG, "Key found"); | ||||||
|                         nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); |                         nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); | ||||||
|  | 
 | ||||||
|  |                         uint64_t found_key; | ||||||
|  |                         if(nfc_worker_mf_get_b_key_from_sector_trailer( | ||||||
|  |                                &tx_rx, i, key, &found_key)) { | ||||||
|  |                             FURI_LOG_D(TAG, "Found B key via reading sector %d", i); | ||||||
|  |                             mf_classic_set_key_found(data, i, MfClassicKeyB, found_key); | ||||||
|  | 
 | ||||||
|  |                             if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { | ||||||
|  |                                 nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             nfc_worker_mf_classic_key_attack(nfc_worker, found_key, &tx_rx, i + 1); | ||||||
|  |                         } | ||||||
|                         nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); |                         nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); | ||||||
|                     } |                     } | ||||||
|                     furi_hal_nfc_sleep(); |                     furi_hal_nfc_sleep(); | ||||||
|  | |||||||
| @ -541,6 +541,7 @@ bool mf_classic_authenticate_skip_activate( | |||||||
| 
 | 
 | ||||||
| bool mf_classic_auth_attempt( | bool mf_classic_auth_attempt( | ||||||
|     FuriHalNfcTxRxContext* tx_rx, |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|  |     Crypto1* crypto, | ||||||
|     MfClassicAuthContext* auth_ctx, |     MfClassicAuthContext* auth_ctx, | ||||||
|     uint64_t key) { |     uint64_t key) { | ||||||
|     furi_assert(tx_rx); |     furi_assert(tx_rx); | ||||||
| @ -549,15 +550,14 @@ bool mf_classic_auth_attempt( | |||||||
|     bool need_halt = (auth_ctx->key_a == MF_CLASSIC_NO_KEY) && |     bool need_halt = (auth_ctx->key_a == MF_CLASSIC_NO_KEY) && | ||||||
|                      (auth_ctx->key_b == MF_CLASSIC_NO_KEY); |                      (auth_ctx->key_b == MF_CLASSIC_NO_KEY); | ||||||
| 
 | 
 | ||||||
|     Crypto1 crypto; |  | ||||||
|     if(auth_ctx->key_a == MF_CLASSIC_NO_KEY) { |     if(auth_ctx->key_a == MF_CLASSIC_NO_KEY) { | ||||||
|         // Try AUTH with key A
 |         // Try AUTH with key A
 | ||||||
|         if(mf_classic_auth( |         if(mf_classic_auth( | ||||||
|                tx_rx, |                tx_rx, | ||||||
|                mf_classic_get_first_block_num_of_sector(auth_ctx->sector), |                mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), | ||||||
|                key, |                key, | ||||||
|                MfClassicKeyA, |                MfClassicKeyA, | ||||||
|                &crypto, |                crypto, | ||||||
|                false, |                false, | ||||||
|                0)) { |                0)) { | ||||||
|             auth_ctx->key_a = key; |             auth_ctx->key_a = key; | ||||||
| @ -573,10 +573,10 @@ bool mf_classic_auth_attempt( | |||||||
|         // Try AUTH with key B
 |         // Try AUTH with key B
 | ||||||
|         if(mf_classic_auth( |         if(mf_classic_auth( | ||||||
|                tx_rx, |                tx_rx, | ||||||
|                mf_classic_get_first_block_num_of_sector(auth_ctx->sector), |                mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), | ||||||
|                key, |                key, | ||||||
|                MfClassicKeyB, |                MfClassicKeyB, | ||||||
|                &crypto, |                crypto, | ||||||
|                false, |                false, | ||||||
|                0)) { |                0)) { | ||||||
|             auth_ctx->key_b = key; |             auth_ctx->key_b = key; | ||||||
| @ -671,6 +671,9 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u | |||||||
|     do { |     do { | ||||||
|         if(blocks_read == total_blocks) break; |         if(blocks_read == total_blocks) break; | ||||||
|         if(!key_b_found) break; |         if(!key_b_found) break; | ||||||
|  |         if(key_a_found) { | ||||||
|  |             furi_hal_nfc_sleep(); | ||||||
|  |         } | ||||||
|         FURI_LOG_D(TAG, "Try to read blocks with key B"); |         FURI_LOG_D(TAG, "Try to read blocks with key B"); | ||||||
|         key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b)); |         key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b)); | ||||||
|         if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break; |         if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break; | ||||||
|  | |||||||
| @ -174,6 +174,7 @@ bool mf_classic_authenticate_skip_activate( | |||||||
| 
 | 
 | ||||||
| bool mf_classic_auth_attempt( | bool mf_classic_auth_attempt( | ||||||
|     FuriHalNfcTxRxContext* tx_rx, |     FuriHalNfcTxRxContext* tx_rx, | ||||||
|  |     Crypto1* crypto, | ||||||
|     MfClassicAuthContext* auth_ctx, |     MfClassicAuthContext* auth_ctx, | ||||||
|     uint64_t key); |     uint64_t key); | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 AloneLiberty
						AloneLiberty