From 673de3995b7f08d51fcc281439c05c368b7bd1ae Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 26 Sep 2022 00:58:36 -0500 Subject: [PATCH] nfp: Multiple fixes against HW --- src/core/hle/service/mii/mii_manager.cpp | 68 +++++++++++++++++++++- src/core/hle/service/mii/mii_manager.h | 1 + src/core/hle/service/nfc/nfc.cpp | 8 +-- src/core/hle/service/nfp/amiibo_crypto.cpp | 55 +++++++++-------- src/core/hle/service/nfp/amiibo_crypto.h | 6 +- src/core/hle/service/nfp/nfp_device.cpp | 60 ++++++++++++------- src/core/hle/service/nfp/nfp_device.h | 2 + src/core/hle/service/nfp/nfp_result.h | 1 + src/core/hle/service/nfp/nfp_types.h | 24 +++++--- 9 files changed, 163 insertions(+), 62 deletions(-) diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp index 3e92152ec0..4bc8703e19 100644 --- a/src/core/hle/service/mii/mii_manager.cpp +++ b/src/core/hle/service/mii/mii_manager.cpp @@ -431,8 +431,7 @@ CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const { Service::Mii::MiiManager manager; auto mii = manager.BuildDefault(0); - // Check if mii data exist - if (mii_v3.version == 0) { + if (!ValidateV3Info(mii_v3)) { return mii; } @@ -576,6 +575,71 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const { return mii_v3; } +bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const { + bool is_valid = mii_v3.version == 0 || mii_v3.version == 3; + + is_valid = is_valid && (mii_v3.mii_name[0] != 0); + + is_valid = is_valid && (mii_v3.mii_information.birth_month < 13); + is_valid = is_valid && (mii_v3.mii_information.birth_day < 32); + is_valid = is_valid && (mii_v3.mii_information.favorite_color < 12); + is_valid = is_valid && (mii_v3.height < 128); + is_valid = is_valid && (mii_v3.build < 128); + + is_valid = is_valid && (mii_v3.appearance_bits1.face_shape < 12); + is_valid = is_valid && (mii_v3.appearance_bits1.skin_color < 7); + is_valid = is_valid && (mii_v3.appearance_bits2.wrinkles < 12); + is_valid = is_valid && (mii_v3.appearance_bits2.makeup < 12); + + is_valid = is_valid && (mii_v3.hair_style < 132); + is_valid = is_valid && (mii_v3.appearance_bits3.hair_color < 8); + + is_valid = is_valid && (mii_v3.appearance_bits4.eye_type < 60); + is_valid = is_valid && (mii_v3.appearance_bits4.eye_color < 6); + is_valid = is_valid && (mii_v3.appearance_bits4.eye_scale < 8); + is_valid = is_valid && (mii_v3.appearance_bits4.eye_vertical_stretch < 7); + is_valid = is_valid && (mii_v3.appearance_bits4.eye_rotation < 8); + is_valid = is_valid && (mii_v3.appearance_bits4.eye_spacing < 13); + is_valid = is_valid && (mii_v3.appearance_bits4.eye_y_position < 19); + + is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_style < 25); + is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_color < 8); + is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_scale < 9); + is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_yscale < 7); + is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_rotation < 12); + is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_spacing < 12); + is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_y_position < 19); + + is_valid = is_valid && (mii_v3.appearance_bits6.nose_type < 18); + is_valid = is_valid && (mii_v3.appearance_bits6.nose_scale < 9); + is_valid = is_valid && (mii_v3.appearance_bits6.nose_y_position < 19); + + is_valid = is_valid && (mii_v3.appearance_bits7.mouth_type < 36); + is_valid = is_valid && (mii_v3.appearance_bits7.mouth_color < 5); + is_valid = is_valid && (mii_v3.appearance_bits7.mouth_scale < 9); + is_valid = is_valid && (mii_v3.appearance_bits7.mouth_horizontal_stretch < 7); + is_valid = is_valid && (mii_v3.appearance_bits8.mouth_y_position < 19); + + is_valid = is_valid && (mii_v3.appearance_bits8.mustache_type < 6); + is_valid = is_valid && (mii_v3.appearance_bits9.mustache_scale < 7); + is_valid = is_valid && (mii_v3.appearance_bits9.mustache_y_position < 17); + + is_valid = is_valid && (mii_v3.appearance_bits9.bear_type < 6); + is_valid = is_valid && (mii_v3.appearance_bits9.facial_hair_color < 8); + + is_valid = is_valid && (mii_v3.appearance_bits10.glasses_type < 9); + is_valid = is_valid && (mii_v3.appearance_bits10.glasses_color < 6); + is_valid = is_valid && (mii_v3.appearance_bits10.glasses_scale < 8); + is_valid = is_valid && (mii_v3.appearance_bits10.glasses_y_position < 21); + + is_valid = is_valid && (mii_v3.appearance_bits11.mole_enabled < 2); + is_valid = is_valid && (mii_v3.appearance_bits11.mole_scale < 9); + is_valid = is_valid && (mii_v3.appearance_bits11.mole_x_position < 17); + is_valid = is_valid && (mii_v3.appearance_bits11.mole_y_position < 31); + + return is_valid; +} + ResultVal> MiiManager::GetDefault(SourceFlag source_flag) { std::vector result; diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index b68fdd54c0..83ad3d3431 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h @@ -24,6 +24,7 @@ public: CharInfo BuildDefault(std::size_t index); CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const; Ver3StoreData ConvertCharInfoToV3(const CharInfo& mii) const; + bool ValidateV3Info(const Ver3StoreData& mii_v3) const; ResultVal> GetDefault(SourceFlag source_flag); Result GetIndex(const CharInfo& info, u32& index); diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 13a843a28d..046c5f18fd 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -106,10 +106,10 @@ public: {1, &IUser::FinalizeOld, "FinalizeOld"}, {2, &IUser::GetStateOld, "GetStateOld"}, {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"}, - {400, nullptr, "Initialize"}, - {401, nullptr, "Finalize"}, - {402, nullptr, "GetState"}, - {403, nullptr, "IsNfcEnabled"}, + {400, &IUser::InitializeOld, "Initialize"}, + {401, &IUser::FinalizeOld, "Finalize"}, + {402, &IUser::GetStateOld, "GetState"}, + {403, &IUser::IsNfcEnabledOld, "IsNfcEnabled"}, {404, nullptr, "ListDevices"}, {405, nullptr, "GetDeviceState"}, {406, nullptr, "GetNpadId"}, diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp index c87da5ae42..9e06970a4d 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.cpp +++ b/src/core/hle/service/nfp/amiibo_crypto.cpp @@ -25,7 +25,8 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { 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, "model_number=0x{0:x}", + static_cast(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.constant_value); @@ -35,11 +36,12 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { // Validate UUID constexpr u8 CT = 0x88; // As defined in `ISO / IEC 14443 - 3` - if ((CT ^ ntag_file.uuid[0] ^ ntag_file.uuid[1] ^ ntag_file.uuid[2]) != ntag_file.uuid[3]) { + if ((CT ^ ntag_file.uuid.uid[0] ^ ntag_file.uuid.uid[1] ^ ntag_file.uuid.uid[2]) != + ntag_file.uuid.uid[3]) { return false; } - if ((ntag_file.uuid[4] ^ ntag_file.uuid[5] ^ ntag_file.uuid[6] ^ ntag_file.uuid[7]) != - ntag_file.uuid[8]) { + if ((ntag_file.uuid.uid[4] ^ ntag_file.uuid.uid[5] ^ ntag_file.uuid.uid[6] ^ + ntag_file.uuid.nintendo_id) != ntag_file.uuid.lock_bytes[0]) { return false; } @@ -70,7 +72,8 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { NTAG215File encoded_data{}; - memcpy(encoded_data.uuid2.data(), nfc_data.uuid.data() + 0x8, sizeof(encoded_data.uuid2)); + encoded_data.uid = nfc_data.uuid.uid; + encoded_data.nintendo_id = nfc_data.uuid.nintendo_id; encoded_data.static_lock = nfc_data.static_lock; encoded_data.compability_container = nfc_data.compability_container; encoded_data.hmac_data = nfc_data.user_memory.hmac_data; @@ -85,7 +88,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { encoded_data.hash = nfc_data.user_memory.hash; encoded_data.application_area = nfc_data.user_memory.application_area; encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag; - memcpy(encoded_data.uuid.data(), nfc_data.uuid.data(), sizeof(encoded_data.uuid)); + encoded_data.lock_bytes = nfc_data.uuid.lock_bytes; encoded_data.model_info = nfc_data.user_memory.model_info; encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt; encoded_data.dynamic_lock = nfc_data.dynamic_lock; @@ -99,8 +102,9 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { EncryptedNTAG215File nfc_data{}; - memcpy(nfc_data.uuid.data() + 0x8, encoded_data.uuid2.data(), sizeof(encoded_data.uuid2)); - memcpy(nfc_data.uuid.data(), encoded_data.uuid.data(), sizeof(encoded_data.uuid)); + nfc_data.uuid.uid = encoded_data.uid; + nfc_data.uuid.nintendo_id = encoded_data.nintendo_id; + nfc_data.uuid.lock_bytes = encoded_data.lock_bytes; nfc_data.static_lock = encoded_data.static_lock; nfc_data.compability_container = encoded_data.compability_container; nfc_data.user_memory.hmac_data = encoded_data.hmac_data; @@ -127,10 +131,10 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { u32 GetTagPassword(const TagUuid& uuid) { // 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; + u32 password = 0xAA ^ (uuid.uid[1] ^ uuid.uid[3]); + password &= (0x55 ^ (uuid.uid[2] ^ uuid.uid[4])) << 8; + password &= (0xAA ^ (uuid.uid[3] ^ uuid.uid[5])) << 16; + password &= (0x55 ^ (uuid.uid[4] ^ uuid.uid[6])) << 24; return password; } @@ -138,15 +142,13 @@ HashSeed GetSeed(const NTAG215File& data) { HashSeed seed{ .magic = data.write_counter, .padding = {}, - .uuid1 = {}, - .uuid2 = {}, + .uid_1 = data.uid, + .nintendo_id_1 = data.nintendo_id, + .uid_2 = data.uid, + .nintendo_id_2 = data.nintendo_id, .keygen_salt = data.keygen_salt, }; - // Copy the first 8 bytes of uuid - memcpy(seed.uuid1.data(), data.uuid.data(), sizeof(seed.uuid1)); - memcpy(seed.uuid2.data(), data.uuid.data(), sizeof(seed.uuid2)); - return seed; } @@ -165,8 +167,10 @@ std::vector GenerateInternalKey(const InternalKey& key, const HashSeed& seed output.insert(output.end(), key.magic_bytes.begin(), key.magic_bytes.begin() + key.magic_length); - output.insert(output.end(), seed.uuid1.begin(), seed.uuid1.end()); - output.insert(output.end(), seed.uuid2.begin(), seed.uuid2.end()); + output.insert(output.end(), seed.uid_1.begin(), seed.uid_1.end()); + output.emplace_back(seed.nintendo_id_1); + output.insert(output.end(), seed.uid_2.begin(), seed.uid_2.end()); + output.emplace_back(seed.nintendo_id_2); for (std::size_t i = 0; i < sizeof(seed.keygen_salt); i++) { output.emplace_back(static_cast(seed.keygen_salt[i] ^ key.xor_pad[i])); @@ -250,14 +254,15 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou reinterpret_cast(&out_data.settings)); // Copy the rest of the data directly - out_data.uuid2 = in_data.uuid2; + out_data.uid = in_data.uid; + out_data.nintendo_id = in_data.nintendo_id; + out_data.lock_bytes = in_data.lock_bytes; out_data.static_lock = in_data.static_lock; out_data.compability_container = in_data.compability_container; out_data.constant_value = in_data.constant_value; out_data.write_counter = in_data.write_counter; - out_data.uuid = in_data.uuid; out_data.model_info = in_data.model_info; out_data.keygen_salt = in_data.keygen_salt; out_data.dynamic_lock = in_data.dynamic_lock; @@ -309,7 +314,7 @@ bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& t // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC! constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), - sizeof(HmacKey), reinterpret_cast(&tag_data.uuid), + sizeof(HmacKey), reinterpret_cast(&tag_data.uid), input_length, reinterpret_cast(&tag_data.hmac_tag)); // Regenerate data HMAC @@ -350,7 +355,7 @@ bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_t constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; constexpr std::size_t input_length2 = HMAC_TAG_START - WRITE_COUNTER_START; mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), - sizeof(HmacKey), reinterpret_cast(&tag_data.uuid), + sizeof(HmacKey), reinterpret_cast(&tag_data.uid), input_length, reinterpret_cast(&encoded_tag_data.hmac_tag)); // Init mbedtls HMAC context @@ -364,7 +369,7 @@ bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_t input_length2); // Data mbedtls_md_hmac_update(&ctx, reinterpret_cast(&encoded_tag_data.hmac_tag), sizeof(HashData)); // Tag HMAC - mbedtls_md_hmac_update(&ctx, reinterpret_cast(&tag_data.uuid), + mbedtls_md_hmac_update(&ctx, reinterpret_cast(&tag_data.uid), input_length); mbedtls_md_hmac_finish(&ctx, reinterpret_cast(&encoded_tag_data.hmac_data)); diff --git a/src/core/hle/service/nfp/amiibo_crypto.h b/src/core/hle/service/nfp/amiibo_crypto.h index e3fa3d07e4..0175ced919 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.h +++ b/src/core/hle/service/nfp/amiibo_crypto.h @@ -24,8 +24,10 @@ using DrgbOutput = std::array; struct HashSeed { u16_be magic; std::array padding; - std::array uuid1; - std::array uuid2; + UniqueSerialNumber uid_1; + u8 nintendo_id_1; + UniqueSerialNumber uid_2; + u8 nintendo_id_2; std::array keygen_salt; }; static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size"); diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index ce3bcccf45..f0eaa7df2d 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -22,6 +22,9 @@ #include "core/hle/service/nfp/nfp_device.h" #include "core/hle/service/nfp/nfp_result.h" #include "core/hle/service/nfp/nfp_user.h" +#include "core/hle/service/time/time_manager.h" +#include "core/hle/service/time/time_zone_content_manager.h" +#include "core/hle/service/time/time_zone_types.h" namespace Service::NFP { NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, @@ -39,6 +42,9 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, }; is_controller_set = true; callback_key = npad_device->SetCallback(engine_callback); + + auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; + current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point; } NfpDevice::~NfpDevice() { @@ -98,6 +104,7 @@ bool NfpDevice::LoadAmiibo(const std::vector& data) { } device_state = DeviceState::TagFound; + deactivate_event->GetReadableEvent().Clear(); activate_event->GetWritableEvent().Signal(); return true; } @@ -112,6 +119,7 @@ void NfpDevice::CloseAmiibo() { device_state = DeviceState::TagRemoved; encrypted_tag_data = {}; tag_data = {}; + activate_event->GetReadableEvent().Clear(); deactivate_event->GetWritableEvent().Signal(); } @@ -140,8 +148,6 @@ void NfpDevice::Finalize() { } Result NfpDevice::StartDetection(s32 protocol_) { - // TODO(german77): Add callback for when nfc data is available - if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { npad_device->SetPollingMode(Common::Input::PollingMode::NFC); device_state = DeviceState::SearchingForTag; @@ -172,11 +178,9 @@ Result NfpDevice::StopDetection() { Result NfpDevice::Flush() { auto& settings = tag_data.settings; - if (settings.write_date.raw_date != settings.write_date.raw_date) { - // TODO: Read current system date - settings.write_date.SetYear(2022); - settings.write_date.SetMonth(9); - settings.write_date.SetDay(9); + const auto& current_date = GetAmiiboDate(current_posix_time); + if (settings.write_date.raw_date != current_date.raw_date) { + settings.write_date = current_date; settings.crc_counter++; // TODO: Find how to calculate the crc check // settings.crc = CalculateCRC(settings); @@ -239,10 +243,10 @@ Result NfpDevice::GetTagInfo(TagInfo& tag_info) const { } tag_info = { - .uuid = encrypted_tag_data.uuid, - .uuid_length = static_cast(encrypted_tag_data.uuid.size()), - .protocol = protocol, - .tag_type = static_cast(encrypted_tag_data.user_memory.model_info.amiibo_type), + .uuid = encrypted_tag_data.uuid.uid, + .uuid_length = static_cast(encrypted_tag_data.uuid.uid.size()), + .protocol = 1, + .tag_type = 2, }; return ResultSuccess; @@ -255,8 +259,6 @@ Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const { } const auto& settings = tag_data.settings; - const u32 application_area_size = - tag_data.settings.settings.appdata_initialized == 0 ? 0 : sizeof(ApplicationArea); // TODO: Validate this data common_info = { @@ -267,8 +269,8 @@ Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const { settings.write_date.GetDay(), }, .write_counter = tag_data.write_counter, - .version = 1, - .application_area_size = application_area_size, + .version = 0, + .application_area_size = sizeof(ApplicationArea), }; return ResultSuccess; } @@ -334,13 +336,8 @@ Result NfpDevice::SetNicknameAndOwner(const AmiiboName& amiibo_name) { Service::Mii::MiiManager manager; auto& settings = tag_data.settings; - // TODO: Read current system date - settings.init_date.SetYear(2022); - settings.init_date.SetMonth(9); - settings.init_date.SetDay(9); - settings.write_date.SetYear(2022); - settings.write_date.SetMonth(9); - settings.write_date.SetDay(9); + settings.init_date = GetAmiiboDate(current_posix_time); + settings.write_date = GetAmiiboDate(current_posix_time); settings.crc_counter++; // TODO: Find how to calculate the crc check // settings.crc = CalculateCRC(settings); @@ -570,4 +567,23 @@ void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo } } +AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const { + const auto& time_zone_manager = + system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); + Time::TimeZone::CalendarInfo calendar_info{}; + AmiiboDate amiibo_date{}; + + amiibo_date.SetYear(2000); + amiibo_date.SetMonth(1); + amiibo_date.SetDay(1); + + if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) { + amiibo_date.SetYear(calendar_info.time.year); + amiibo_date.SetMonth(calendar_info.time.month); + amiibo_date.SetDay(calendar_info.time.day); + } + + return amiibo_date; +} + } // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 9ceb7b8fde..c020506a6b 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -75,6 +75,7 @@ private: AmiiboName GetAmiiboName(const AmiiboSettings& settings) const; void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name); + AmiiboDate GetAmiiboDate(s64 posix_time) const; bool is_controller_set{}; int callback_key; @@ -88,6 +89,7 @@ private: bool is_data_moddified{}; s32 protocol{}; + s64 current_posix_time{}; DeviceState device_state{DeviceState::Unavailable}; NTAG215File tag_data{}; diff --git a/src/core/hle/service/nfp/nfp_result.h b/src/core/hle/service/nfp/nfp_result.h index 15bc02b15d..ac259e2ff7 100644 --- a/src/core/hle/service/nfp/nfp_result.h +++ b/src/core/hle/service/nfp/nfp_result.h @@ -17,5 +17,6 @@ constexpr Result ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128); constexpr Result CorruptedData(ErrorModule::NFP, 144); constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152); constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168); +constexpr Result NotAnAmiibo(ErrorModule::NFP, 178); } // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 2685ae8fe5..4487918467 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -75,11 +75,19 @@ enum class AmiiboSeries : u8 { Diablo, }; -using TagUuid = std::array; +using UniqueSerialNumber = std::array; +using LockBytes = std::array; using HashData = std::array; using ApplicationArea = std::array; using AmiiboName = std::array; +struct TagUuid { + UniqueSerialNumber uid; + u8 nintendo_id; + LockBytes lock_bytes; +}; +static_assert(sizeof(TagUuid) == 10, "TagUuid is an invalid size"); + struct AmiiboDate { u16 raw_date{}; @@ -91,7 +99,7 @@ struct AmiiboDate { return static_cast(((GetValue() & 0xFE00) >> 9) + 2000); } u8 GetMonth() const { - return static_cast(((GetValue() & 0x01E0) >> 5) - 1); + return static_cast((GetValue() & 0x01E0) >> 5); } u8 GetDay() const { return static_cast(GetValue() & 0x001F); @@ -102,7 +110,7 @@ struct AmiiboDate { raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted); } void SetMonth(u8 month) { - const u16 month_converted = static_cast((month + 1) << 5); + const u16 month_converted = static_cast(month << 5); raw_date = Common::swap16((GetValue() & ~0x01E0) | month_converted); } void SetDay(u8 day) { @@ -137,7 +145,7 @@ struct AmiiboModelInfo { u16 character_id; u8 character_variant; AmiiboType amiibo_type; - u16 model_number; + u16_be model_number; AmiiboSeries series; u8 constant_value; // Must be 02 INSERT_PADDING_BYTES(0x4); // Unknown @@ -172,7 +180,7 @@ struct EncryptedAmiiboFile { static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); struct NTAG215File { - std::array uuid2; + LockBytes lock_bytes; // Tag UUID u16 static_lock; // Set defined pages as read only u32 compability_container; // Defines available memory HashData hmac_data; // Hash @@ -188,7 +196,8 @@ struct NTAG215File { HashData hash; // Probably a SHA256-HMAC hash? ApplicationArea application_area; // Encrypted Game data HashData hmac_tag; // Hash - std::array uuid; + UniqueSerialNumber uid; // Unique serial number + u8 nintendo_id; // Tag UUID AmiiboModelInfo model_info; HashData keygen_salt; // Salt u32 dynamic_lock; // Dynamic lock @@ -215,7 +224,8 @@ static_assert(std::is_trivially_copyable_v, "EncryptedNTAG215File must be trivially copyable."); struct TagInfo { - TagUuid uuid; + UniqueSerialNumber uuid; + INSERT_PADDING_BYTES(0x3); u8 uuid_length; INSERT_PADDING_BYTES(0x15); s32 protocol;