diff options
| author | 2023-03-10 13:55:28 -0500 | |
|---|---|---|
| committer | 2023-03-10 13:55:28 -0500 | |
| commit | e0bd27b674f961d16e8ac4ba9d125b69d080800d (patch) | |
| tree | bbcb999e72f40d50fe60a9d92cafff0cbf4204da /src | |
| parent | Merge pull request #9925 from ameerj/gl-sync-signal (diff) | |
| parent | service: nfp: Improve implementation (diff) | |
| download | yuzu-e0bd27b674f961d16e8ac4ba9d125b69d080800d.tar.gz yuzu-e0bd27b674f961d16e8ac4ba9d125b69d080800d.tar.xz yuzu-e0bd27b674f961d16e8ac4ba9d125b69d080800d.zip | |
Merge pull request #9928 from german77/super_nfp
service: nfp: Improve implementation
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/service/am/applets/applet_cabinet.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/amiibo_crypto.cpp | 14 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.cpp | 210 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.h | 9 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_types.h | 49 |
5 files changed, 234 insertions, 52 deletions
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index d0969b0f1..162687b29 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp | |||
| @@ -119,7 +119,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) | |||
| 119 | case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { | 119 | case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { |
| 120 | Service::NFP::AmiiboName name{}; | 120 | Service::NFP::AmiiboName name{}; |
| 121 | std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); | 121 | std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); |
| 122 | nfp_device->SetNicknameAndOwner(name); | 122 | nfp_device->SetRegisterInfoPrivate(name); |
| 123 | break; | 123 | break; |
| 124 | } | 124 | } |
| 125 | case Service::NFP::CabinetMode::StartGameDataEraser: | 125 | case Service::NFP::CabinetMode::StartGameDataEraser: |
| @@ -129,7 +129,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) | |||
| 129 | nfp_device->RestoreAmiibo(); | 129 | nfp_device->RestoreAmiibo(); |
| 130 | break; | 130 | break; |
| 131 | case Service::NFP::CabinetMode::StartFormatter: | 131 | case Service::NFP::CabinetMode::StartFormatter: |
| 132 | nfp_device->DeleteAllData(); | 132 | nfp_device->Format(); |
| 133 | break; | 133 | break; |
| 134 | default: | 134 | default: |
| 135 | UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); | 135 | UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); |
diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp index ffb2f959c..ddf04b1d7 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.cpp +++ b/src/core/hle/service/nfp/amiibo_crypto.cpp | |||
| @@ -80,13 +80,16 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { | |||
| 80 | encoded_data.hmac_data = nfc_data.user_memory.hmac_data; | 80 | encoded_data.hmac_data = nfc_data.user_memory.hmac_data; |
| 81 | encoded_data.constant_value = nfc_data.user_memory.constant_value; | 81 | encoded_data.constant_value = nfc_data.user_memory.constant_value; |
| 82 | encoded_data.write_counter = nfc_data.user_memory.write_counter; | 82 | encoded_data.write_counter = nfc_data.user_memory.write_counter; |
| 83 | encoded_data.amiibo_version = nfc_data.user_memory.amiibo_version; | ||
| 83 | encoded_data.settings = nfc_data.user_memory.settings; | 84 | encoded_data.settings = nfc_data.user_memory.settings; |
| 84 | encoded_data.owner_mii = nfc_data.user_memory.owner_mii; | 85 | encoded_data.owner_mii = nfc_data.user_memory.owner_mii; |
| 85 | encoded_data.title_id = nfc_data.user_memory.title_id; | 86 | encoded_data.application_id = nfc_data.user_memory.application_id; |
| 86 | encoded_data.applicaton_write_counter = nfc_data.user_memory.applicaton_write_counter; | 87 | encoded_data.application_write_counter = nfc_data.user_memory.application_write_counter; |
| 87 | encoded_data.application_area_id = nfc_data.user_memory.application_area_id; | 88 | encoded_data.application_area_id = nfc_data.user_memory.application_area_id; |
| 89 | encoded_data.application_id_byte = nfc_data.user_memory.application_id_byte; | ||
| 88 | encoded_data.unknown = nfc_data.user_memory.unknown; | 90 | encoded_data.unknown = nfc_data.user_memory.unknown; |
| 89 | encoded_data.unknown2 = nfc_data.user_memory.unknown2; | 91 | encoded_data.unknown2 = nfc_data.user_memory.unknown2; |
| 92 | encoded_data.application_area_crc = nfc_data.user_memory.application_area_crc; | ||
| 90 | encoded_data.application_area = nfc_data.user_memory.application_area; | 93 | encoded_data.application_area = nfc_data.user_memory.application_area; |
| 91 | encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag; | 94 | encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag; |
| 92 | encoded_data.lock_bytes = nfc_data.uuid.lock_bytes; | 95 | encoded_data.lock_bytes = nfc_data.uuid.lock_bytes; |
| @@ -111,13 +114,16 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { | |||
| 111 | nfc_data.user_memory.hmac_data = encoded_data.hmac_data; | 114 | nfc_data.user_memory.hmac_data = encoded_data.hmac_data; |
| 112 | nfc_data.user_memory.constant_value = encoded_data.constant_value; | 115 | nfc_data.user_memory.constant_value = encoded_data.constant_value; |
| 113 | nfc_data.user_memory.write_counter = encoded_data.write_counter; | 116 | nfc_data.user_memory.write_counter = encoded_data.write_counter; |
| 117 | nfc_data.user_memory.amiibo_version = encoded_data.amiibo_version; | ||
| 114 | nfc_data.user_memory.settings = encoded_data.settings; | 118 | nfc_data.user_memory.settings = encoded_data.settings; |
| 115 | nfc_data.user_memory.owner_mii = encoded_data.owner_mii; | 119 | nfc_data.user_memory.owner_mii = encoded_data.owner_mii; |
| 116 | nfc_data.user_memory.title_id = encoded_data.title_id; | 120 | nfc_data.user_memory.application_id = encoded_data.application_id; |
| 117 | nfc_data.user_memory.applicaton_write_counter = encoded_data.applicaton_write_counter; | 121 | nfc_data.user_memory.application_write_counter = encoded_data.application_write_counter; |
| 118 | nfc_data.user_memory.application_area_id = encoded_data.application_area_id; | 122 | nfc_data.user_memory.application_area_id = encoded_data.application_area_id; |
| 123 | nfc_data.user_memory.application_id_byte = encoded_data.application_id_byte; | ||
| 119 | nfc_data.user_memory.unknown = encoded_data.unknown; | 124 | nfc_data.user_memory.unknown = encoded_data.unknown; |
| 120 | nfc_data.user_memory.unknown2 = encoded_data.unknown2; | 125 | nfc_data.user_memory.unknown2 = encoded_data.unknown2; |
| 126 | nfc_data.user_memory.application_area_crc = encoded_data.application_area_crc; | ||
| 121 | nfc_data.user_memory.application_area = encoded_data.application_area; | 127 | nfc_data.user_memory.application_area = encoded_data.application_area; |
| 122 | nfc_data.user_memory.hmac_tag = encoded_data.hmac_tag; | 128 | nfc_data.user_memory.hmac_tag = encoded_data.hmac_tag; |
| 123 | nfc_data.user_memory.model_info = encoded_data.model_info; | 129 | nfc_data.user_memory.model_info = encoded_data.model_info; |
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 1bdc42741..ddff90d6a 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp | |||
| @@ -174,8 +174,8 @@ Result NfpDevice::StopDetection() { | |||
| 174 | 174 | ||
| 175 | if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { | 175 | if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { |
| 176 | CloseAmiibo(); | 176 | CloseAmiibo(); |
| 177 | return ResultSuccess; | ||
| 178 | } | 177 | } |
| 178 | |||
| 179 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { | 179 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { |
| 180 | device_state = DeviceState::Initialized; | 180 | device_state = DeviceState::Initialized; |
| 181 | return ResultSuccess; | 181 | return ResultSuccess; |
| @@ -204,9 +204,7 @@ Result NfpDevice::Flush() { | |||
| 204 | const auto& current_date = GetAmiiboDate(current_posix_time); | 204 | const auto& current_date = GetAmiiboDate(current_posix_time); |
| 205 | if (settings.write_date.raw_date != current_date.raw_date) { | 205 | if (settings.write_date.raw_date != current_date.raw_date) { |
| 206 | settings.write_date = current_date; | 206 | settings.write_date = current_date; |
| 207 | settings.crc_counter++; | 207 | UpdateSettingsCrc(); |
| 208 | // TODO: Find how to calculate the crc check | ||
| 209 | // settings.crc = CalculateCRC(settings); | ||
| 210 | } | 208 | } |
| 211 | 209 | ||
| 212 | tag_data.write_counter++; | 210 | tag_data.write_counter++; |
| @@ -318,7 +316,7 @@ Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const { | |||
| 318 | common_info = { | 316 | common_info = { |
| 319 | .last_write_date = settings.write_date.GetWriteDate(), | 317 | .last_write_date = settings.write_date.GetWriteDate(), |
| 320 | .write_counter = tag_data.write_counter, | 318 | .write_counter = tag_data.write_counter, |
| 321 | .version = 0, | 319 | .version = tag_data.amiibo_version, |
| 322 | .application_area_size = sizeof(ApplicationArea), | 320 | .application_area_size = sizeof(ApplicationArea), |
| 323 | }; | 321 | }; |
| 324 | return ResultSuccess; | 322 | return ResultSuccess; |
| @@ -370,13 +368,95 @@ Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const { | |||
| 370 | .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii), | 368 | .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii), |
| 371 | .creation_date = settings.init_date.GetWriteDate(), | 369 | .creation_date = settings.init_date.GetWriteDate(), |
| 372 | .amiibo_name = GetAmiiboName(settings), | 370 | .amiibo_name = GetAmiiboName(settings), |
| 373 | .font_region = {}, | 371 | .font_region = settings.settings.font_region, |
| 372 | }; | ||
| 373 | |||
| 374 | return ResultSuccess; | ||
| 375 | } | ||
| 376 | |||
| 377 | Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { | ||
| 378 | if (device_state != DeviceState::TagMounted) { | ||
| 379 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 380 | if (device_state == DeviceState::TagRemoved) { | ||
| 381 | return TagRemoved; | ||
| 382 | } | ||
| 383 | return WrongDeviceState; | ||
| 384 | } | ||
| 385 | |||
| 386 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 387 | LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||
| 388 | return WrongDeviceState; | ||
| 389 | } | ||
| 390 | |||
| 391 | u8 flags = static_cast<u8>(tag_data.settings.settings.raw >> 0x4); | ||
| 392 | if (tag_data.settings.settings.amiibo_initialized == 0) { | ||
| 393 | flags = flags & 0xfe; | ||
| 394 | } | ||
| 395 | |||
| 396 | u64 application_id = 0; | ||
| 397 | u32 application_area_id = 0; | ||
| 398 | AppAreaVersion app_area_version = AppAreaVersion::NotSet; | ||
| 399 | if (tag_data.settings.settings.appdata_initialized != 0) { | ||
| 400 | application_id = tag_data.application_id; | ||
| 401 | app_area_version = | ||
| 402 | static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf); | ||
| 403 | |||
| 404 | // Restore application id to original value | ||
| 405 | if (application_id >> 0x38 != 0) { | ||
| 406 | const u8 application_byte = tag_data.application_id_byte & 0xf; | ||
| 407 | application_id = RemoveVersionByte(application_id) | | ||
| 408 | (static_cast<u64>(application_byte) << application_id_version_offset); | ||
| 409 | } | ||
| 410 | |||
| 411 | application_area_id = tag_data.application_area_id; | ||
| 412 | } | ||
| 413 | |||
| 414 | // TODO: Validate this data | ||
| 415 | admin_info = { | ||
| 416 | .application_id = application_id, | ||
| 417 | .application_area_id = application_area_id, | ||
| 418 | .crc_change_counter = tag_data.settings.crc_counter, | ||
| 419 | .flags = flags, | ||
| 420 | .tag_type = PackedTagType::Type2, | ||
| 421 | .app_area_version = app_area_version, | ||
| 374 | }; | 422 | }; |
| 375 | 423 | ||
| 376 | return ResultSuccess; | 424 | return ResultSuccess; |
| 377 | } | 425 | } |
| 378 | 426 | ||
| 379 | Result NfpDevice::SetNicknameAndOwner(const AmiiboName& amiibo_name) { | 427 | Result NfpDevice::DeleteRegisterInfo() { |
| 428 | if (device_state != DeviceState::TagMounted) { | ||
| 429 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 430 | if (device_state == DeviceState::TagRemoved) { | ||
| 431 | return TagRemoved; | ||
| 432 | } | ||
| 433 | return WrongDeviceState; | ||
| 434 | } | ||
| 435 | |||
| 436 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 437 | LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||
| 438 | return WrongDeviceState; | ||
| 439 | } | ||
| 440 | |||
| 441 | if (tag_data.settings.settings.amiibo_initialized == 0) { | ||
| 442 | return RegistrationIsNotInitialized; | ||
| 443 | } | ||
| 444 | |||
| 445 | Common::TinyMT rng{}; | ||
| 446 | rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii)); | ||
| 447 | rng.GenerateRandomBytes(&tag_data.settings.amiibo_name, sizeof(tag_data.settings.amiibo_name)); | ||
| 448 | rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8)); | ||
| 449 | rng.GenerateRandomBytes(&tag_data.unknown2[0], sizeof(u32)); | ||
| 450 | rng.GenerateRandomBytes(&tag_data.unknown2[1], sizeof(u32)); | ||
| 451 | rng.GenerateRandomBytes(&tag_data.application_area_crc, sizeof(u32)); | ||
| 452 | rng.GenerateRandomBytes(&tag_data.settings.init_date, sizeof(u32)); | ||
| 453 | tag_data.settings.settings.font_region.Assign(0); | ||
| 454 | tag_data.settings.settings.amiibo_initialized.Assign(0); | ||
| 455 | |||
| 456 | return Flush(); | ||
| 457 | } | ||
| 458 | |||
| 459 | Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) { | ||
| 380 | if (device_state != DeviceState::TagMounted) { | 460 | if (device_state != DeviceState::TagMounted) { |
| 381 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | 461 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); |
| 382 | if (device_state == DeviceState::TagRemoved) { | 462 | if (device_state == DeviceState::TagRemoved) { |
| @@ -393,16 +473,23 @@ Result NfpDevice::SetNicknameAndOwner(const AmiiboName& amiibo_name) { | |||
| 393 | Service::Mii::MiiManager manager; | 473 | Service::Mii::MiiManager manager; |
| 394 | auto& settings = tag_data.settings; | 474 | auto& settings = tag_data.settings; |
| 395 | 475 | ||
| 396 | settings.init_date = GetAmiiboDate(current_posix_time); | 476 | if (tag_data.settings.settings.amiibo_initialized == 0) { |
| 397 | settings.write_date = GetAmiiboDate(current_posix_time); | 477 | settings.init_date = GetAmiiboDate(current_posix_time); |
| 398 | settings.crc_counter++; | 478 | settings.write_date.raw_date = 0; |
| 399 | // TODO: Find how to calculate the crc check | 479 | } |
| 400 | // settings.crc = CalculateCRC(settings); | ||
| 401 | 480 | ||
| 402 | SetAmiiboName(settings, amiibo_name); | 481 | SetAmiiboName(settings, amiibo_name); |
| 403 | tag_data.owner_mii = manager.ConvertCharInfoToV3(manager.BuildDefault(0)); | 482 | tag_data.owner_mii = manager.ConvertCharInfoToV3(manager.BuildDefault(0)); |
| 483 | tag_data.unknown = 0; | ||
| 484 | tag_data.unknown2[6] = 0; | ||
| 485 | settings.country_code_id = 0; | ||
| 486 | settings.settings.font_region.Assign(0); | ||
| 404 | settings.settings.amiibo_initialized.Assign(1); | 487 | settings.settings.amiibo_initialized.Assign(1); |
| 405 | 488 | ||
| 489 | // TODO: this is a mix of tag.file input | ||
| 490 | std::array<u8, 0x7e> unknown_input{}; | ||
| 491 | tag_data.application_area_crc = CalculateCrc(unknown_input); | ||
| 492 | |||
| 406 | return Flush(); | 493 | return Flush(); |
| 407 | } | 494 | } |
| 408 | 495 | ||
| @@ -425,23 +512,17 @@ Result NfpDevice::RestoreAmiibo() { | |||
| 425 | return ResultSuccess; | 512 | return ResultSuccess; |
| 426 | } | 513 | } |
| 427 | 514 | ||
| 428 | Result NfpDevice::DeleteAllData() { | 515 | Result NfpDevice::Format() { |
| 429 | const auto result = DeleteApplicationArea(); | 516 | auto result1 = DeleteApplicationArea(); |
| 430 | if (result.IsError()) { | 517 | auto result2 = DeleteRegisterInfo(); |
| 431 | return result; | ||
| 432 | } | ||
| 433 | 518 | ||
| 434 | if (device_state != DeviceState::TagMounted) { | 519 | if (result1.IsError()) { |
| 435 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | 520 | return result1; |
| 436 | if (device_state == DeviceState::TagRemoved) { | ||
| 437 | return TagRemoved; | ||
| 438 | } | ||
| 439 | return WrongDeviceState; | ||
| 440 | } | 521 | } |
| 441 | 522 | ||
| 442 | Common::TinyMT rng{}; | 523 | if (result2.IsError()) { |
| 443 | rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii)); | 524 | return result2; |
| 444 | tag_data.settings.settings.amiibo_initialized.Assign(0); | 525 | } |
| 445 | 526 | ||
| 446 | return Flush(); | 527 | return Flush(); |
| 447 | } | 528 | } |
| @@ -569,7 +650,10 @@ Result NfpDevice::SetApplicationArea(std::span<const u8> data) { | |||
| 569 | rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), | 650 | rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), |
| 570 | sizeof(ApplicationArea) - data.size()); | 651 | sizeof(ApplicationArea) - data.size()); |
| 571 | 652 | ||
| 572 | tag_data.applicaton_write_counter++; | 653 | if (tag_data.application_write_counter != counter_limit) { |
| 654 | tag_data.application_write_counter++; | ||
| 655 | } | ||
| 656 | |||
| 573 | is_data_moddified = true; | 657 | is_data_moddified = true; |
| 574 | 658 | ||
| 575 | return ResultSuccess; | 659 | return ResultSuccess; |
| @@ -617,14 +701,25 @@ Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat | |||
| 617 | rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), | 701 | rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), |
| 618 | sizeof(ApplicationArea) - data.size()); | 702 | sizeof(ApplicationArea) - data.size()); |
| 619 | 703 | ||
| 620 | // TODO: Investigate why the title id needs to be moddified | 704 | if (tag_data.application_write_counter != counter_limit) { |
| 621 | tag_data.title_id = system.GetApplicationProcessProgramID(); | 705 | tag_data.application_write_counter++; |
| 622 | tag_data.title_id = tag_data.title_id | 0x30000000ULL; | 706 | } |
| 707 | |||
| 708 | const u64 application_id = system.GetApplicationProcessProgramID(); | ||
| 709 | |||
| 710 | tag_data.application_id_byte = | ||
| 711 | static_cast<u8>(application_id >> application_id_version_offset & 0xf); | ||
| 712 | tag_data.application_id = | ||
| 713 | RemoveVersionByte(application_id) | | ||
| 714 | (static_cast<u64>(AppAreaVersion::NintendoSwitch) << application_id_version_offset); | ||
| 623 | tag_data.settings.settings.appdata_initialized.Assign(1); | 715 | tag_data.settings.settings.appdata_initialized.Assign(1); |
| 624 | tag_data.application_area_id = access_id; | 716 | tag_data.application_area_id = access_id; |
| 625 | tag_data.applicaton_write_counter++; | ||
| 626 | tag_data.unknown = {}; | 717 | tag_data.unknown = {}; |
| 627 | 718 | ||
| 719 | // TODO: this is a mix of tag_data input | ||
| 720 | std::array<u8, 0x7e> unknown_input{}; | ||
| 721 | tag_data.application_area_crc = CalculateCrc(unknown_input); | ||
| 722 | |||
| 628 | return Flush(); | 723 | return Flush(); |
| 629 | } | 724 | } |
| 630 | 725 | ||
| @@ -642,12 +737,20 @@ Result NfpDevice::DeleteApplicationArea() { | |||
| 642 | return WrongDeviceState; | 737 | return WrongDeviceState; |
| 643 | } | 738 | } |
| 644 | 739 | ||
| 740 | if (tag_data.settings.settings.appdata_initialized == 0) { | ||
| 741 | return ApplicationAreaIsNotInitialized; | ||
| 742 | } | ||
| 743 | |||
| 744 | if (tag_data.application_write_counter != counter_limit) { | ||
| 745 | tag_data.application_write_counter++; | ||
| 746 | } | ||
| 747 | |||
| 645 | Common::TinyMT rng{}; | 748 | Common::TinyMT rng{}; |
| 646 | rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(ApplicationArea)); | 749 | rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(ApplicationArea)); |
| 647 | rng.GenerateRandomBytes(&tag_data.title_id, sizeof(u64)); | 750 | rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64)); |
| 648 | rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32)); | 751 | rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32)); |
| 752 | rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8)); | ||
| 649 | tag_data.settings.settings.appdata_initialized.Assign(0); | 753 | tag_data.settings.settings.appdata_initialized.Assign(0); |
| 650 | tag_data.applicaton_write_counter++; | ||
| 651 | tag_data.unknown = {}; | 754 | tag_data.unknown = {}; |
| 652 | 755 | ||
| 653 | return Flush(); | 756 | return Flush(); |
| @@ -719,4 +822,45 @@ AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const { | |||
| 719 | return amiibo_date; | 822 | return amiibo_date; |
| 720 | } | 823 | } |
| 721 | 824 | ||
| 825 | u64 NfpDevice::RemoveVersionByte(u64 application_id) const { | ||
| 826 | return application_id & ~(0xfULL << application_id_version_offset); | ||
| 827 | } | ||
| 828 | |||
| 829 | void NfpDevice::UpdateSettingsCrc() { | ||
| 830 | auto& settings = tag_data.settings; | ||
| 831 | |||
| 832 | if (settings.crc_counter != counter_limit) { | ||
| 833 | settings.crc_counter++; | ||
| 834 | } | ||
| 835 | |||
| 836 | // TODO: this reads data from a global, find what it is | ||
| 837 | std::array<u8, 8> unknown_input{}; | ||
| 838 | settings.crc = CalculateCrc(unknown_input); | ||
| 839 | } | ||
| 840 | |||
| 841 | u32 NfpDevice::CalculateCrc(std::span<const u8> data) { | ||
| 842 | constexpr u32 magic = 0xedb88320; | ||
| 843 | u32 crc = 0xffffffff; | ||
| 844 | |||
| 845 | if (data.size() == 0) { | ||
| 846 | return 0; | ||
| 847 | } | ||
| 848 | |||
| 849 | for (u8 input : data) { | ||
| 850 | u32 temp = (crc ^ input) >> 1; | ||
| 851 | if (((crc ^ input) & 1) != 0) { | ||
| 852 | temp = temp ^ magic; | ||
| 853 | } | ||
| 854 | |||
| 855 | for (std::size_t step = 0; step < 7; ++step) { | ||
| 856 | crc = temp >> 1; | ||
| 857 | if ((temp & 1) != 0) { | ||
| 858 | crc = temp >> 1 ^ magic; | ||
| 859 | } | ||
| 860 | } | ||
| 861 | } | ||
| 862 | |||
| 863 | return ~crc; | ||
| 864 | } | ||
| 865 | |||
| 722 | } // namespace Service::NFP | 866 | } // namespace Service::NFP |
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index b6a46f2ac..06386401d 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h | |||
| @@ -47,10 +47,12 @@ public: | |||
| 47 | Result GetCommonInfo(CommonInfo& common_info) const; | 47 | Result GetCommonInfo(CommonInfo& common_info) const; |
| 48 | Result GetModelInfo(ModelInfo& model_info) const; | 48 | Result GetModelInfo(ModelInfo& model_info) const; |
| 49 | Result GetRegisterInfo(RegisterInfo& register_info) const; | 49 | Result GetRegisterInfo(RegisterInfo& register_info) const; |
| 50 | Result GetAdminInfo(AdminInfo& admin_info) const; | ||
| 50 | 51 | ||
| 51 | Result SetNicknameAndOwner(const AmiiboName& amiibo_name); | 52 | Result DeleteRegisterInfo(); |
| 53 | Result SetRegisterInfoPrivate(const AmiiboName& amiibo_name); | ||
| 52 | Result RestoreAmiibo(); | 54 | Result RestoreAmiibo(); |
| 53 | Result DeleteAllData(); | 55 | Result Format(); |
| 54 | 56 | ||
| 55 | Result OpenApplicationArea(u32 access_id); | 57 | Result OpenApplicationArea(u32 access_id); |
| 56 | Result GetApplicationAreaId(u32& application_area_id) const; | 58 | Result GetApplicationAreaId(u32& application_area_id) const; |
| @@ -76,6 +78,9 @@ private: | |||
| 76 | AmiiboName GetAmiiboName(const AmiiboSettings& settings) const; | 78 | AmiiboName GetAmiiboName(const AmiiboSettings& settings) const; |
| 77 | void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name); | 79 | void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name); |
| 78 | AmiiboDate GetAmiiboDate(s64 posix_time) const; | 80 | AmiiboDate GetAmiiboDate(s64 posix_time) const; |
| 81 | u64 RemoveVersionByte(u64 application_id) const; | ||
| 82 | void UpdateSettingsCrc(); | ||
| 83 | u32 CalculateCrc(std::span<const u8>); | ||
| 79 | 84 | ||
| 80 | bool is_controller_set{}; | 85 | bool is_controller_set{}; |
| 81 | int callback_key; | 86 | int callback_key; |
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index fc228c2b2..142343d6e 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h | |||
| @@ -10,6 +10,8 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::NFP { | 11 | namespace Service::NFP { |
| 12 | static constexpr std::size_t amiibo_name_length = 0xA; | 12 | static constexpr std::size_t amiibo_name_length = 0xA; |
| 13 | static constexpr std::size_t application_id_version_offset = 0x1c; | ||
| 14 | static constexpr std::size_t counter_limit = 0xffff; | ||
| 13 | 15 | ||
| 14 | enum class ServiceType : u32 { | 16 | enum class ServiceType : u32 { |
| 15 | User, | 17 | User, |
| @@ -99,6 +101,14 @@ enum class TagProtocol : u32 { | |||
| 99 | All = 0xFFFFFFFFU, | 101 | All = 0xFFFFFFFFU, |
| 100 | }; | 102 | }; |
| 101 | 103 | ||
| 104 | enum class AppAreaVersion : u8 { | ||
| 105 | Nintendo3DS = 0, | ||
| 106 | NintendoWiiU = 1, | ||
| 107 | Nintendo3DSv2 = 2, | ||
| 108 | NintendoSwitch = 3, | ||
| 109 | NotSet = 0xFF, | ||
| 110 | }; | ||
| 111 | |||
| 102 | enum class CabinetMode : u8 { | 112 | enum class CabinetMode : u8 { |
| 103 | StartNicknameAndOwnerSettings, | 113 | StartNicknameAndOwnerSettings, |
| 104 | StartGameDataEraser, | 114 | StartGameDataEraser, |
| @@ -197,6 +207,7 @@ struct Settings { | |||
| 197 | union { | 207 | union { |
| 198 | u8 raw{}; | 208 | u8 raw{}; |
| 199 | 209 | ||
| 210 | BitField<0, 4, u8> font_region; | ||
| 200 | BitField<4, 1, u8> amiibo_initialized; | 211 | BitField<4, 1, u8> amiibo_initialized; |
| 201 | BitField<5, 1, u8> appdata_initialized; | 212 | BitField<5, 1, u8> appdata_initialized; |
| 202 | }; | 213 | }; |
| @@ -236,18 +247,20 @@ static_assert(sizeof(NTAG215Password) == 0x8, "NTAG215Password is an invalid siz | |||
| 236 | struct EncryptedAmiiboFile { | 247 | struct EncryptedAmiiboFile { |
| 237 | u8 constant_value; // Must be A5 | 248 | u8 constant_value; // Must be A5 |
| 238 | u16_be write_counter; // Number of times the amiibo has been written? | 249 | u16_be write_counter; // Number of times the amiibo has been written? |
| 239 | INSERT_PADDING_BYTES(0x1); // Unknown 1 | 250 | u8 amiibo_version; // Amiibo file version |
| 240 | AmiiboSettings settings; // Encrypted amiibo settings | 251 | AmiiboSettings settings; // Encrypted amiibo settings |
| 241 | HashData hmac_tag; // Hash | 252 | HashData hmac_tag; // Hash |
| 242 | AmiiboModelInfo model_info; // Encrypted amiibo model info | 253 | AmiiboModelInfo model_info; // Encrypted amiibo model info |
| 243 | HashData keygen_salt; // Salt | 254 | HashData keygen_salt; // Salt |
| 244 | HashData hmac_data; // Hash | 255 | HashData hmac_data; // Hash |
| 245 | Service::Mii::Ver3StoreData owner_mii; // Encrypted Mii data | 256 | Service::Mii::Ver3StoreData owner_mii; // Encrypted Mii data |
| 246 | u64_be title_id; // Encrypted Game id | 257 | u64_be application_id; // Encrypted Game id |
| 247 | u16_be applicaton_write_counter; // Encrypted Counter | 258 | u16_be application_write_counter; // Encrypted Counter |
| 248 | u32_be application_area_id; // Encrypted Game id | 259 | u32_be application_area_id; // Encrypted Game id |
| 249 | std::array<u8, 0x2> unknown; | 260 | u8 application_id_byte; |
| 250 | std::array<u32, 0x8> unknown2; | 261 | u8 unknown; |
| 262 | std::array<u32, 0x7> unknown2; | ||
| 263 | u32_be application_area_crc; | ||
| 251 | ApplicationArea application_area; // Encrypted Game data | 264 | ApplicationArea application_area; // Encrypted Game data |
| 252 | }; | 265 | }; |
| 253 | static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); | 266 | static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); |
| @@ -259,14 +272,16 @@ struct NTAG215File { | |||
| 259 | HashData hmac_data; // Hash | 272 | HashData hmac_data; // Hash |
| 260 | u8 constant_value; // Must be A5 | 273 | u8 constant_value; // Must be A5 |
| 261 | u16_be write_counter; // Number of times the amiibo has been written? | 274 | u16_be write_counter; // Number of times the amiibo has been written? |
| 262 | INSERT_PADDING_BYTES(0x1); // Unknown 1 | 275 | u8 amiibo_version; // Amiibo file version |
| 263 | AmiiboSettings settings; | 276 | AmiiboSettings settings; |
| 264 | Service::Mii::Ver3StoreData owner_mii; // Encrypted Mii data | 277 | Service::Mii::Ver3StoreData owner_mii; // Mii data |
| 265 | u64_be title_id; | 278 | u64_be application_id; // Game id |
| 266 | u16_be applicaton_write_counter; // Encrypted Counter | 279 | u16_be application_write_counter; // Counter |
| 267 | u32_be application_area_id; | 280 | u32_be application_area_id; |
| 268 | std::array<u8, 0x2> unknown; | 281 | u8 application_id_byte; |
| 269 | std::array<u32, 0x8> unknown2; | 282 | u8 unknown; |
| 283 | std::array<u32, 0x7> unknown2; | ||
| 284 | u32_be application_area_crc; | ||
| 270 | ApplicationArea application_area; // Encrypted Game data | 285 | ApplicationArea application_area; // Encrypted Game data |
| 271 | HashData hmac_tag; // Hash | 286 | HashData hmac_tag; // Hash |
| 272 | UniqueSerialNumber uid; // Unique serial number | 287 | UniqueSerialNumber uid; // Unique serial number |
| @@ -336,6 +351,18 @@ struct RegisterInfo { | |||
| 336 | }; | 351 | }; |
| 337 | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); | 352 | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); |
| 338 | 353 | ||
| 354 | struct AdminInfo { | ||
| 355 | u64 application_id; | ||
| 356 | u32 application_area_id; | ||
| 357 | u16 crc_change_counter; | ||
| 358 | u8 flags; | ||
| 359 | PackedTagType tag_type; | ||
| 360 | AppAreaVersion app_area_version; | ||
| 361 | INSERT_PADDING_BYTES(0x7); | ||
| 362 | INSERT_PADDING_BYTES(0x28); | ||
| 363 | }; | ||
| 364 | static_assert(sizeof(AdminInfo) == 0x40, "AdminInfo is an invalid size"); | ||
| 365 | |||
| 339 | struct SectorKey { | 366 | struct SectorKey { |
| 340 | MifareCmd command; | 367 | MifareCmd command; |
| 341 | u8 unknown; // Usually 1 | 368 | u8 unknown; // Usually 1 |