diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 6edbc06a2..daf9bedea 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -15,6 +15,7 @@ enum { SubmenuIndexUnlockByReader, SubmenuIndexUnlockByPassword, SubmenuIndexWrite, + SubmenuIndexDictAttack }; enum { @@ -150,7 +151,8 @@ static NfcCommand } if(!mf_ultralight_event->data->auth_context.skip_auth) { mf_ultralight_event->data->auth_context.password = instance->mf_ul_auth->password; - mf_ultralight_event->data->auth_context.tdes_key = instance->mf_ul_auth->tdes_key; + mf_ultralight_event->data->key_request_data.key = instance->mf_ul_auth->tdes_key; + // TODO: Key provided attribute is not set } } else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthSuccess) { instance->mf_ul_auth->pack = mf_ultralight_event->data->auth_context.pack; @@ -201,6 +203,14 @@ static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instanc SubmenuIndexUnlock, nfc_protocol_support_common_submenu_callback, instance); + if(data->type == MfUltralightTypeMfulC) { + submenu_add_item( + submenu, + "Unlock with Dictionary", + SubmenuIndexDictAttack, + nfc_protocol_support_common_submenu_callback, + instance); + } } else if( data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 || data->type == MfUltralightTypeNTAG216 || data->type == MfUltralightTypeUL11 || @@ -269,6 +279,12 @@ static bool nfc_scene_read_and_saved_menu_on_event_mf_ultralight( } else if(event.event == SubmenuIndexCommonEdit) { scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); consumed = true; + } else if(event.event == SubmenuIndexDictAttack) { + if(!scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneMfUltralightCDictAttack)) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightCDictAttack); + } + consumed = true; } } return consumed; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index f48348c17..c697544c7 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -181,10 +181,6 @@ MfUltralightPoller* mf_ultralight_poller_alloc(Iso14443_3aPoller* iso14443_3a_po instance->general_event.protocol = NfcProtocolMfUltralight; instance->general_event.event_data = &instance->mfu_event; instance->general_event.instance = instance; - - instance->dict_attack_ctx.auth_success = false; - instance->dict_attack_ctx.is_card_present = false; - mbedtls_des3_init(&instance->des_context); return instance; } @@ -255,7 +251,7 @@ static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); instance->state = MfUltralightPollerStateGetFeatureSet; } else { - FURI_LOG_D(TAG, "Didn't response. Check Ultralight C"); + FURI_LOG_D(TAG, "Didn't respond. Check Ultralight C"); iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->state = MfUltralightPollerStateDetectMfulC; } @@ -270,7 +266,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPo instance->data->type = MfUltralightTypeMfulC; instance->state = MfUltralightPollerStateGetFeatureSet; } else { - FURI_LOG_D(TAG, "Didn't response. Check NTAG 203"); + FURI_LOG_D(TAG, "Didn't respond. Check NTAG 203"); instance->state = MfUltralightPollerStateDetectNtag203; } iso14443_3a_poller_halt(instance->iso14443_3a_poller); @@ -456,7 +452,28 @@ static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPol command = instance->callback(instance->general_event, instance->context); if(!instance->mfu_event.data->auth_context.skip_auth) { FURI_LOG_D(TAG, "Trying to authenticate with 3des key"); - instance->auth_context.tdes_key = instance->mfu_event.data->auth_context.tdes_key; + instance->auth_context.tdes_key = instance->mfu_event.data->key_request_data.key; + instance->auth_context.auth_success = false; + // For debugging + FURI_LOG_D( + "TAG", + "Key data: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + instance->auth_context.tdes_key.data[0], + instance->auth_context.tdes_key.data[1], + instance->auth_context.tdes_key.data[2], + instance->auth_context.tdes_key.data[3], + instance->auth_context.tdes_key.data[4], + instance->auth_context.tdes_key.data[5], + instance->auth_context.tdes_key.data[6], + instance->auth_context.tdes_key.data[7], + instance->auth_context.tdes_key.data[8], + instance->auth_context.tdes_key.data[9], + instance->auth_context.tdes_key.data[10], + instance->auth_context.tdes_key.data[11], + instance->auth_context.tdes_key.data[12], + instance->auth_context.tdes_key.data[13], + instance->auth_context.tdes_key.data[14], + instance->auth_context.tdes_key.data[15]); do { uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE]; uint8_t RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0}; @@ -473,20 +490,41 @@ static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPol mf_ultralight_3des_shift_data(RndA); instance->auth_context.auth_success = (memcmp(RndA, decoded_shifted_RndA, sizeof(decoded_shifted_RndA)) == 0); - if(instance->auth_context.auth_success) { - FURI_LOG_D(TAG, "Auth success"); + FURI_LOG_E(TAG, "Auth success"); + if(instance->mode == MfUltralightPollerModeDictAttack) { + memcpy( + &instance->data->page[44], + instance->auth_context.tdes_key.data, + MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE); + instance->data->pages_read = instance->pages_total; + instance->pages_read = instance->pages_total; + instance->state = MfUltralightPollerStateReadSuccess; + } } } while(false); - if(instance->error != MfUltralightErrorNone || !instance->auth_context.auth_success) { - FURI_LOG_D(TAG, "Auth failed"); + FURI_LOG_E(TAG, "Auth failed"); iso14443_3a_poller_halt(instance->iso14443_3a_poller); + if(instance->mode == MfUltralightPollerModeDictAttack) { + // Not needed? We already do a callback earlier? + instance->mfu_event.type = MfUltralightPollerEventTypeRequestKey; + command = instance->callback(instance->general_event, instance->context); + if(!instance->mfu_event.data->key_request_data.key_provided) { + instance->state = MfUltralightPollerStateReadPages; + } else { + instance->auth_context.tdes_key = + instance->mfu_event.data->key_request_data.key; + instance->state = MfUltralightPollerStateAuthMfulC; + } + } } } } - instance->state = MfUltralightPollerStateReadPages; - + // Regression review + if(instance->mode != MfUltralightPollerModeDictAttack) { + instance->state = MfUltralightPollerStateReadPages; + } return command; } @@ -509,12 +547,16 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in instance->error = mf_ultralight_poller_read_page(instance, start_page, &data); } + // Regression review + const uint8_t read_cnt = instance->data->type == MfUltralightTypeMfulC ? 1 : 4; if(instance->error == MfUltralightErrorNone) { - if(start_page < instance->pages_total) { - FURI_LOG_D(TAG, "Read page %d success", start_page); - instance->data->page[start_page] = data.page[0]; - instance->pages_read++; - instance->data->pages_read = instance->pages_read; + for(size_t i = 0; i < read_cnt; i++) { + if(start_page + i < instance->pages_total) { + FURI_LOG_D(TAG, "Read page %d success", start_page + i); + instance->data->page[start_page + i] = data.page[i]; + instance->pages_read++; + instance->data->pages_read = instance->pages_read; + } } if(instance->pages_read == instance->pages_total) { @@ -523,7 +565,7 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in } else { if(instance->data->type == MfUltralightTypeMfulC && !mf_ultralight_3des_key_valid(instance->data)) { - instance->state = MfUltralightPollerStateDictAttack; + instance->state = MfUltralightPollerStateCheckMfulCAuthStatus; } else { FURI_LOG_D(TAG, "Read page %d failed", instance->pages_read); if(instance->pages_read) { @@ -732,63 +774,6 @@ static NfcCommand mf_ultralight_poller_handler_write_success(MfUltralightPoller* return command; } -static NfcCommand mf_ultralight_poller_handler_dict_attack(MfUltralightPoller* instance) { - NfcCommand command = NfcCommandContinue; - const MfUltralightData* tag_data = instance->data; - uint32_t features = mf_ultralight_get_feature_support_set(tag_data->type); - FURI_LOG_D(TAG, "Dict Attack"); - do { - if(!mf_ultralight_support_feature(features, MfUltralightFeatureSupportAuthenticate)) { - instance->error = MfUltralightErrorProtocol; - instance->state = MfUltralightPollerStateReadFailed; - break; - } - - instance->dict_attack_ctx.is_card_present = true; - instance->mfu_event.type = MfUltralightPollerEventTypeRequestKey; - command = instance->callback(instance->general_event, instance->context); - if(!instance->mfu_event.data->key_request_data.key_provided) { - instance->state = MfUltralightPollerStateReadSuccess; - break; - } - - FURI_LOG_D(TAG, "Trying next 3DES key"); - instance->error = MfUltralightErrorNone; - instance->auth_context.auth_success = false; - instance->auth_context.tdes_key = instance->mfu_event.data->key_request_data.key; - do { - uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE]; - uint8_t RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0}; - furi_hal_random_fill_buf(RndA, sizeof(RndA)); - instance->error = mf_ultralight_poller_authenticate_start(instance, RndA, output); - if(instance->error != MfUltralightErrorNone) break; - - uint8_t decoded_shifted_RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0}; - const uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET; - instance->error = mf_ultralight_poller_authenticate_end( - instance, RndB, output, decoded_shifted_RndA); - if(instance->error != MfUltralightErrorNone) break; - - mf_ultralight_3des_shift_data(RndA); - instance->auth_context.auth_success = - (memcmp(RndA, decoded_shifted_RndA, sizeof(decoded_shifted_RndA)) == 0); - if(instance->auth_context.auth_success) { - FURI_LOG_D(TAG, "Dict attack success"); - instance->state = MfUltralightPollerStateReadPages; - instance->dict_attack_ctx.auth_success = true; - break; - } - } while(false); - - if(!instance->auth_context.auth_success) { - FURI_LOG_D(TAG, "Dict attack auth failed"); - iso14443_3a_poller_halt(instance->iso14443_3a_poller); - } - } while(false); - - return command; -} - static const MfUltralightPollerReadHandler mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = { [MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle, @@ -814,8 +799,6 @@ static const MfUltralightPollerReadHandler [MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages, [MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail, [MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success, - [MfUltralightPollerStateDictAttack] = mf_ultralight_poller_handler_dict_attack, - }; static NfcCommand mf_ultralight_poller_run(NfcGenericEvent event, void* context) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 141ab6c46..c769273ec 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -134,7 +134,7 @@ MfUltralightError mf_ultralight_poller_authenticate_start( uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET; mf_ultralight_3des_decrypt( &instance->des_context, - instance->mfu_event.data->auth_context.tdes_key.data, + instance->auth_context.tdes_key.data, iv, encRndB, sizeof(encRndB), @@ -145,7 +145,7 @@ MfUltralightError mf_ultralight_poller_authenticate_start( mf_ultralight_3des_encrypt( &instance->des_context, - instance->mfu_event.data->auth_context.tdes_key.data, + instance->auth_context.tdes_key.data, encRndB, output, MF_ULTRALIGHT_C_AUTH_DATA_SIZE, @@ -179,7 +179,7 @@ MfUltralightError mf_ultralight_poller_authenticate_end( mf_ultralight_3des_decrypt( &instance->des_context, - instance->mfu_event.data->auth_context.tdes_key.data, + instance->auth_context.tdes_key.data, RndB, bit_buffer_get_data(instance->rx_buffer) + 1, MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index bbd9c6c3e..b35c49aea 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -68,17 +68,10 @@ typedef enum { MfUltralightPollerStateWritePages, MfUltralightPollerStateWriteFail, MfUltralightPollerStateWriteSuccess, - MfUltralightPollerStateDictAttack, MfUltralightPollerStateNum, } MfUltralightPollerState; -typedef struct { - uint8_t sectors_total; - bool auth_success; - bool is_card_present; -} MfUltralightPollerDictAttackContext; - struct MfUltralightPoller { Iso14443_3aPoller* iso14443_3a_poller; MfUltralightPollerState state; @@ -96,7 +89,6 @@ struct MfUltralightPoller { uint8_t tearing_flag_total; uint16_t current_page; MfUltralightError error; - MfUltralightPollerDictAttackContext dict_attack_ctx; mbedtls_des3_context des_context; NfcGenericEvent general_event;