Просмотр исходного кода

nfp: Separate nfc tag from amiibo data

Narr the Reg 4 лет назад
Родитель
Сommit
6a1ad03153
3 измененных файлов с 76 добавлено и 44 удалено
  1. 7 2
      src/core/hid/emulated_controller.h
  2. 43 31
      src/core/hle/service/nfp/nfp.cpp
  3. 26 11
      src/core/hle/service/nfp/nfp.h

+ 7 - 2
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

+ 43 - 31
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<u8>& 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<u8>& 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);
-
-    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, "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);
+    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_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}", 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<u8>(amiibo.uuid.size()),
+            .uuid = tag_data.uuid,
+            .uuid_length = static_cast<u8>(tag_data.uuid.size()),
             .protocol = protocol,
-            .tag_type = static_cast<u32>(amiibo.model_info.amiibo_type),
+            .tag_type = static_cast<u32>(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<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const {
+std::vector<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const {
     // TODO(german77): Read file
     std::vector<u8> 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<Module>();
     std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager);

+ 26 - 11
src/core/hle/service/nfp/nfp.h

@@ -7,6 +7,7 @@
 #include <array>
 #include <vector>
 
+#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<u8, 10>;
+
 struct TagInfo {
-    std::array<u8, 10> 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<u8, 10> 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<u8>& 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<u8> LoadAmiiboApplicationData(u32 access_id) const;
+        std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const;
         void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& 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;