1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 20:49:49 +04:00

Merge pull request #898 from mishamyte/feature/ul-c-try-auth-with-default-pass

[NFC]: Ultralight C. Attempt of authentication with default key
This commit is contained in:
MMX
2025-04-29 18:37:06 +03:00
committed by GitHub
5 changed files with 109 additions and 33 deletions

View File

@@ -445,6 +445,8 @@ static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance
static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPoller* instance) { static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPoller* instance) {
NfcCommand command = NfcCommandContinue; NfcCommand command = NfcCommandContinue;
FURI_LOG_D(TAG, "MfulC auth"); FURI_LOG_D(TAG, "MfulC auth");
do {
if(mf_ultralight_support_feature( if(mf_ultralight_support_feature(
instance->feature_set, MfUltralightFeatureSupportAuthenticate)) { instance->feature_set, MfUltralightFeatureSupportAuthenticate)) {
instance->mfu_event.type = MfUltralightPollerEventTypeAuthRequest; instance->mfu_event.type = MfUltralightPollerEventTypeAuthRequest;
@@ -453,35 +455,25 @@ static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPol
if(!instance->mfu_event.data->auth_context.skip_auth) { if(!instance->mfu_event.data->auth_context.skip_auth) {
FURI_LOG_D(TAG, "Trying to authenticate with 3des key"); 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->auth_context.tdes_key;
do { instance->error =
uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE]; mf_ultralight_poller_auth_tdes(instance, &instance->auth_context);
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}; if(instance->error == MfUltralightErrorNone &&
const uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET; instance->auth_context.auth_success) {
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, "Auth success"); FURI_LOG_D(TAG, "Auth success");
} } else {
} while(false);
if(instance->error != MfUltralightErrorNone || !instance->auth_context.auth_success) {
FURI_LOG_D(TAG, "Auth failed"); FURI_LOG_D(TAG, "Auth failed");
iso14443_3a_poller_halt(instance->iso14443_3a_poller); 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; return command;
} }
@@ -578,6 +570,40 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll
return NfcCommandContinue; 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 static NfcCommand
mf_ultralight_poller_handler_check_mfuc_auth_status(MfUltralightPoller* instance) { mf_ultralight_poller_handler_check_mfuc_auth_status(MfUltralightPoller* instance) {
instance->state = MfUltralightPollerStateReadSuccess; instance->state = MfUltralightPollerStateReadSuccess;
@@ -742,6 +768,8 @@ static const MfUltralightPollerReadHandler
mf_ultralight_poller_handler_read_tearing_flags, mf_ultralight_poller_handler_read_tearing_flags,
[MfUltralightPollerStateAuth] = mf_ultralight_poller_handler_auth, [MfUltralightPollerStateAuth] = mf_ultralight_poller_handler_auth,
[MfUltralightPollerStateTryDefaultPass] = mf_ultralight_poller_handler_try_default_pass, [MfUltralightPollerStateTryDefaultPass] = mf_ultralight_poller_handler_try_default_pass,
[MfUltralightPollerStateTryDefaultMfulCKey] =
mf_ultralight_poller_handler_try_default_ultralight_c_key,
[MfUltralightPollerStateCheckMfulCAuthStatus] = [MfUltralightPollerStateCheckMfulCAuthStatus] =
mf_ultralight_poller_handler_check_mfuc_auth_status, mf_ultralight_poller_handler_check_mfuc_auth_status,
[MfUltralightPollerStateAuthMfulC] = mf_ultralight_poller_handler_auth_ultralight_c, [MfUltralightPollerStateAuthMfulC] = mf_ultralight_poller_handler_auth_ultralight_c,

View File

@@ -81,6 +81,19 @@ MfUltralightError mf_ultralight_poller_auth_pwd(
MfUltralightPoller* instance, MfUltralightPoller* instance,
MfUltralightPollerAuthContext* data); 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. * @brief Start authentication procedure.
* *

View File

@@ -1,6 +1,7 @@
#include "mf_ultralight_poller_i.h" #include "mf_ultralight_poller_i.h"
#include <furi.h> #include <furi.h>
#include <furi_hal.h>
#define TAG "MfUltralightPoller" #define TAG "MfUltralightPoller"
@@ -62,6 +63,38 @@ MfUltralightError mf_ultralight_poller_auth_pwd(
return ret; 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( static MfUltralightError mf_ultralight_poller_send_authenticate_cmd(
MfUltralightPoller* instance, MfUltralightPoller* instance,
const uint8_t* cmd, 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; uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET;
mf_ultralight_3des_decrypt( mf_ultralight_3des_decrypt(
&instance->des_context, &instance->des_context,
instance->mfu_event.data->auth_context.tdes_key.data, instance->auth_context.tdes_key.data,
iv, iv,
encRndB, encRndB,
sizeof(encRndB), sizeof(encRndB),
@@ -145,7 +178,7 @@ MfUltralightError mf_ultralight_poller_authenticate_start(
mf_ultralight_3des_encrypt( mf_ultralight_3des_encrypt(
&instance->des_context, &instance->des_context,
instance->mfu_event.data->auth_context.tdes_key.data, instance->auth_context.tdes_key.data,
encRndB, encRndB,
output, output,
MF_ULTRALIGHT_C_AUTH_DATA_SIZE, MF_ULTRALIGHT_C_AUTH_DATA_SIZE,
@@ -179,7 +212,7 @@ MfUltralightError mf_ultralight_poller_authenticate_end(
mf_ultralight_3des_decrypt( mf_ultralight_3des_decrypt(
&instance->des_context, &instance->des_context,
instance->mfu_event.data->auth_context.tdes_key.data, instance->auth_context.tdes_key.data,
RndB, RndB,
bit_buffer_get_data(instance->rx_buffer) + 1, bit_buffer_get_data(instance->rx_buffer) + 1,
MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE, MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE,

View File

@@ -59,6 +59,7 @@ typedef enum {
MfUltralightPollerStateAuthMfulC, MfUltralightPollerStateAuthMfulC,
MfUltralightPollerStateReadPages, MfUltralightPollerStateReadPages,
MfUltralightPollerStateTryDefaultPass, MfUltralightPollerStateTryDefaultPass,
MfUltralightPollerStateTryDefaultMfulCKey,
MfUltralightPollerStateCheckMfulCAuthStatus, MfUltralightPollerStateCheckMfulCAuthStatus,
MfUltralightPollerStateReadFailed, MfUltralightPollerStateReadFailed,
MfUltralightPollerStateReadSuccess, MfUltralightPollerStateReadSuccess,

View File

@@ -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_is_page_pwd_or_pack,_Bool,"MfUltralightType, uint16_t"
Function,+,mf_ultralight_load,_Bool,"MfUltralightData*, FlipperFormat*, uint32_t" Function,+,mf_ultralight_load,_Bool,"MfUltralightData*, FlipperFormat*, uint32_t"
Function,+,mf_ultralight_poller_auth_pwd,MfUltralightError,"MfUltralightPoller*, MfUltralightPollerAuthContext*" 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_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_authenticate_start,MfUltralightError,"MfUltralightPoller*, const uint8_t*, uint8_t*"
Function,+,mf_ultralight_poller_read_counter,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightCounter*" Function,+,mf_ultralight_poller_read_counter,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightCounter*"
1 entry status name type params
2741 Function + mf_ultralight_is_page_pwd_or_pack _Bool MfUltralightType, uint16_t
2742 Function + mf_ultralight_load _Bool MfUltralightData*, FlipperFormat*, uint32_t
2743 Function + mf_ultralight_poller_auth_pwd MfUltralightError MfUltralightPoller*, MfUltralightPollerAuthContext*
2744 Function + mf_ultralight_poller_auth_tdes MfUltralightError MfUltralightPoller*, MfUltralightPollerAuthContext*
2745 Function + mf_ultralight_poller_authenticate_end MfUltralightError MfUltralightPoller*, const uint8_t*, const uint8_t*, uint8_t*
2746 Function + mf_ultralight_poller_authenticate_start MfUltralightError MfUltralightPoller*, const uint8_t*, uint8_t*
2747 Function + mf_ultralight_poller_read_counter MfUltralightError MfUltralightPoller*, uint8_t, MfUltralightCounter*