From 6a1ad031530f506a1bc789c42d639dc11ce4f2ea Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 10 Feb 2022 10:58:37 -0600 Subject: [PATCH] nfp: Separate nfc tag from amiibo data --- src/core/hid/emulated_controller.h | 9 +++- src/core/hle/service/nfp/nfp.cpp | 70 +++++++++++++++++------------- src/core/hle/service/nfp/nfp.h | 37 +++++++++++----- 3 files changed, 74 insertions(+), 42 deletions(-) diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 7785e6110..aa52f9572 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -299,16 +299,21 @@ public: /** * Sends a specific vibration to the output device - * @return returns true if vibration had no errors + * @return true if vibration had no errors */ bool SetVibration(std::size_t device_index, VibrationValue vibration); /** * Sends a small vibration to the output device - * @return returns true if SetVibration was successfull + * @return true if SetVibration was successfull */ bool TestVibration(std::size_t device_index); + /** + * Sets the desired data to be polled from a controller + * @param polling_mode type of input desired buttons, gyro, nfc, ir, etc. + * @return true if SetPollingMode was successfull + */ bool SetPollingMode(Common::Input::PollingMode polling_mode); /// Returns the led pattern corresponding to this emulated controller diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 459fa798f..63e257975 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -479,7 +479,7 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { } bool Module::Interface::LoadAmiibo(const std::vector& buffer) { - if (buffer.size() < sizeof(AmiiboFile)) { + if (buffer.size() < sizeof(NTAG215File)) { LOG_ERROR(Service_NFP, "Wrong file size"); return false; } @@ -490,12 +490,15 @@ bool Module::Interface::LoadAmiibo(const std::vector& buffer) { } LOG_INFO(Service_NFP, "Amiibo detected"); - std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); + std::memcpy(&tag_data, buffer.data(), sizeof(tag_data)); if (!IsAmiiboValid()) { return false; } + // This value can't be dumped from a tag. Generate it + tag_data.PWD = GetTagPassword(tag_data.uuid); + device_state = DeviceState::TagFound; activate_event->GetWritableEvent().Signal(); return true; @@ -511,42 +514,43 @@ void Module::Interface::CloseAmiibo() { } bool Module::Interface::IsAmiiboValid() const { - LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", amiibo.uuid_lock); - LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", amiibo.compability_container); - LOG_DEBUG(Service_NFP, "crypto_init=0x{0:x}", amiibo.crypto_init); - LOG_DEBUG(Service_NFP, "write_count={}", amiibo.write_count); + const auto& amiibo_data = tag_data.user_memory; + LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", tag_data.lock_bytes); + LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", tag_data.compability_container); + LOG_DEBUG(Service_NFP, "crypto_init=0x{0:x}", amiibo_data.crypto_init); + LOG_DEBUG(Service_NFP, "write_count={}", amiibo_data.write_count); - LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo.model_info.character_id); - LOG_DEBUG(Service_NFP, "character_variant={}", amiibo.model_info.character_variant); - LOG_DEBUG(Service_NFP, "amiibo_type={}", amiibo.model_info.amiibo_type); - LOG_DEBUG(Service_NFP, "model_number=0x{0:x}", amiibo.model_info.model_number); - LOG_DEBUG(Service_NFP, "series={}", amiibo.model_info.series); - LOG_DEBUG(Service_NFP, "fixed_value=0x{0:x}", amiibo.model_info.fixed); + LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); + LOG_DEBUG(Service_NFP, "character_variant={}", amiibo_data.model_info.character_variant); + LOG_DEBUG(Service_NFP, "amiibo_type={}", amiibo_data.model_info.amiibo_type); + LOG_DEBUG(Service_NFP, "model_number=0x{0:x}", amiibo_data.model_info.model_number); + LOG_DEBUG(Service_NFP, "series={}", amiibo_data.model_info.series); + LOG_DEBUG(Service_NFP, "fixed_value=0x{0:x}", amiibo_data.model_info.fixed); - LOG_DEBUG(Service_NFP, "tag_dynamic_lock=0x{0:x}", amiibo.tag_dynamic_lock); - LOG_DEBUG(Service_NFP, "tag_CFG0=0x{0:x}", amiibo.tag_CFG0); - LOG_DEBUG(Service_NFP, "tag_CFG1=0x{0:x}", amiibo.tag_CFG1); + LOG_DEBUG(Service_NFP, "tag_dynamic_lock=0x{0:x}", tag_data.dynamic_lock); + LOG_DEBUG(Service_NFP, "tag_CFG0=0x{0:x}", tag_data.CFG0); + LOG_DEBUG(Service_NFP, "tag_CFG1=0x{0:x}", tag_data.CFG1); // Check against all know constants on an amiibo binary - if (amiibo.uuid_lock != 0xE00F) { + if (tag_data.lock_bytes != 0xE00F) { return false; } - if (amiibo.compability_container != 0xEEFF10F1UL) { + if (tag_data.compability_container != 0xEEFF10F1U) { return false; } - if ((amiibo.crypto_init & 0xFF) != 0xA5) { + if ((amiibo_data.crypto_init & 0xFF) != 0xA5) { return false; } - if (amiibo.model_info.fixed != 0x02) { + if (amiibo_data.model_info.fixed != 0x02) { return false; } - if ((amiibo.tag_dynamic_lock & 0xFFFFFF) != 0x0F0001) { + if ((tag_data.dynamic_lock & 0xFFFFFF) != 0x0F0001) { return false; } - if (amiibo.tag_CFG0 != 0x04000000UL) { + if (tag_data.CFG0 != 0x04000000U) { return false; } - if (amiibo.tag_CFG1 != 0x5F) { + if (tag_data.CFG1 != 0x5F) { return false; } return true; @@ -629,12 +633,11 @@ ResultCode Module::Interface::Unmount() { ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const { if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { - // Read this data from the amiibo save file tag_info = { - .uuid = amiibo.uuid, - .uuid_length = static_cast(amiibo.uuid.size()), + .uuid = tag_data.uuid, + .uuid_length = static_cast(tag_data.uuid.size()), .protocol = protocol, - .tag_type = static_cast(amiibo.model_info.amiibo_type), + .tag_type = static_cast(tag_data.user_memory.model_info.amiibo_type), }; return ResultSuccess; } @@ -654,7 +657,7 @@ ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const { .last_write_year = 2022, .last_write_month = 2, .last_write_day = 7, - .write_counter = amiibo.write_count, + .write_counter = tag_data.user_memory.write_count, .version = 1, .application_area_size = ApplicationAreaSize, }; @@ -667,7 +670,7 @@ ResultCode Module::Interface::GetModelInfo(ModelInfo& model_info) const { return ErrCodes::WrongDeviceState; } - model_info = amiibo.model_info; + model_info = tag_data.user_memory.model_info; return ResultSuccess; } @@ -757,7 +760,7 @@ bool Module::Interface::AmiiboApplicationDataExist(u32 access_id) const { return false; } -const std::vector Module::Interface::LoadAmiiboApplicationData(u32 access_id) const { +std::vector Module::Interface::LoadAmiiboApplicationData(u32 access_id) const { // TODO(german77): Read file std::vector data(ApplicationAreaSize); return data; @@ -781,6 +784,15 @@ Core::HID::NpadIdType Module::Interface::GetNpadId() const { return npad_id; } +u32 Module::Interface::GetTagPassword(const TagUuid& uuid) const { + // Verifiy that the generated password is correct + u32 password = 0xAA ^ (uuid[1] ^ uuid[3]); + password &= (0x55 ^ (uuid[2] ^ uuid[4])) << 8; + password &= (0xAA ^ (uuid[3] ^ uuid[5])) << 16; + password &= (0x55 ^ (uuid[4] ^ uuid[6])) << 24; + return password; +} + void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { auto module = std::make_shared(); std::make_shared(module, system)->InstallAsService(service_manager); diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 633539dcc..bc3b1967f 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -7,6 +7,7 @@ #include #include +#include "common/common_funcs.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/service.h" @@ -85,8 +86,10 @@ enum class AmiiboSeries : u8 { Diablo }; +using TagUuid = std::array; + struct TagInfo { - std::array uuid; + TagUuid uuid; u8 uuid_length; INSERT_PADDING_BYTES(0x15); s32 protocol; @@ -138,10 +141,7 @@ public: const char* name); ~Interface() override; - struct AmiiboFile { - std::array uuid; - u16 uuid_lock; // Must be 0F E0 - u32 compability_container; // Must be F1 10 FF EE + struct EncryptedAmiiboFile { u16 crypto_init; // Must be A5 XX u16 write_count; // Number of times the amiibo has been written? INSERT_PADDING_BYTES(0x20); // System crypts @@ -150,11 +150,22 @@ public: INSERT_PADDING_BYTES(0xC); // SHA256-HMAC INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer INSERT_PADDING_BYTES(0x54); // section 2 encrypted buffer - u32 tag_dynamic_lock; // Must be 01 00 0F XX - u32 tag_CFG0; // Must be 00 00 00 04 - u32 tag_CFG1; // Must be 50 00 00 00 }; - static_assert(sizeof(AmiiboFile) == 0x214, "AmiiboFile is an invalid size"); + static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); + + struct NTAG215File { + TagUuid uuid; // Unique serial number + u16 lock_bytes; // Set defined pages as read only + u32 compability_container; // Defines available memory + EncryptedAmiiboFile user_memory; // Writable data + u32 dynamic_lock; // Dynamic lock + u32 CFG0; // Defines memory protected by password + u32 CFG1; // Defines number of verification attempts + u32 PWD; // Password to allow write access + u16 PACK; // Password acknowledge reply + u16 RFUI; // Reserved for future use + }; + static_assert(sizeof(NTAG215File) == 0x21C, "NTAG215File is an invalid size"); void CreateUserInterface(Kernel::HLERequestContext& ctx); bool LoadAmiibo(const std::vector& buffer); @@ -191,17 +202,21 @@ public: private: /// Validates that the amiibo file is not corrupted bool IsAmiiboValid() const; + bool AmiiboApplicationDataExist(u32 access_id) const; - const std::vector LoadAmiiboApplicationData(u32 access_id) const; + std::vector LoadAmiiboApplicationData(u32 access_id) const; void SaveAmiiboApplicationData(u32 access_id, const std::vector& data) const; + /// return password needed to allow write access to protected memory + u32 GetTagPassword(const TagUuid& uuid) const; + const Core::HID::NpadIdType npad_id; DeviceState device_state{DeviceState::Unaviable}; KernelHelpers::ServiceContext service_context; Kernel::KEvent* activate_event; Kernel::KEvent* deactivate_event; - AmiiboFile amiibo{}; + NTAG215File tag_data{}; s32 protocol; bool is_application_area_initialized{}; u32 application_area_id;