From f633f476c8d41f9b80df1ad0a1d54934482fa894 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 25 Mar 2024 07:18:28 +0000 Subject: [PATCH] [FL-3787] NFC: Slix privacy password reveal and Desfire detect fix (#3504) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * slix: fix incorrect default privacy passwords * slix poller: add check privacy password state * mf desfire: change detect algorithm * mf desfire: change detection algorithm to check master key version * mf desfire: change assert to check * Update api symbols and cleanup code Co-authored-by: あく --- .../protocols/mf_desfire/mf_desfire_poller.c | 4 +- .../protocols/mf_desfire/mf_desfire_poller.h | 15 ++++++ .../mf_desfire/mf_desfire_poller_i.c | 35 ++++++++----- lib/nfc/protocols/slix/slix.c | 4 +- lib/nfc/protocols/slix/slix_poller.c | 51 ++++++++++++++++++- lib/nfc/protocols/slix/slix_poller_i.h | 2 + targets/f18/api_symbols.csv | 2 +- targets/f7/api_symbols.csv | 3 +- 8 files changed, 96 insertions(+), 20 deletions(-) diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index 5af033d4ca..246107616d 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -225,8 +225,8 @@ static bool mf_desfire_poller_detect(NfcGenericEvent event, void* context) { bool protocol_detected = false; if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { - MfDesfireVersion version = {}; - const MfDesfireError error = mf_desfire_poller_read_version(instance, &version); + MfDesfireKeyVersion key_version = {0}; + MfDesfireError error = mf_desfire_poller_read_key_version(instance, 0, &key_version); protocol_detected = (error == MfDesfireErrorNone); } diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h index 6ef2f3f68d..707df42cd6 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h @@ -91,6 +91,21 @@ MfDesfireError MfDesfireError mf_desfire_poller_read_key_settings(MfDesfirePoller* instance, MfDesfireKeySettings* data); +/** + * @brief Read key version on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] key_num key number. + * @param[in] data pointer to the MfDesfireKeyVersion structure to be filled with key version data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_key_version( + MfDesfirePoller* instance, + uint8_t key_num, + MfDesfireKeyVersion* data); + /** * @brief Read key versions on MfDesfire card. * diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 4990e0c068..790f117157 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -139,6 +139,28 @@ MfDesfireError return error; } +MfDesfireError mf_desfire_poller_read_key_version( + MfDesfirePoller* instance, + uint8_t key_num, + MfDesfireKeyVersion* data) { + furi_check(instance); + furi_check(data); + + bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t) * 2); + bit_buffer_set_byte(instance->input_buffer, 0, MF_DESFIRE_CMD_GET_KEY_VERSION); + bit_buffer_set_byte(instance->input_buffer, 1, key_num); + + MfDesfireError error = + mf_desfire_send_chunks(instance, instance->input_buffer, instance->result_buffer); + if(error == MfDesfireErrorNone) { + if(!mf_desfire_key_version_parse(data, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + } + } + + return error; +} + MfDesfireError mf_desfire_poller_read_key_versions( MfDesfirePoller* instance, SimpleArray* data, @@ -148,22 +170,11 @@ MfDesfireError mf_desfire_poller_read_key_versions( simple_array_init(data, count); - bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t) * 2); - bit_buffer_set_byte(instance->input_buffer, 0, MF_DESFIRE_CMD_GET_KEY_VERSION); - MfDesfireError error = MfDesfireErrorNone; for(uint32_t i = 0; i < count; ++i) { - bit_buffer_set_byte(instance->input_buffer, 1, i); - - error = mf_desfire_send_chunks(instance, instance->input_buffer, instance->result_buffer); - + error = mf_desfire_poller_read_key_version(instance, i, simple_array_get(data, i)); if(error != MfDesfireErrorNone) break; - - if(!mf_desfire_key_version_parse(simple_array_get(data, i), instance->result_buffer)) { - error = MfDesfireErrorProtocol; - break; - } } return error; diff --git a/lib/nfc/protocols/slix/slix.c b/lib/nfc/protocols/slix/slix.c index 41d19beb7e..533ecff741 100644 --- a/lib/nfc/protocols/slix/slix.c +++ b/lib/nfc/protocols/slix/slix.c @@ -78,8 +78,8 @@ typedef struct { static const SlixPasswordConfig slix_password_configs[] = { [SlixPasswordTypeRead] = {SLIX_PASSWORD_READ_KEY, SLIX_TYPE_FEATURE_READ, 0x00000000U}, [SlixPasswordTypeWrite] = {SLIX_PASSWORD_WRITE_KEY, SLIX_TYPE_FEATURE_WRITE, 0x00000000U}, - [SlixPasswordTypePrivacy] = {SLIX_PASSWORD_PRIVACY_KEY, SLIX_TYPE_FEATURE_PRIVACY, 0xFFFFFFFFU}, - [SlixPasswordTypeDestroy] = {SLIX_PASSWORD_DESTROY_KEY, SLIX_TYPE_FEATURE_DESTROY, 0xFFFFFFFFU}, + [SlixPasswordTypePrivacy] = {SLIX_PASSWORD_PRIVACY_KEY, SLIX_TYPE_FEATURE_PRIVACY, 0x0F0F0F0FU}, + [SlixPasswordTypeDestroy] = {SLIX_PASSWORD_DESTROY_KEY, SLIX_TYPE_FEATURE_DESTROY, 0x0F0F0F0FU}, [SlixPasswordTypeEasAfi] = {SLIX_PASSWORD_EAS_KEY, SLIX_TYPE_FEATURE_EAS, 0x00000000U}, }; diff --git a/lib/nfc/protocols/slix/slix_poller.c b/lib/nfc/protocols/slix/slix_poller.c index d9d38d1020..3c9a7cce4b 100644 --- a/lib/nfc/protocols/slix/slix_poller.c +++ b/lib/nfc/protocols/slix/slix_poller.c @@ -73,17 +73,62 @@ static NfcCommand slix_poller_handler_read_signature(SlixPoller* instance) { if(slix_type_has_features(instance->type, SLIX_TYPE_FEATURE_SIGNATURE)) { instance->error = slix_poller_read_signature(instance, &instance->data->signature); if(instance->error == SlixErrorNone) { - instance->poller_state = SlixPollerStateReady; + instance->poller_state = SlixPollerStateCheckPrivacyPassword; } else { instance->poller_state = SlixPollerStateError; } } else { - instance->poller_state = SlixPollerStateReady; + instance->poller_state = SlixPollerStateCheckPrivacyPassword; } return NfcCommandContinue; } +static NfcCommand slix_poller_handler_check_privacy_password(SlixPoller* instance) { + NfcCommand command = NfcCommandContinue; + + do { + if(!slix_type_has_features(instance->type, SLIX_TYPE_FEATURE_PRIVACY)) { + instance->poller_state = SlixPollerStateReady; + break; + } + if(instance->privacy_password_checked) { + instance->poller_state = SlixPollerStateReady; + break; + } + + instance->slix_event.type = SlixPollerEventTypePrivacyUnlockRequest; + command = instance->callback(instance->general_event, instance->context); + + if(!instance->slix_event_data.privacy_password.password_set) { + instance->poller_state = SlixPollerStateReady; + break; + } + + SlixPassword pwd = instance->slix_event_data.privacy_password.password; + FURI_LOG_I(TAG, "Trying to check privacy password: %08lX", pwd); + + instance->error = slix_poller_get_random_number(instance, &instance->random_number); + if(instance->error != SlixErrorNone) { + instance->poller_state = SlixPollerStateReady; + break; + } + + instance->error = slix_poller_set_password(instance, SlixPasswordTypePrivacy, pwd); + if(instance->error != SlixErrorNone) { + command = NfcCommandReset; + break; + } + + FURI_LOG_I(TAG, "Found privacy password"); + instance->data->passwords[SlixPasswordTypePrivacy] = pwd; + instance->privacy_password_checked = true; + instance->poller_state = SlixPollerStateReady; + } while(false); + + return command; +} + static NfcCommand slix_poller_handler_privacy_unlock(SlixPoller* instance) { NfcCommand command = NfcCommandContinue; instance->poller_state = SlixPollerStateError; @@ -108,6 +153,7 @@ static NfcCommand slix_poller_handler_privacy_unlock(SlixPoller* instance) { FURI_LOG_I(TAG, "Privacy mode disabled"); instance->data->passwords[SlixPasswordTypePrivacy] = pwd; + instance->privacy_password_checked = true; instance->poller_state = SlixPollerStateIdle; slix_unlocked = true; } while(false); @@ -140,6 +186,7 @@ static const SlixPollerStateHandler slix_poller_state_handler[SlixPollerStateNum [SlixPollerStateError] = slix_poller_handler_error, [SlixPollerStateGetNxpSysInfo] = slix_poller_handler_get_nfc_system_info, [SlixPollerStateReadSignature] = slix_poller_handler_read_signature, + [SlixPollerStateCheckPrivacyPassword] = slix_poller_handler_check_privacy_password, [SlixPollerStatePrivacyUnlock] = slix_poller_handler_privacy_unlock, [SlixPollerStateReady] = slix_poller_handler_ready, }; diff --git a/lib/nfc/protocols/slix/slix_poller_i.h b/lib/nfc/protocols/slix/slix_poller_i.h index 7a3b543b7b..38c23c297b 100644 --- a/lib/nfc/protocols/slix/slix_poller_i.h +++ b/lib/nfc/protocols/slix/slix_poller_i.h @@ -14,6 +14,7 @@ typedef enum { SlixPollerStateIdle, SlixPollerStateGetNxpSysInfo, SlixPollerStateReadSignature, + SlixPollerStateCheckPrivacyPassword, SlixPollerStatePrivacyUnlock, SlixPollerStateReady, SlixPollerStateError, @@ -27,6 +28,7 @@ struct SlixPoller { SlixPollerState poller_state; SlixError error; SlixRandomNumber random_number; + bool privacy_password_checked; BitBuffer* tx_buffer; BitBuffer* rx_buffer; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index f19a5428c5..880bfe754a 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,60.0,, +Version,+,60.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index d1e91ddbed..1f30a11504 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,60.0,, +Version,+,60.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2444,6 +2444,7 @@ Function,+,mf_desfire_poller_read_file_settings_multi,MfDesfireError,"MfDesfireP Function,+,mf_desfire_poller_read_file_value,MfDesfireError,"MfDesfirePoller*, MfDesfireFileId, MfDesfireFileData*" Function,+,mf_desfire_poller_read_free_memory,MfDesfireError,"MfDesfirePoller*, MfDesfireFreeMemory*" Function,+,mf_desfire_poller_read_key_settings,MfDesfireError,"MfDesfirePoller*, MfDesfireKeySettings*" +Function,+,mf_desfire_poller_read_key_version,MfDesfireError,"MfDesfirePoller*, uint8_t, MfDesfireKeyVersion*" Function,+,mf_desfire_poller_read_key_versions,MfDesfireError,"MfDesfirePoller*, SimpleArray*, uint32_t" Function,+,mf_desfire_poller_read_version,MfDesfireError,"MfDesfirePoller*, MfDesfireVersion*" Function,+,mf_desfire_poller_select_application,MfDesfireError,"MfDesfirePoller*, const MfDesfireApplicationId*"