Skip to content

[NFC] Ultralight C. Attempt of authentication with default key + use default UL/UL-C pwd/key as default value for key input #4208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions applications/main/nfc/helpers/mf_ultralight_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ void mf_ultralight_auth_free(MfUltralightAuth* instance) {
void mf_ultralight_auth_reset(MfUltralightAuth* instance) {
furi_assert(instance);

uint32_t default_password = MF_ULTRALIGHT_DEFAULT_PASSWORD;

instance->type = MfUltralightAuthTypeNone;
memset(&instance->password, 0, sizeof(MfUltralightAuthPassword));
memset(&instance->tdes_key, 0, sizeof(MfUltralightC3DesAuthKey));
memcpy(&instance->password, &default_password, sizeof(MfUltralightAuthPassword));
memcpy(&instance->tdes_key, MF_ULTRALIGHT_C_DEFAULT_KEY, sizeof(MfUltralightC3DesAuthKey));
memset(&instance->pack, 0, sizeof(MfUltralightAuthPack));
}

Expand Down
6 changes: 6 additions & 0 deletions lib/nfc/protocols/mf_ultralight/mf_ultralight.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ extern "C" {
#define MF_ULTRALIGHT_TEARING_FLAG_NUM (3)
#define MF_ULTRALIGHT_AUTH_PASSWORD_SIZE (4)
#define MF_ULTRALIGHT_AUTH_PACK_SIZE (2)
#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL)

#define MF_ULTRALIGHT_C_AUTH_RESPONSE_SIZE (9)
#define MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE (16)
Expand All @@ -47,6 +48,11 @@ extern "C" {
#define MF_ULTRALIGHT_C_AUTH_RND_A_BLOCK_OFFSET (0)
#define MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET (8)
#define MF_ULTRALIGHT_C_ENCRYPTED_PACK_SIZE (MF_ULTRALIGHT_C_AUTH_DATA_SIZE + 1)
#define MF_ULTRALIGHT_C_DEFAULT_KEY \
(uint8_t[]) { \
0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, \
0x46 \
}

typedef enum {
MfUltralightErrorNone,
Expand Down
92 changes: 60 additions & 32 deletions lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

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) {
do {
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;
instance->error =
mf_ultralight_poller_auth_tdes(instance, &instance->auth_context);

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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
13 changes: 13 additions & 0 deletions lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
39 changes: 36 additions & 3 deletions lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "mf_ultralight_poller_i.h"

#include <furi.h>
#include <furi_hal.h>

#define TAG "MfUltralightPoller"

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ extern "C" {
#define MF_ULTRALIGHT_POLLER_STANDARD_FWT_FC (60000)
#define MF_ULTRALIGHT_MAX_BUFF_SIZE (64)

#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL)

#define MF_ULTRALIGHT_IS_NTAG_I2C(type) \
(((type) == MfUltralightTypeNTAGI2C1K) || ((type) == MfUltralightTypeNTAGI2C2K) || \
((type) == MfUltralightTypeNTAGI2CPlus1K) || ((type) == MfUltralightTypeNTAGI2CPlus2K))
Expand Down Expand Up @@ -61,6 +59,7 @@ typedef enum {
MfUltralightPollerStateAuthMfulC,
MfUltralightPollerStateReadPages,
MfUltralightPollerStateTryDefaultPass,
MfUltralightPollerStateTryDefaultMfulCKey,
MfUltralightPollerStateCheckMfulCAuthStatus,
MfUltralightPollerStateReadFailed,
MfUltralightPollerStateReadSuccess,
Expand Down
2 changes: 1 addition & 1 deletion targets/f18/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,86.0,,
Version,+,86.1,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Header,+,applications/services/cli/cli.h,,
Expand Down
3 changes: 2 additions & 1 deletion targets/f7/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,86.0,,
Version,+,86.1,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Expand Down Expand Up @@ -2697,6 +2697,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*"
Expand Down
Loading