From f63586c5f5aad1eb4d25e59d81a83e58529988ff Mon Sep 17 00:00:00 2001
From: Narr the Reg <juangerman-13@hotmail.com>
Date: Mon, 22 May 2023 18:31:39 -0600
Subject: [PATCH] service: nfc: Remove encryption key requirement

---
 .../hle/service/nfc/common/amiibo_crypto.cpp  |  3 -
 src/core/hle/service/nfc/common/device.cpp    | 71 +++++++++++++------
 src/core/hle/service/nfc/common/device.h      |  3 +
 3 files changed, 54 insertions(+), 23 deletions(-)

diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
index f3901ee8d..b2bcb68c3 100644
--- a/src/core/hle/service/nfc/common/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
@@ -52,9 +52,6 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
     if (ntag_file.compability_container != 0xEEFF10F1U) {
         return false;
     }
-    if (amiibo_data.constant_value != 0xA5) {
-        return false;
-    }
     if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
         return false;
     }
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 322bde2ed..e5d4545a8 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -119,18 +119,31 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
 
     memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
     is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data);
-
-    if (is_plain_amiibo) {
-        encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(tag_data);
-        LOG_INFO(Service_NFP, "Using plain amiibo");
-    } else {
-        tag_data = {};
-        memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
-    }
+    is_write_protected = false;
 
     device_state = DeviceState::TagFound;
     deactivate_event->GetReadableEvent().Clear();
     activate_event->Signal();
+
+    // Fallback for plain amiibos
+    if (is_plain_amiibo) {
+        LOG_INFO(Service_NFP, "Using plain amiibo");
+        encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(tag_data);
+        return true;
+    }
+
+    // Fallback for encrypted amiibos without keys
+    if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
+        LOG_INFO(Service_NFC, "Loading amiibo without keys");
+        memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+        BuildAmiiboWithoutKeys();
+        is_plain_amiibo = true;
+        is_write_protected = true;
+        return true;
+    }
+
+    tag_data = {};
+    memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
     return true;
 }
 
@@ -346,23 +359,15 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
         return ResultWrongDeviceState;
     }
 
-    // The loaded amiibo is not encrypted
-    if (is_plain_amiibo) {
-        device_state = DeviceState::TagMounted;
-        mount_target = mount_target_;
-        return ResultSuccess;
-    }
-
     if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
         LOG_ERROR(Service_NFP, "Not an amiibo");
         return ResultNotAnAmiibo;
     }
 
-    // Mark amiibos as read only when keys are missing
-    if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
-        LOG_ERROR(Service_NFP, "No keys detected");
+    // The loaded amiibo is not encrypted
+    if (is_plain_amiibo) {
         device_state = DeviceState::TagMounted;
-        mount_target = NFP::MountTarget::Rom;
+        mount_target = mount_target_;
         return ResultSuccess;
     }
 
@@ -457,6 +462,11 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
         return ResultWrongDeviceState;
     }
 
+    if (is_write_protected) {
+        LOG_ERROR(Service_NFP, "No keys available skipping write request");
+        return ResultSuccess;
+    }
+
     std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
     if (is_plain_amiibo) {
         memcpy(data.data(), &tag_data, sizeof(tag_data));
@@ -1033,7 +1043,6 @@ Result NfcDevice::GetAll(NFP::NfpData& data) const {
     }
 
     NFP::CommonInfo common_info{};
-    Service::Mii::MiiManager manager;
     const u64 application_id = tag_data.application_id;
 
     GetCommonInfo(common_info);
@@ -1249,6 +1258,28 @@ void NfcDevice::UpdateRegisterInfoCrc() {
     tag_data.register_info_crc = crc.checksum();
 }
 
+void NfcDevice::BuildAmiiboWithoutKeys() {
+    Service::Mii::MiiManager manager;
+    auto& settings = tag_data.settings;
+
+    tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_tag_data);
+
+    // Common info
+    tag_data.write_counter = 0;
+    tag_data.amiibo_version = 0;
+    settings.write_date = GetAmiiboDate(GetCurrentPosixTime());
+
+    // Register info
+    SetAmiiboName(settings, {'y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o'});
+    settings.settings.font_region.Assign(0);
+    settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
+    tag_data.owner_mii = manager.BuildFromStoreData(manager.BuildDefault(0));
+
+    // Admin info
+    settings.settings.amiibo_initialized.Assign(1);
+    settings.settings.appdata_initialized.Assign(0);
+}
+
 u64 NfcDevice::GetHandle() const {
     // Generate a handle based of the npad id
     return static_cast<u64>(npad_id);
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index 98e1945c1..6a37e8458 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -110,6 +110,8 @@ private:
     void UpdateSettingsCrc();
     void UpdateRegisterInfoCrc();
 
+    void BuildAmiiboWithoutKeys();
+
     bool is_controller_set{};
     int callback_key;
     const Core::HID::NpadIdType npad_id;
@@ -128,6 +130,7 @@ private:
     bool is_data_moddified{};
     bool is_app_area_open{};
     bool is_plain_amiibo{};
+    bool is_write_protected{};
     NFP::MountTarget mount_target{NFP::MountTarget::None};
 
     NFP::NTAG215File tag_data{};