diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 7d51f6c6e..6c6e230f0 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -445,43 +445,35 @@ static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPoller* instance) { NfcCommand command = NfcCommandContinue; FURI_LOG_D(TAG, "MfulC auth"); - if(mf_ultralight_support_feature( - instance->feature_set, MfUltralightFeatureSupportAuthenticate)) { - instance->mfu_event.type = MfUltralightPollerEventTypeAuthRequest; - 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; - 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; + do { + if(mf_ultralight_support_feature( + instance->feature_set, MfUltralightFeatureSupportAuthenticate)) { + instance->mfu_event.type = MfUltralightPollerEventTypeAuthRequest; - 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; + 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->error = + mf_ultralight_poller_auth_tdes(instance, &instance->auth_context); - 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) { + if(instance->error == MfUltralightErrorNone && + instance->auth_context.auth_success) { FURI_LOG_D(TAG, "Auth success"); + } else { + FURI_LOG_D(TAG, "Auth failed"); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); } - } while(false); - - if(instance->error != MfUltralightErrorNone || !instance->auth_context.auth_success) { - FURI_LOG_D(TAG, "Auth failed"); - iso14443_3a_poller_halt(instance->iso14443_3a_poller); + } else { + // We assume here that it is card read without explicitly provided key + // So we try to auth with default one + instance->state = MfUltralightPollerStateTryDefaultMfulCKey; + break; } } - } - instance->state = MfUltralightPollerStateReadPages; + instance->state = MfUltralightPollerStateReadPages; + } while(false); return command; } @@ -578,6 +570,40 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll return NfcCommandContinue; } +static NfcCommand + mf_ultralight_poller_handler_try_default_ultralight_c_key(MfUltralightPoller* instance) { + do { + if(!mf_ultralight_support_feature( + instance->feature_set, MfUltralightFeatureSupportAuthenticate)) { + break; + } + + if(instance->auth_context.auth_success) { + break; + } + + FURI_LOG_D(TAG, "Trying authentication with default 3DES key"); + + memcpy( + &instance->auth_context.tdes_key.data, + MF_ULTRALIGHT_C_DEFAULT_KEY, + MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE); + + instance->error = mf_ultralight_poller_auth_tdes(instance, &instance->auth_context); + + if(instance->error == MfUltralightErrorNone && instance->auth_context.auth_success) { + FURI_LOG_D(TAG, "Default 3DES key detected"); + } else { + FURI_LOG_D(TAG, "Authentication attempt with default 3DES key failed"); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); + } + + } while(false); + + instance->state = MfUltralightPollerStateReadPages; + return NfcCommandContinue; +} + static NfcCommand mf_ultralight_poller_handler_check_mfuc_auth_status(MfUltralightPoller* instance) { instance->state = MfUltralightPollerStateReadSuccess; @@ -742,6 +768,8 @@ static const MfUltralightPollerReadHandler mf_ultralight_poller_handler_read_tearing_flags, [MfUltralightPollerStateAuth] = mf_ultralight_poller_handler_auth, [MfUltralightPollerStateTryDefaultPass] = mf_ultralight_poller_handler_try_default_pass, + [MfUltralightPollerStateTryDefaultMfulCKey] = + mf_ultralight_poller_handler_try_default_ultralight_c_key, [MfUltralightPollerStateCheckMfulCAuthStatus] = mf_ultralight_poller_handler_check_mfuc_auth_status, [MfUltralightPollerStateAuthMfulC] = mf_ultralight_poller_handler_auth_ultralight_c, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index e50017324..661c6db74 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -81,6 +81,19 @@ MfUltralightError mf_ultralight_poller_auth_pwd( MfUltralightPoller* instance, MfUltralightPollerAuthContext* data); +/** + * @brief Perform 3DES authentication with key. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in, out] data pointer to the authentication context. + * @return MfUltralightErrorNone on success, an error code on failure. + */ +MfUltralightError mf_ultralight_poller_auth_tdes( + MfUltralightPoller* instance, + MfUltralightPollerAuthContext* data); + /** * @brief Start authentication procedure. * 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 d84377612..fdafaf37d 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -1,6 +1,7 @@ #include "mf_ultralight_poller_i.h" #include +#include #define TAG "MfUltralightPoller" @@ -62,6 +63,38 @@ MfUltralightError mf_ultralight_poller_auth_pwd( return ret; } +MfUltralightError mf_ultralight_poller_auth_tdes( + MfUltralightPoller* instance, + MfUltralightPollerAuthContext* data) { + furi_check(instance); + furi_check(data); + + MfUltralightError ret = MfUltralightErrorNone; + + 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)); + + ret = mf_ultralight_poller_authenticate_start(instance, RndA, output); + + if(ret != MfUltralightErrorNone) { + return ret; + } + + 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; + ret = mf_ultralight_poller_authenticate_end(instance, RndB, output, decoded_shifted_RndA); + + if(ret != MfUltralightErrorNone) { + return ret; + } + + mf_ultralight_3des_shift_data(RndA); + data->auth_success = (memcmp(RndA, decoded_shifted_RndA, sizeof(decoded_shifted_RndA)) == 0); + + return ret; +} + static MfUltralightError mf_ultralight_poller_send_authenticate_cmd( MfUltralightPoller* instance, const uint8_t* cmd, @@ -134,7 +167,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 +178,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 +212,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 6880a0c43..7db9a77d9 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -59,6 +59,7 @@ typedef enum { MfUltralightPollerStateAuthMfulC, MfUltralightPollerStateReadPages, MfUltralightPollerStateTryDefaultPass, + MfUltralightPollerStateTryDefaultMfulCKey, MfUltralightPollerStateCheckMfulCAuthStatus, MfUltralightPollerStateReadFailed, MfUltralightPollerStateReadSuccess, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 7c4dca564..101a9f1bb 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -2741,6 +2741,7 @@ Function,+,mf_ultralight_is_equal,_Bool,"const MfUltralightData*, const MfUltral Function,+,mf_ultralight_is_page_pwd_or_pack,_Bool,"MfUltralightType, uint16_t" Function,+,mf_ultralight_load,_Bool,"MfUltralightData*, FlipperFormat*, uint32_t" Function,+,mf_ultralight_poller_auth_pwd,MfUltralightError,"MfUltralightPoller*, MfUltralightPollerAuthContext*" +Function,+,mf_ultralight_poller_auth_tdes,MfUltralightError,"MfUltralightPoller*, MfUltralightPollerAuthContext*" Function,+,mf_ultralight_poller_authenticate_end,MfUltralightError,"MfUltralightPoller*, const uint8_t*, const uint8_t*, uint8_t*" Function,+,mf_ultralight_poller_authenticate_start,MfUltralightError,"MfUltralightPoller*, const uint8_t*, uint8_t*" Function,+,mf_ultralight_poller_read_counter,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightCounter*"