diff options
| -rw-r--r-- | src/core/hle/service/mii/mii_manager.cpp | 68 | ||||
| -rw-r--r-- | src/core/hle/service/mii/mii_manager.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/nfc/nfc.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/amiibo_crypto.cpp | 55 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/amiibo_crypto.h | 6 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.cpp | 60 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_result.h | 1 | ||||
| -rw-r--r-- | 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 3e92152ec..4bc8703e1 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 { | |||
| 431 | Service::Mii::MiiManager manager; | 431 | Service::Mii::MiiManager manager; |
| 432 | auto mii = manager.BuildDefault(0); | 432 | auto mii = manager.BuildDefault(0); |
| 433 | 433 | ||
| 434 | // Check if mii data exist | 434 | if (!ValidateV3Info(mii_v3)) { |
| 435 | if (mii_v3.version == 0) { | ||
| 436 | return mii; | 435 | return mii; |
| 437 | } | 436 | } |
| 438 | 437 | ||
| @@ -576,6 +575,71 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const { | |||
| 576 | return mii_v3; | 575 | return mii_v3; |
| 577 | } | 576 | } |
| 578 | 577 | ||
| 578 | bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const { | ||
| 579 | bool is_valid = mii_v3.version == 0 || mii_v3.version == 3; | ||
| 580 | |||
| 581 | is_valid = is_valid && (mii_v3.mii_name[0] != 0); | ||
| 582 | |||
| 583 | is_valid = is_valid && (mii_v3.mii_information.birth_month < 13); | ||
| 584 | is_valid = is_valid && (mii_v3.mii_information.birth_day < 32); | ||
| 585 | is_valid = is_valid && (mii_v3.mii_information.favorite_color < 12); | ||
| 586 | is_valid = is_valid && (mii_v3.height < 128); | ||
| 587 | is_valid = is_valid && (mii_v3.build < 128); | ||
| 588 | |||
| 589 | is_valid = is_valid && (mii_v3.appearance_bits1.face_shape < 12); | ||
| 590 | is_valid = is_valid && (mii_v3.appearance_bits1.skin_color < 7); | ||
| 591 | is_valid = is_valid && (mii_v3.appearance_bits2.wrinkles < 12); | ||
| 592 | is_valid = is_valid && (mii_v3.appearance_bits2.makeup < 12); | ||
| 593 | |||
| 594 | is_valid = is_valid && (mii_v3.hair_style < 132); | ||
| 595 | is_valid = is_valid && (mii_v3.appearance_bits3.hair_color < 8); | ||
| 596 | |||
| 597 | is_valid = is_valid && (mii_v3.appearance_bits4.eye_type < 60); | ||
| 598 | is_valid = is_valid && (mii_v3.appearance_bits4.eye_color < 6); | ||
| 599 | is_valid = is_valid && (mii_v3.appearance_bits4.eye_scale < 8); | ||
| 600 | is_valid = is_valid && (mii_v3.appearance_bits4.eye_vertical_stretch < 7); | ||
| 601 | is_valid = is_valid && (mii_v3.appearance_bits4.eye_rotation < 8); | ||
| 602 | is_valid = is_valid && (mii_v3.appearance_bits4.eye_spacing < 13); | ||
| 603 | is_valid = is_valid && (mii_v3.appearance_bits4.eye_y_position < 19); | ||
| 604 | |||
| 605 | is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_style < 25); | ||
| 606 | is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_color < 8); | ||
| 607 | is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_scale < 9); | ||
| 608 | is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_yscale < 7); | ||
| 609 | is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_rotation < 12); | ||
| 610 | is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_spacing < 12); | ||
| 611 | is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_y_position < 19); | ||
| 612 | |||
| 613 | is_valid = is_valid && (mii_v3.appearance_bits6.nose_type < 18); | ||
| 614 | is_valid = is_valid && (mii_v3.appearance_bits6.nose_scale < 9); | ||
| 615 | is_valid = is_valid && (mii_v3.appearance_bits6.nose_y_position < 19); | ||
| 616 | |||
| 617 | is_valid = is_valid && (mii_v3.appearance_bits7.mouth_type < 36); | ||
| 618 | is_valid = is_valid && (mii_v3.appearance_bits7.mouth_color < 5); | ||
| 619 | is_valid = is_valid && (mii_v3.appearance_bits7.mouth_scale < 9); | ||
| 620 | is_valid = is_valid && (mii_v3.appearance_bits7.mouth_horizontal_stretch < 7); | ||
| 621 | is_valid = is_valid && (mii_v3.appearance_bits8.mouth_y_position < 19); | ||
| 622 | |||
| 623 | is_valid = is_valid && (mii_v3.appearance_bits8.mustache_type < 6); | ||
| 624 | is_valid = is_valid && (mii_v3.appearance_bits9.mustache_scale < 7); | ||
| 625 | is_valid = is_valid && (mii_v3.appearance_bits9.mustache_y_position < 17); | ||
| 626 | |||
| 627 | is_valid = is_valid && (mii_v3.appearance_bits9.bear_type < 6); | ||
| 628 | is_valid = is_valid && (mii_v3.appearance_bits9.facial_hair_color < 8); | ||
| 629 | |||
| 630 | is_valid = is_valid && (mii_v3.appearance_bits10.glasses_type < 9); | ||
| 631 | is_valid = is_valid && (mii_v3.appearance_bits10.glasses_color < 6); | ||
| 632 | is_valid = is_valid && (mii_v3.appearance_bits10.glasses_scale < 8); | ||
| 633 | is_valid = is_valid && (mii_v3.appearance_bits10.glasses_y_position < 21); | ||
| 634 | |||
| 635 | is_valid = is_valid && (mii_v3.appearance_bits11.mole_enabled < 2); | ||
| 636 | is_valid = is_valid && (mii_v3.appearance_bits11.mole_scale < 9); | ||
| 637 | is_valid = is_valid && (mii_v3.appearance_bits11.mole_x_position < 17); | ||
| 638 | is_valid = is_valid && (mii_v3.appearance_bits11.mole_y_position < 31); | ||
| 639 | |||
| 640 | return is_valid; | ||
| 641 | } | ||
| 642 | |||
| 579 | ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) { | 643 | ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) { |
| 580 | std::vector<MiiInfoElement> result; | 644 | std::vector<MiiInfoElement> result; |
| 581 | 645 | ||
diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index b68fdd54c..83ad3d343 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h | |||
| @@ -24,6 +24,7 @@ public: | |||
| 24 | CharInfo BuildDefault(std::size_t index); | 24 | CharInfo BuildDefault(std::size_t index); |
| 25 | CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const; | 25 | CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const; |
| 26 | Ver3StoreData ConvertCharInfoToV3(const CharInfo& mii) const; | 26 | Ver3StoreData ConvertCharInfoToV3(const CharInfo& mii) const; |
| 27 | bool ValidateV3Info(const Ver3StoreData& mii_v3) const; | ||
| 27 | ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag); | 28 | ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag); |
| 28 | Result GetIndex(const CharInfo& info, u32& index); | 29 | Result GetIndex(const CharInfo& info, u32& index); |
| 29 | 30 | ||
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 13a843a28..046c5f18f 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp | |||
| @@ -106,10 +106,10 @@ public: | |||
| 106 | {1, &IUser::FinalizeOld, "FinalizeOld"}, | 106 | {1, &IUser::FinalizeOld, "FinalizeOld"}, |
| 107 | {2, &IUser::GetStateOld, "GetStateOld"}, | 107 | {2, &IUser::GetStateOld, "GetStateOld"}, |
| 108 | {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"}, | 108 | {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"}, |
| 109 | {400, nullptr, "Initialize"}, | 109 | {400, &IUser::InitializeOld, "Initialize"}, |
| 110 | {401, nullptr, "Finalize"}, | 110 | {401, &IUser::FinalizeOld, "Finalize"}, |
| 111 | {402, nullptr, "GetState"}, | 111 | {402, &IUser::GetStateOld, "GetState"}, |
| 112 | {403, nullptr, "IsNfcEnabled"}, | 112 | {403, &IUser::IsNfcEnabledOld, "IsNfcEnabled"}, |
| 113 | {404, nullptr, "ListDevices"}, | 113 | {404, nullptr, "ListDevices"}, |
| 114 | {405, nullptr, "GetDeviceState"}, | 114 | {405, nullptr, "GetDeviceState"}, |
| 115 | {406, nullptr, "GetNpadId"}, | 115 | {406, nullptr, "GetNpadId"}, |
diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp index c87da5ae4..9e06970a4 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) { | |||
| 25 | LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); | 25 | LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); |
| 26 | LOG_DEBUG(Service_NFP, "character_variant={}", amiibo_data.model_info.character_variant); | 26 | LOG_DEBUG(Service_NFP, "character_variant={}", amiibo_data.model_info.character_variant); |
| 27 | LOG_DEBUG(Service_NFP, "amiibo_type={}", amiibo_data.model_info.amiibo_type); | 27 | LOG_DEBUG(Service_NFP, "amiibo_type={}", amiibo_data.model_info.amiibo_type); |
| 28 | LOG_DEBUG(Service_NFP, "model_number=0x{0:x}", amiibo_data.model_info.model_number); | 28 | LOG_DEBUG(Service_NFP, "model_number=0x{0:x}", |
| 29 | static_cast<u16>(amiibo_data.model_info.model_number)); | ||
| 29 | LOG_DEBUG(Service_NFP, "series={}", amiibo_data.model_info.series); | 30 | LOG_DEBUG(Service_NFP, "series={}", amiibo_data.model_info.series); |
| 30 | LOG_DEBUG(Service_NFP, "fixed_value=0x{0:x}", amiibo_data.model_info.constant_value); | 31 | LOG_DEBUG(Service_NFP, "fixed_value=0x{0:x}", amiibo_data.model_info.constant_value); |
| 31 | 32 | ||
| @@ -35,11 +36,12 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { | |||
| 35 | 36 | ||
| 36 | // Validate UUID | 37 | // Validate UUID |
| 37 | constexpr u8 CT = 0x88; // As defined in `ISO / IEC 14443 - 3` | 38 | constexpr u8 CT = 0x88; // As defined in `ISO / IEC 14443 - 3` |
| 38 | if ((CT ^ ntag_file.uuid[0] ^ ntag_file.uuid[1] ^ ntag_file.uuid[2]) != ntag_file.uuid[3]) { | 39 | if ((CT ^ ntag_file.uuid.uid[0] ^ ntag_file.uuid.uid[1] ^ ntag_file.uuid.uid[2]) != |
| 40 | ntag_file.uuid.uid[3]) { | ||
| 39 | return false; | 41 | return false; |
| 40 | } | 42 | } |
| 41 | if ((ntag_file.uuid[4] ^ ntag_file.uuid[5] ^ ntag_file.uuid[6] ^ ntag_file.uuid[7]) != | 43 | if ((ntag_file.uuid.uid[4] ^ ntag_file.uuid.uid[5] ^ ntag_file.uuid.uid[6] ^ |
| 42 | ntag_file.uuid[8]) { | 44 | ntag_file.uuid.nintendo_id) != ntag_file.uuid.lock_bytes[0]) { |
| 43 | return false; | 45 | return false; |
| 44 | } | 46 | } |
| 45 | 47 | ||
| @@ -70,7 +72,8 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { | |||
| 70 | NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { | 72 | NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { |
| 71 | NTAG215File encoded_data{}; | 73 | NTAG215File encoded_data{}; |
| 72 | 74 | ||
| 73 | memcpy(encoded_data.uuid2.data(), nfc_data.uuid.data() + 0x8, sizeof(encoded_data.uuid2)); | 75 | encoded_data.uid = nfc_data.uuid.uid; |
| 76 | encoded_data.nintendo_id = nfc_data.uuid.nintendo_id; | ||
| 74 | encoded_data.static_lock = nfc_data.static_lock; | 77 | encoded_data.static_lock = nfc_data.static_lock; |
| 75 | encoded_data.compability_container = nfc_data.compability_container; | 78 | encoded_data.compability_container = nfc_data.compability_container; |
| 76 | encoded_data.hmac_data = nfc_data.user_memory.hmac_data; | 79 | encoded_data.hmac_data = nfc_data.user_memory.hmac_data; |
| @@ -85,7 +88,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { | |||
| 85 | encoded_data.hash = nfc_data.user_memory.hash; | 88 | encoded_data.hash = nfc_data.user_memory.hash; |
| 86 | encoded_data.application_area = nfc_data.user_memory.application_area; | 89 | encoded_data.application_area = nfc_data.user_memory.application_area; |
| 87 | encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag; | 90 | encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag; |
| 88 | memcpy(encoded_data.uuid.data(), nfc_data.uuid.data(), sizeof(encoded_data.uuid)); | 91 | encoded_data.lock_bytes = nfc_data.uuid.lock_bytes; |
| 89 | encoded_data.model_info = nfc_data.user_memory.model_info; | 92 | encoded_data.model_info = nfc_data.user_memory.model_info; |
| 90 | encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt; | 93 | encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt; |
| 91 | encoded_data.dynamic_lock = nfc_data.dynamic_lock; | 94 | encoded_data.dynamic_lock = nfc_data.dynamic_lock; |
| @@ -99,8 +102,9 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { | |||
| 99 | EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { | 102 | EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { |
| 100 | EncryptedNTAG215File nfc_data{}; | 103 | EncryptedNTAG215File nfc_data{}; |
| 101 | 104 | ||
| 102 | memcpy(nfc_data.uuid.data() + 0x8, encoded_data.uuid2.data(), sizeof(encoded_data.uuid2)); | 105 | nfc_data.uuid.uid = encoded_data.uid; |
| 103 | memcpy(nfc_data.uuid.data(), encoded_data.uuid.data(), sizeof(encoded_data.uuid)); | 106 | nfc_data.uuid.nintendo_id = encoded_data.nintendo_id; |
| 107 | nfc_data.uuid.lock_bytes = encoded_data.lock_bytes; | ||
| 104 | nfc_data.static_lock = encoded_data.static_lock; | 108 | nfc_data.static_lock = encoded_data.static_lock; |
| 105 | nfc_data.compability_container = encoded_data.compability_container; | 109 | nfc_data.compability_container = encoded_data.compability_container; |
| 106 | nfc_data.user_memory.hmac_data = encoded_data.hmac_data; | 110 | nfc_data.user_memory.hmac_data = encoded_data.hmac_data; |
| @@ -127,10 +131,10 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { | |||
| 127 | 131 | ||
| 128 | u32 GetTagPassword(const TagUuid& uuid) { | 132 | u32 GetTagPassword(const TagUuid& uuid) { |
| 129 | // Verifiy that the generated password is correct | 133 | // Verifiy that the generated password is correct |
| 130 | u32 password = 0xAA ^ (uuid[1] ^ uuid[3]); | 134 | u32 password = 0xAA ^ (uuid.uid[1] ^ uuid.uid[3]); |
| 131 | password &= (0x55 ^ (uuid[2] ^ uuid[4])) << 8; | 135 | password &= (0x55 ^ (uuid.uid[2] ^ uuid.uid[4])) << 8; |
| 132 | password &= (0xAA ^ (uuid[3] ^ uuid[5])) << 16; | 136 | password &= (0xAA ^ (uuid.uid[3] ^ uuid.uid[5])) << 16; |
| 133 | password &= (0x55 ^ (uuid[4] ^ uuid[6])) << 24; | 137 | password &= (0x55 ^ (uuid.uid[4] ^ uuid.uid[6])) << 24; |
| 134 | return password; | 138 | return password; |
| 135 | } | 139 | } |
| 136 | 140 | ||
| @@ -138,15 +142,13 @@ HashSeed GetSeed(const NTAG215File& data) { | |||
| 138 | HashSeed seed{ | 142 | HashSeed seed{ |
| 139 | .magic = data.write_counter, | 143 | .magic = data.write_counter, |
| 140 | .padding = {}, | 144 | .padding = {}, |
| 141 | .uuid1 = {}, | 145 | .uid_1 = data.uid, |
| 142 | .uuid2 = {}, | 146 | .nintendo_id_1 = data.nintendo_id, |
| 147 | .uid_2 = data.uid, | ||
| 148 | .nintendo_id_2 = data.nintendo_id, | ||
| 143 | .keygen_salt = data.keygen_salt, | 149 | .keygen_salt = data.keygen_salt, |
| 144 | }; | 150 | }; |
| 145 | 151 | ||
| 146 | // Copy the first 8 bytes of uuid | ||
| 147 | memcpy(seed.uuid1.data(), data.uuid.data(), sizeof(seed.uuid1)); | ||
| 148 | memcpy(seed.uuid2.data(), data.uuid.data(), sizeof(seed.uuid2)); | ||
| 149 | |||
| 150 | return seed; | 152 | return seed; |
| 151 | } | 153 | } |
| 152 | 154 | ||
| @@ -165,8 +167,10 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed | |||
| 165 | output.insert(output.end(), key.magic_bytes.begin(), | 167 | output.insert(output.end(), key.magic_bytes.begin(), |
| 166 | key.magic_bytes.begin() + key.magic_length); | 168 | key.magic_bytes.begin() + key.magic_length); |
| 167 | 169 | ||
| 168 | output.insert(output.end(), seed.uuid1.begin(), seed.uuid1.end()); | 170 | output.insert(output.end(), seed.uid_1.begin(), seed.uid_1.end()); |
| 169 | output.insert(output.end(), seed.uuid2.begin(), seed.uuid2.end()); | 171 | output.emplace_back(seed.nintendo_id_1); |
| 172 | output.insert(output.end(), seed.uid_2.begin(), seed.uid_2.end()); | ||
| 173 | output.emplace_back(seed.nintendo_id_2); | ||
| 170 | 174 | ||
| 171 | for (std::size_t i = 0; i < sizeof(seed.keygen_salt); i++) { | 175 | for (std::size_t i = 0; i < sizeof(seed.keygen_salt); i++) { |
| 172 | output.emplace_back(static_cast<u8>(seed.keygen_salt[i] ^ key.xor_pad[i])); | 176 | output.emplace_back(static_cast<u8>(seed.keygen_salt[i] ^ key.xor_pad[i])); |
| @@ -250,14 +254,15 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou | |||
| 250 | reinterpret_cast<unsigned char*>(&out_data.settings)); | 254 | reinterpret_cast<unsigned char*>(&out_data.settings)); |
| 251 | 255 | ||
| 252 | // Copy the rest of the data directly | 256 | // Copy the rest of the data directly |
| 253 | out_data.uuid2 = in_data.uuid2; | 257 | out_data.uid = in_data.uid; |
| 258 | out_data.nintendo_id = in_data.nintendo_id; | ||
| 259 | out_data.lock_bytes = in_data.lock_bytes; | ||
| 254 | out_data.static_lock = in_data.static_lock; | 260 | out_data.static_lock = in_data.static_lock; |
| 255 | out_data.compability_container = in_data.compability_container; | 261 | out_data.compability_container = in_data.compability_container; |
| 256 | 262 | ||
| 257 | out_data.constant_value = in_data.constant_value; | 263 | out_data.constant_value = in_data.constant_value; |
| 258 | out_data.write_counter = in_data.write_counter; | 264 | out_data.write_counter = in_data.write_counter; |
| 259 | 265 | ||
| 260 | out_data.uuid = in_data.uuid; | ||
| 261 | out_data.model_info = in_data.model_info; | 266 | out_data.model_info = in_data.model_info; |
| 262 | out_data.keygen_salt = in_data.keygen_salt; | 267 | out_data.keygen_salt = in_data.keygen_salt; |
| 263 | out_data.dynamic_lock = in_data.dynamic_lock; | 268 | out_data.dynamic_lock = in_data.dynamic_lock; |
| @@ -309,7 +314,7 @@ bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& t | |||
| 309 | // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC! | 314 | // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC! |
| 310 | constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; | 315 | constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; |
| 311 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), | 316 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), |
| 312 | sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uuid), | 317 | sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uid), |
| 313 | input_length, reinterpret_cast<unsigned char*>(&tag_data.hmac_tag)); | 318 | input_length, reinterpret_cast<unsigned char*>(&tag_data.hmac_tag)); |
| 314 | 319 | ||
| 315 | // Regenerate data HMAC | 320 | // Regenerate data HMAC |
| @@ -350,7 +355,7 @@ bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_t | |||
| 350 | constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; | 355 | constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; |
| 351 | constexpr std::size_t input_length2 = HMAC_TAG_START - WRITE_COUNTER_START; | 356 | constexpr std::size_t input_length2 = HMAC_TAG_START - WRITE_COUNTER_START; |
| 352 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), | 357 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), |
| 353 | sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uuid), | 358 | sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uid), |
| 354 | input_length, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag)); | 359 | input_length, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag)); |
| 355 | 360 | ||
| 356 | // Init mbedtls HMAC context | 361 | // Init mbedtls HMAC context |
| @@ -364,7 +369,7 @@ bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_t | |||
| 364 | input_length2); // Data | 369 | input_length2); // Data |
| 365 | mbedtls_md_hmac_update(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag), | 370 | mbedtls_md_hmac_update(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag), |
| 366 | sizeof(HashData)); // Tag HMAC | 371 | sizeof(HashData)); // Tag HMAC |
| 367 | mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char*>(&tag_data.uuid), | 372 | mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char*>(&tag_data.uid), |
| 368 | input_length); | 373 | input_length); |
| 369 | mbedtls_md_hmac_finish(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_data)); | 374 | mbedtls_md_hmac_finish(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_data)); |
| 370 | 375 | ||
diff --git a/src/core/hle/service/nfp/amiibo_crypto.h b/src/core/hle/service/nfp/amiibo_crypto.h index e3fa3d07e..0175ced91 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<u8, 0x20>; | |||
| 24 | struct HashSeed { | 24 | struct HashSeed { |
| 25 | u16_be magic; | 25 | u16_be magic; |
| 26 | std::array<u8, 0xE> padding; | 26 | std::array<u8, 0xE> padding; |
| 27 | std::array<u8, 0x8> uuid1; | 27 | UniqueSerialNumber uid_1; |
| 28 | std::array<u8, 0x8> uuid2; | 28 | u8 nintendo_id_1; |
| 29 | UniqueSerialNumber uid_2; | ||
| 30 | u8 nintendo_id_2; | ||
| 29 | std::array<u8, 0x20> keygen_salt; | 31 | std::array<u8, 0x20> keygen_salt; |
| 30 | }; | 32 | }; |
| 31 | static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size"); | 33 | 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 ce3bcccf4..f0eaa7df2 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp | |||
| @@ -22,6 +22,9 @@ | |||
| 22 | #include "core/hle/service/nfp/nfp_device.h" | 22 | #include "core/hle/service/nfp/nfp_device.h" |
| 23 | #include "core/hle/service/nfp/nfp_result.h" | 23 | #include "core/hle/service/nfp/nfp_result.h" |
| 24 | #include "core/hle/service/nfp/nfp_user.h" | 24 | #include "core/hle/service/nfp/nfp_user.h" |
| 25 | #include "core/hle/service/time/time_manager.h" | ||
| 26 | #include "core/hle/service/time/time_zone_content_manager.h" | ||
| 27 | #include "core/hle/service/time/time_zone_types.h" | ||
| 25 | 28 | ||
| 26 | namespace Service::NFP { | 29 | namespace Service::NFP { |
| 27 | NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, | 30 | NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, |
| @@ -39,6 +42,9 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, | |||
| 39 | }; | 42 | }; |
| 40 | is_controller_set = true; | 43 | is_controller_set = true; |
| 41 | callback_key = npad_device->SetCallback(engine_callback); | 44 | callback_key = npad_device->SetCallback(engine_callback); |
| 45 | |||
| 46 | auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; | ||
| 47 | current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point; | ||
| 42 | } | 48 | } |
| 43 | 49 | ||
| 44 | NfpDevice::~NfpDevice() { | 50 | NfpDevice::~NfpDevice() { |
| @@ -98,6 +104,7 @@ bool NfpDevice::LoadAmiibo(const std::vector<u8>& data) { | |||
| 98 | } | 104 | } |
| 99 | 105 | ||
| 100 | device_state = DeviceState::TagFound; | 106 | device_state = DeviceState::TagFound; |
| 107 | deactivate_event->GetReadableEvent().Clear(); | ||
| 101 | activate_event->GetWritableEvent().Signal(); | 108 | activate_event->GetWritableEvent().Signal(); |
| 102 | return true; | 109 | return true; |
| 103 | } | 110 | } |
| @@ -112,6 +119,7 @@ void NfpDevice::CloseAmiibo() { | |||
| 112 | device_state = DeviceState::TagRemoved; | 119 | device_state = DeviceState::TagRemoved; |
| 113 | encrypted_tag_data = {}; | 120 | encrypted_tag_data = {}; |
| 114 | tag_data = {}; | 121 | tag_data = {}; |
| 122 | activate_event->GetReadableEvent().Clear(); | ||
| 115 | deactivate_event->GetWritableEvent().Signal(); | 123 | deactivate_event->GetWritableEvent().Signal(); |
| 116 | } | 124 | } |
| 117 | 125 | ||
| @@ -140,8 +148,6 @@ void NfpDevice::Finalize() { | |||
| 140 | } | 148 | } |
| 141 | 149 | ||
| 142 | Result NfpDevice::StartDetection(s32 protocol_) { | 150 | Result NfpDevice::StartDetection(s32 protocol_) { |
| 143 | // TODO(german77): Add callback for when nfc data is available | ||
| 144 | |||
| 145 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | 151 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { |
| 146 | npad_device->SetPollingMode(Common::Input::PollingMode::NFC); | 152 | npad_device->SetPollingMode(Common::Input::PollingMode::NFC); |
| 147 | device_state = DeviceState::SearchingForTag; | 153 | device_state = DeviceState::SearchingForTag; |
| @@ -172,11 +178,9 @@ Result NfpDevice::StopDetection() { | |||
| 172 | Result NfpDevice::Flush() { | 178 | Result NfpDevice::Flush() { |
| 173 | auto& settings = tag_data.settings; | 179 | auto& settings = tag_data.settings; |
| 174 | 180 | ||
| 175 | if (settings.write_date.raw_date != settings.write_date.raw_date) { | 181 | const auto& current_date = GetAmiiboDate(current_posix_time); |
| 176 | // TODO: Read current system date | 182 | if (settings.write_date.raw_date != current_date.raw_date) { |
| 177 | settings.write_date.SetYear(2022); | 183 | settings.write_date = current_date; |
| 178 | settings.write_date.SetMonth(9); | ||
| 179 | settings.write_date.SetDay(9); | ||
| 180 | settings.crc_counter++; | 184 | settings.crc_counter++; |
| 181 | // TODO: Find how to calculate the crc check | 185 | // TODO: Find how to calculate the crc check |
| 182 | // settings.crc = CalculateCRC(settings); | 186 | // settings.crc = CalculateCRC(settings); |
| @@ -239,10 +243,10 @@ Result NfpDevice::GetTagInfo(TagInfo& tag_info) const { | |||
| 239 | } | 243 | } |
| 240 | 244 | ||
| 241 | tag_info = { | 245 | tag_info = { |
| 242 | .uuid = encrypted_tag_data.uuid, | 246 | .uuid = encrypted_tag_data.uuid.uid, |
| 243 | .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.size()), | 247 | .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), |
| 244 | .protocol = protocol, | 248 | .protocol = 1, |
| 245 | .tag_type = static_cast<u32>(encrypted_tag_data.user_memory.model_info.amiibo_type), | 249 | .tag_type = 2, |
| 246 | }; | 250 | }; |
| 247 | 251 | ||
| 248 | return ResultSuccess; | 252 | return ResultSuccess; |
| @@ -255,8 +259,6 @@ Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const { | |||
| 255 | } | 259 | } |
| 256 | 260 | ||
| 257 | const auto& settings = tag_data.settings; | 261 | const auto& settings = tag_data.settings; |
| 258 | const u32 application_area_size = | ||
| 259 | tag_data.settings.settings.appdata_initialized == 0 ? 0 : sizeof(ApplicationArea); | ||
| 260 | 262 | ||
| 261 | // TODO: Validate this data | 263 | // TODO: Validate this data |
| 262 | common_info = { | 264 | common_info = { |
| @@ -267,8 +269,8 @@ Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const { | |||
| 267 | settings.write_date.GetDay(), | 269 | settings.write_date.GetDay(), |
| 268 | }, | 270 | }, |
| 269 | .write_counter = tag_data.write_counter, | 271 | .write_counter = tag_data.write_counter, |
| 270 | .version = 1, | 272 | .version = 0, |
| 271 | .application_area_size = application_area_size, | 273 | .application_area_size = sizeof(ApplicationArea), |
| 272 | }; | 274 | }; |
| 273 | return ResultSuccess; | 275 | return ResultSuccess; |
| 274 | } | 276 | } |
| @@ -334,13 +336,8 @@ Result NfpDevice::SetNicknameAndOwner(const AmiiboName& amiibo_name) { | |||
| 334 | Service::Mii::MiiManager manager; | 336 | Service::Mii::MiiManager manager; |
| 335 | auto& settings = tag_data.settings; | 337 | auto& settings = tag_data.settings; |
| 336 | 338 | ||
| 337 | // TODO: Read current system date | 339 | settings.init_date = GetAmiiboDate(current_posix_time); |
| 338 | settings.init_date.SetYear(2022); | 340 | settings.write_date = GetAmiiboDate(current_posix_time); |
| 339 | settings.init_date.SetMonth(9); | ||
| 340 | settings.init_date.SetDay(9); | ||
| 341 | settings.write_date.SetYear(2022); | ||
| 342 | settings.write_date.SetMonth(9); | ||
| 343 | settings.write_date.SetDay(9); | ||
| 344 | settings.crc_counter++; | 341 | settings.crc_counter++; |
| 345 | // TODO: Find how to calculate the crc check | 342 | // TODO: Find how to calculate the crc check |
| 346 | // settings.crc = CalculateCRC(settings); | 343 | // settings.crc = CalculateCRC(settings); |
| @@ -570,4 +567,23 @@ void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo | |||
| 570 | } | 567 | } |
| 571 | } | 568 | } |
| 572 | 569 | ||
| 570 | AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const { | ||
| 571 | const auto& time_zone_manager = | ||
| 572 | system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); | ||
| 573 | Time::TimeZone::CalendarInfo calendar_info{}; | ||
| 574 | AmiiboDate amiibo_date{}; | ||
| 575 | |||
| 576 | amiibo_date.SetYear(2000); | ||
| 577 | amiibo_date.SetMonth(1); | ||
| 578 | amiibo_date.SetDay(1); | ||
| 579 | |||
| 580 | if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) { | ||
| 581 | amiibo_date.SetYear(calendar_info.time.year); | ||
| 582 | amiibo_date.SetMonth(calendar_info.time.month); | ||
| 583 | amiibo_date.SetDay(calendar_info.time.day); | ||
| 584 | } | ||
| 585 | |||
| 586 | return amiibo_date; | ||
| 587 | } | ||
| 588 | |||
| 573 | } // namespace Service::NFP | 589 | } // namespace Service::NFP |
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 9ceb7b8fd..c020506a6 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h | |||
| @@ -75,6 +75,7 @@ private: | |||
| 75 | 75 | ||
| 76 | AmiiboName GetAmiiboName(const AmiiboSettings& settings) const; | 76 | AmiiboName GetAmiiboName(const AmiiboSettings& settings) const; |
| 77 | void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name); | 77 | void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name); |
| 78 | AmiiboDate GetAmiiboDate(s64 posix_time) const; | ||
| 78 | 79 | ||
| 79 | bool is_controller_set{}; | 80 | bool is_controller_set{}; |
| 80 | int callback_key; | 81 | int callback_key; |
| @@ -88,6 +89,7 @@ private: | |||
| 88 | 89 | ||
| 89 | bool is_data_moddified{}; | 90 | bool is_data_moddified{}; |
| 90 | s32 protocol{}; | 91 | s32 protocol{}; |
| 92 | s64 current_posix_time{}; | ||
| 91 | DeviceState device_state{DeviceState::Unavailable}; | 93 | DeviceState device_state{DeviceState::Unavailable}; |
| 92 | 94 | ||
| 93 | NTAG215File tag_data{}; | 95 | NTAG215File tag_data{}; |
diff --git a/src/core/hle/service/nfp/nfp_result.h b/src/core/hle/service/nfp/nfp_result.h index 15bc02b15..ac259e2ff 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); | |||
| 17 | constexpr Result CorruptedData(ErrorModule::NFP, 144); | 17 | constexpr Result CorruptedData(ErrorModule::NFP, 144); |
| 18 | constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152); | 18 | constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152); |
| 19 | constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168); | 19 | constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168); |
| 20 | constexpr Result NotAnAmiibo(ErrorModule::NFP, 178); | ||
| 20 | 21 | ||
| 21 | } // namespace Service::NFP | 22 | } // namespace Service::NFP |
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 2685ae8fe..448791846 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 { | |||
| 75 | Diablo, | 75 | Diablo, |
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | using TagUuid = std::array<u8, 10>; | 78 | using UniqueSerialNumber = std::array<u8, 7>; |
| 79 | using LockBytes = std::array<u8, 2>; | ||
| 79 | using HashData = std::array<u8, 0x20>; | 80 | using HashData = std::array<u8, 0x20>; |
| 80 | using ApplicationArea = std::array<u8, 0xD8>; | 81 | using ApplicationArea = std::array<u8, 0xD8>; |
| 81 | using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; | 82 | using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; |
| 82 | 83 | ||
| 84 | struct TagUuid { | ||
| 85 | UniqueSerialNumber uid; | ||
| 86 | u8 nintendo_id; | ||
| 87 | LockBytes lock_bytes; | ||
| 88 | }; | ||
| 89 | static_assert(sizeof(TagUuid) == 10, "TagUuid is an invalid size"); | ||
| 90 | |||
| 83 | struct AmiiboDate { | 91 | struct AmiiboDate { |
| 84 | u16 raw_date{}; | 92 | u16 raw_date{}; |
| 85 | 93 | ||
| @@ -91,7 +99,7 @@ struct AmiiboDate { | |||
| 91 | return static_cast<u16>(((GetValue() & 0xFE00) >> 9) + 2000); | 99 | return static_cast<u16>(((GetValue() & 0xFE00) >> 9) + 2000); |
| 92 | } | 100 | } |
| 93 | u8 GetMonth() const { | 101 | u8 GetMonth() const { |
| 94 | return static_cast<u8>(((GetValue() & 0x01E0) >> 5) - 1); | 102 | return static_cast<u8>((GetValue() & 0x01E0) >> 5); |
| 95 | } | 103 | } |
| 96 | u8 GetDay() const { | 104 | u8 GetDay() const { |
| 97 | return static_cast<u8>(GetValue() & 0x001F); | 105 | return static_cast<u8>(GetValue() & 0x001F); |
| @@ -102,7 +110,7 @@ struct AmiiboDate { | |||
| 102 | raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted); | 110 | raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted); |
| 103 | } | 111 | } |
| 104 | void SetMonth(u8 month) { | 112 | void SetMonth(u8 month) { |
| 105 | const u16 month_converted = static_cast<u16>((month + 1) << 5); | 113 | const u16 month_converted = static_cast<u16>(month << 5); |
| 106 | raw_date = Common::swap16((GetValue() & ~0x01E0) | month_converted); | 114 | raw_date = Common::swap16((GetValue() & ~0x01E0) | month_converted); |
| 107 | } | 115 | } |
| 108 | void SetDay(u8 day) { | 116 | void SetDay(u8 day) { |
| @@ -137,7 +145,7 @@ struct AmiiboModelInfo { | |||
| 137 | u16 character_id; | 145 | u16 character_id; |
| 138 | u8 character_variant; | 146 | u8 character_variant; |
| 139 | AmiiboType amiibo_type; | 147 | AmiiboType amiibo_type; |
| 140 | u16 model_number; | 148 | u16_be model_number; |
| 141 | AmiiboSeries series; | 149 | AmiiboSeries series; |
| 142 | u8 constant_value; // Must be 02 | 150 | u8 constant_value; // Must be 02 |
| 143 | INSERT_PADDING_BYTES(0x4); // Unknown | 151 | INSERT_PADDING_BYTES(0x4); // Unknown |
| @@ -172,7 +180,7 @@ struct EncryptedAmiiboFile { | |||
| 172 | static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); | 180 | static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); |
| 173 | 181 | ||
| 174 | struct NTAG215File { | 182 | struct NTAG215File { |
| 175 | std::array<u8, 0x2> uuid2; | 183 | LockBytes lock_bytes; // Tag UUID |
| 176 | u16 static_lock; // Set defined pages as read only | 184 | u16 static_lock; // Set defined pages as read only |
| 177 | u32 compability_container; // Defines available memory | 185 | u32 compability_container; // Defines available memory |
| 178 | HashData hmac_data; // Hash | 186 | HashData hmac_data; // Hash |
| @@ -188,7 +196,8 @@ struct NTAG215File { | |||
| 188 | HashData hash; // Probably a SHA256-HMAC hash? | 196 | HashData hash; // Probably a SHA256-HMAC hash? |
| 189 | ApplicationArea application_area; // Encrypted Game data | 197 | ApplicationArea application_area; // Encrypted Game data |
| 190 | HashData hmac_tag; // Hash | 198 | HashData hmac_tag; // Hash |
| 191 | std::array<u8, 0x8> uuid; | 199 | UniqueSerialNumber uid; // Unique serial number |
| 200 | u8 nintendo_id; // Tag UUID | ||
| 192 | AmiiboModelInfo model_info; | 201 | AmiiboModelInfo model_info; |
| 193 | HashData keygen_salt; // Salt | 202 | HashData keygen_salt; // Salt |
| 194 | u32 dynamic_lock; // Dynamic lock | 203 | u32 dynamic_lock; // Dynamic lock |
| @@ -215,7 +224,8 @@ static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>, | |||
| 215 | "EncryptedNTAG215File must be trivially copyable."); | 224 | "EncryptedNTAG215File must be trivially copyable."); |
| 216 | 225 | ||
| 217 | struct TagInfo { | 226 | struct TagInfo { |
| 218 | TagUuid uuid; | 227 | UniqueSerialNumber uuid; |
| 228 | INSERT_PADDING_BYTES(0x3); | ||
| 219 | u8 uuid_length; | 229 | u8 uuid_length; |
| 220 | INSERT_PADDING_BYTES(0x15); | 230 | INSERT_PADDING_BYTES(0x15); |
| 221 | s32 protocol; | 231 | s32 protocol; |