summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nfc/common/amiibo_crypto.cpp44
-rw-r--r--src/core/hle/service/nfc/common/amiibo_crypto.h9
-rw-r--r--src/core/hle/service/nfc/common/device.cpp164
-rw-r--r--src/core/hle/service/nfc/common/device.h11
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp4
-rw-r--r--src/core/hle/service/nfc/mifare_result.h2
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp13
-rw-r--r--src/core/hle/service/nfc/nfc_result.h3
-rw-r--r--src/core/hle/service/nfc/nfc_types.h37
-rw-r--r--src/core/hle/service/nfp/nfp_types.h26
10 files changed, 198 insertions, 115 deletions
diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
index b2bcb68c3..bc232c334 100644
--- a/src/core/hle/service/nfc/common/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
@@ -36,12 +36,12 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
36 36
37 // Validate UUID 37 // Validate UUID
38 constexpr u8 CT = 0x88; // As defined in `ISO / IEC 14443 - 3` 38 constexpr u8 CT = 0x88; // As defined in `ISO / IEC 14443 - 3`
39 if ((CT ^ ntag_file.uuid.uid[0] ^ ntag_file.uuid.uid[1] ^ ntag_file.uuid.uid[2]) != 39 if ((CT ^ ntag_file.uuid.part1[0] ^ ntag_file.uuid.part1[1] ^ ntag_file.uuid.part1[2]) !=
40 ntag_file.uuid.uid[3]) { 40 ntag_file.uuid.crc_check1) {
41 return false; 41 return false;
42 } 42 }
43 if ((ntag_file.uuid.uid[4] ^ ntag_file.uuid.uid[5] ^ ntag_file.uuid.uid[6] ^ 43 if ((ntag_file.uuid.part2[0] ^ ntag_file.uuid.part2[1] ^ ntag_file.uuid.part2[2] ^
44 ntag_file.uuid.nintendo_id) != ntag_file.uuid.lock_bytes[0]) { 44 ntag_file.uuid.nintendo_id) != ntag_file.uuid_crc_check2) {
45 return false; 45 return false;
46 } 46 }
47 47
@@ -74,8 +74,9 @@ bool IsAmiiboValid(const NTAG215File& ntag_file) {
74NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { 74NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
75 NTAG215File encoded_data{}; 75 NTAG215File encoded_data{};
76 76
77 encoded_data.uid = nfc_data.uuid.uid; 77 encoded_data.uid = nfc_data.uuid;
78 encoded_data.nintendo_id = nfc_data.uuid.nintendo_id; 78 encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2;
79 encoded_data.internal_number = nfc_data.internal_number;
79 encoded_data.static_lock = nfc_data.static_lock; 80 encoded_data.static_lock = nfc_data.static_lock;
80 encoded_data.compability_container = nfc_data.compability_container; 81 encoded_data.compability_container = nfc_data.compability_container;
81 encoded_data.hmac_data = nfc_data.user_memory.hmac_data; 82 encoded_data.hmac_data = nfc_data.user_memory.hmac_data;
@@ -94,7 +95,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
94 encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc; 95 encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc;
95 encoded_data.application_area = nfc_data.user_memory.application_area; 96 encoded_data.application_area = nfc_data.user_memory.application_area;
96 encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag; 97 encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag;
97 encoded_data.lock_bytes = nfc_data.uuid.lock_bytes;
98 encoded_data.model_info = nfc_data.user_memory.model_info; 98 encoded_data.model_info = nfc_data.user_memory.model_info;
99 encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt; 99 encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt;
100 encoded_data.dynamic_lock = nfc_data.dynamic_lock; 100 encoded_data.dynamic_lock = nfc_data.dynamic_lock;
@@ -108,9 +108,9 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
108EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { 108EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
109 EncryptedNTAG215File nfc_data{}; 109 EncryptedNTAG215File nfc_data{};
110 110
111 nfc_data.uuid.uid = encoded_data.uid; 111 nfc_data.uuid = encoded_data.uid;
112 nfc_data.uuid.nintendo_id = encoded_data.nintendo_id; 112 nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2;
113 nfc_data.uuid.lock_bytes = encoded_data.lock_bytes; 113 nfc_data.internal_number = encoded_data.internal_number;
114 nfc_data.static_lock = encoded_data.static_lock; 114 nfc_data.static_lock = encoded_data.static_lock;
115 nfc_data.compability_container = encoded_data.compability_container; 115 nfc_data.compability_container = encoded_data.compability_container;
116 nfc_data.user_memory.hmac_data = encoded_data.hmac_data; 116 nfc_data.user_memory.hmac_data = encoded_data.hmac_data;
@@ -139,23 +139,12 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
139 return nfc_data; 139 return nfc_data;
140} 140}
141 141
142u32 GetTagPassword(const TagUuid& uuid) {
143 // Verify that the generated password is correct
144 u32 password = 0xAA ^ (uuid.uid[1] ^ uuid.uid[3]);
145 password &= (0x55 ^ (uuid.uid[2] ^ uuid.uid[4])) << 8;
146 password &= (0xAA ^ (uuid.uid[3] ^ uuid.uid[5])) << 16;
147 password &= (0x55 ^ (uuid.uid[4] ^ uuid.uid[6])) << 24;
148 return password;
149}
150
151HashSeed GetSeed(const NTAG215File& data) { 142HashSeed GetSeed(const NTAG215File& data) {
152 HashSeed seed{ 143 HashSeed seed{
153 .magic = data.write_counter, 144 .magic = data.write_counter,
154 .padding = {}, 145 .padding = {},
155 .uid_1 = data.uid, 146 .uid_1 = data.uid,
156 .nintendo_id_1 = data.nintendo_id,
157 .uid_2 = data.uid, 147 .uid_2 = data.uid,
158 .nintendo_id_2 = data.nintendo_id,
159 .keygen_salt = data.keygen_salt, 148 .keygen_salt = data.keygen_salt,
160 }; 149 };
161 150
@@ -177,10 +166,11 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed
177 output.insert(output.end(), key.magic_bytes.begin(), 166 output.insert(output.end(), key.magic_bytes.begin(),
178 key.magic_bytes.begin() + key.magic_length); 167 key.magic_bytes.begin() + key.magic_length);
179 168
180 output.insert(output.end(), seed.uid_1.begin(), seed.uid_1.end()); 169 std::array<u8, sizeof(NFP::TagUuid)> seed_uuid{};
181 output.emplace_back(seed.nintendo_id_1); 170 memcpy(seed_uuid.data(), &seed.uid_1, sizeof(NFP::TagUuid));
182 output.insert(output.end(), seed.uid_2.begin(), seed.uid_2.end()); 171 output.insert(output.end(), seed_uuid.begin(), seed_uuid.end());
183 output.emplace_back(seed.nintendo_id_2); 172 memcpy(seed_uuid.data(), &seed.uid_2, sizeof(NFP::TagUuid));
173 output.insert(output.end(), seed_uuid.begin(), seed_uuid.end());
184 174
185 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++) {
186 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]));
@@ -264,8 +254,8 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
264 254
265 // Copy the rest of the data directly 255 // Copy the rest of the data directly
266 out_data.uid = in_data.uid; 256 out_data.uid = in_data.uid;
267 out_data.nintendo_id = in_data.nintendo_id; 257 out_data.uid_crc_check2 = in_data.uid_crc_check2;
268 out_data.lock_bytes = in_data.lock_bytes; 258 out_data.internal_number = in_data.internal_number;
269 out_data.static_lock = in_data.static_lock; 259 out_data.static_lock = in_data.static_lock;
270 out_data.compability_container = in_data.compability_container; 260 out_data.compability_container = in_data.compability_container;
271 261
diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.h b/src/core/hle/service/nfc/common/amiibo_crypto.h
index bf3044ed9..6a3e0841e 100644
--- a/src/core/hle/service/nfc/common/amiibo_crypto.h
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.h
@@ -24,10 +24,8 @@ using DrgbOutput = std::array<u8, 0x20>;
24struct HashSeed { 24struct HashSeed {
25 u16_be magic; 25 u16_be magic;
26 std::array<u8, 0xE> padding; 26 std::array<u8, 0xE> padding;
27 NFC::UniqueSerialNumber uid_1; 27 TagUuid uid_1;
28 u8 nintendo_id_1; 28 TagUuid uid_2;
29 NFC::UniqueSerialNumber uid_2;
30 u8 nintendo_id_2;
31 std::array<u8, 0x20> keygen_salt; 29 std::array<u8, 0x20> keygen_salt;
32}; 30};
33static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size"); 31static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size");
@@ -69,9 +67,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data);
69/// Converts from encoded file format to encrypted file format 67/// Converts from encoded file format to encrypted file format
70EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data); 68EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data);
71 69
72/// Returns password needed to allow write access to protected memory
73u32 GetTagPassword(const TagUuid& uuid);
74
75// Generates Seed needed for key derivation 70// Generates Seed needed for key derivation
76HashSeed GetSeed(const NTAG215File& data); 71HashSeed GetSeed(const NTAG215File& data);
77 72
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index b14f682b5..f4b180b06 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -242,34 +242,39 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
242 return ResultWrongDeviceState; 242 return ResultWrongDeviceState;
243 } 243 }
244 244
245 UniqueSerialNumber uuid = encrypted_tag_data.uuid.uid; 245 UniqueSerialNumber uuid{};
246 246 u8 uuid_length{};
247 // Generate random UUID to bypass amiibo load limits 247 NfcProtocol protocol{NfcProtocol::TypeA};
248 if (Settings::values.random_amiibo_id) { 248 TagType tag_type{TagType::Type2};
249 Common::TinyMT rng{};
250 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
251 rng.GenerateRandomBytes(uuid.data(), sizeof(UniqueSerialNumber));
252 uuid[3] = 0x88 ^ uuid[0] ^ uuid[1] ^ uuid[2];
253 }
254 249
255 if (is_mifare) { 250 if (is_mifare) {
256 tag_info = { 251 tag_type = TagType::Mifare;
257 .uuid = uuid, 252 uuid_length = sizeof(NFP::NtagTagUuid);
258 .uuid_extension = {}, 253 memcpy(uuid.data(), mifare_data.data(), uuid_length);
259 .uuid_length = static_cast<u8>(uuid.size()), 254 } else {
260 .protocol = NfcProtocol::TypeA, 255 tag_type = TagType::Type2;
261 .tag_type = TagType::Type4, 256 uuid_length = sizeof(NFP::NtagTagUuid);
257 NFP::NtagTagUuid nUuid{
258 .part1 = encrypted_tag_data.uuid.part1,
259 .part2 = encrypted_tag_data.uuid.part2,
260 .nintendo_id = encrypted_tag_data.uuid.nintendo_id,
262 }; 261 };
263 return ResultSuccess; 262 memcpy(uuid.data(), &nUuid, uuid_length);
263
264 // Generate random UUID to bypass amiibo load limits
265 if (Settings::values.random_amiibo_id) {
266 Common::TinyMT rng{};
267 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
268 rng.GenerateRandomBytes(uuid.data(), uuid_length);
269 }
264 } 270 }
265 271
266 // Protocol and tag type may change here 272 // Protocol and tag type may change here
267 tag_info = { 273 tag_info = {
268 .uuid = uuid, 274 .uuid = uuid,
269 .uuid_extension = {}, 275 .uuid_length = uuid_length,
270 .uuid_length = static_cast<u8>(uuid.size()), 276 .protocol = protocol,
271 .protocol = NfcProtocol::TypeA, 277 .tag_type = tag_type,
272 .tag_type = TagType::Type2,
273 }; 278 };
274 279
275 return ResultSuccess; 280 return ResultSuccess;
@@ -277,8 +282,38 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
277 282
278Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameters, 283Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameters,
279 std::span<MifareReadBlockData> read_block_data) const { 284 std::span<MifareReadBlockData> read_block_data) const {
285 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
286 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
287 if (device_state == DeviceState::TagRemoved) {
288 return ResultTagRemoved;
289 }
290 return ResultWrongDeviceState;
291 }
292
280 Result result = ResultSuccess; 293 Result result = ResultSuccess;
281 294
295 TagInfo tag_info{};
296 result = GetTagInfo(tag_info, true);
297
298 if (result.IsError()) {
299 return result;
300 }
301
302 if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
303 return ResultInvalidTagType;
304 }
305
306 if (parameters.size() == 0) {
307 return ResultInvalidArgument;
308 }
309
310 const auto unknown = parameters[0].sector_key.unknown;
311 for (std::size_t i = 0; i < parameters.size(); i++) {
312 if (unknown != parameters[i].sector_key.unknown) {
313 return ResultInvalidArgument;
314 }
315 }
316
282 for (std::size_t i = 0; i < parameters.size(); i++) { 317 for (std::size_t i = 0; i < parameters.size(); i++) {
283 result = ReadMifare(parameters[i], read_block_data[i]); 318 result = ReadMifare(parameters[i], read_block_data[i]);
284 if (result.IsError()) { 319 if (result.IsError()) {
@@ -293,17 +328,8 @@ Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
293 MifareReadBlockData& read_block_data) const { 328 MifareReadBlockData& read_block_data) const {
294 const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock); 329 const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
295 read_block_data.sector_number = parameter.sector_number; 330 read_block_data.sector_number = parameter.sector_number;
296
297 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
298 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
299 if (device_state == DeviceState::TagRemoved) {
300 return ResultTagRemoved;
301 }
302 return ResultWrongDeviceState;
303 }
304
305 if (mifare_data.size() < sector_index + sizeof(DataBlock)) { 331 if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
306 return Mifare::ResultReadError; 332 return ResultMifareError288;
307 } 333 }
308 334
309 // TODO: Use parameter.sector_key to read encrypted data 335 // TODO: Use parameter.sector_key to read encrypted data
@@ -315,6 +341,28 @@ Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
315Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> parameters) { 341Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> parameters) {
316 Result result = ResultSuccess; 342 Result result = ResultSuccess;
317 343
344 TagInfo tag_info{};
345 result = GetTagInfo(tag_info, true);
346
347 if (result.IsError()) {
348 return result;
349 }
350
351 if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
352 return ResultInvalidTagType;
353 }
354
355 if (parameters.size() == 0) {
356 return ResultInvalidArgument;
357 }
358
359 const auto unknown = parameters[0].sector_key.unknown;
360 for (std::size_t i = 0; i < parameters.size(); i++) {
361 if (unknown != parameters[i].sector_key.unknown) {
362 return ResultInvalidArgument;
363 }
364 }
365
318 for (std::size_t i = 0; i < parameters.size(); i++) { 366 for (std::size_t i = 0; i < parameters.size(); i++) {
319 result = WriteMifare(parameters[i]); 367 result = WriteMifare(parameters[i]);
320 if (result.IsError()) { 368 if (result.IsError()) {
@@ -324,7 +372,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
324 372
325 if (!npad_device->WriteNfc(mifare_data)) { 373 if (!npad_device->WriteNfc(mifare_data)) {
326 LOG_ERROR(Service_NFP, "Error writing to file"); 374 LOG_ERROR(Service_NFP, "Error writing to file");
327 return Mifare::ResultReadError; 375 return ResultMifareError288;
328 } 376 }
329 377
330 return result; 378 return result;
@@ -342,7 +390,7 @@ Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) {
342 } 390 }
343 391
344 if (mifare_data.size() < sector_index + sizeof(DataBlock)) { 392 if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
345 return Mifare::ResultReadError; 393 return ResultMifareError288;
346 } 394 }
347 395
348 // TODO: Use parameter.sector_key to encrypt the data 396 // TODO: Use parameter.sector_key to encrypt the data
@@ -366,7 +414,7 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
366 414
367 if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { 415 if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
368 LOG_ERROR(Service_NFP, "Not an amiibo"); 416 LOG_ERROR(Service_NFP, "Not an amiibo");
369 return ResultNotAnAmiibo; 417 return ResultInvalidTagType;
370 } 418 }
371 419
372 // The loaded amiibo is not encrypted 420 // The loaded amiibo is not encrypted
@@ -381,14 +429,14 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
381 } 429 }
382 430
383 if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { 431 if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
384 bool has_backup = HasBackup(encrypted_tag_data.uuid.uid).IsSuccess(); 432 bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess();
385 LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup); 433 LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup);
386 return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData; 434 return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
387 } 435 }
388 436
389 std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File)); 437 std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
390 memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); 438 memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
391 WriteBackupData(encrypted_tag_data.uuid.uid, data); 439 WriteBackupData(encrypted_tag_data.uuid, data);
392 440
393 device_state = DeviceState::TagMounted; 441 device_state = DeviceState::TagMounted;
394 mount_target = mount_target_; 442 mount_target = mount_target_;
@@ -492,7 +540,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
492 } 540 }
493 541
494 memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); 542 memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
495 WriteBackupData(encrypted_tag_data.uuid.uid, data); 543 WriteBackupData(encrypted_tag_data.uuid, data);
496 } 544 }
497 545
498 if (!npad_device->WriteNfc(data)) { 546 if (!npad_device->WriteNfc(data)) {
@@ -520,7 +568,7 @@ Result NfcDevice::Restore() {
520 return result; 568 return result;
521 } 569 }
522 570
523 result = ReadBackupData(tag_info.uuid, data); 571 result = ReadBackupData(tag_info.uuid, tag_info.uuid_length, data);
524 572
525 if (result.IsError()) { 573 if (result.IsError()) {
526 return result; 574 return result;
@@ -548,7 +596,7 @@ Result NfcDevice::Restore() {
548 } 596 }
549 597
550 if (!NFP::AmiiboCrypto::IsAmiiboValid(temporary_encrypted_tag_data)) { 598 if (!NFP::AmiiboCrypto::IsAmiiboValid(temporary_encrypted_tag_data)) {
551 return ResultNotAnAmiibo; 599 return ResultInvalidTagType;
552 } 600 }
553 601
554 if (!is_plain_amiibo) { 602 if (!is_plain_amiibo) {
@@ -1194,10 +1242,12 @@ Result NfcDevice::BreakTag(NFP::BreakType break_type) {
1194 return FlushWithBreak(break_type); 1242 return FlushWithBreak(break_type);
1195} 1243}
1196 1244
1197Result NfcDevice::HasBackup(const NFC::UniqueSerialNumber& uid) const { 1245Result NfcDevice::HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const {
1246 ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
1198 constexpr auto backup_dir = "backup"; 1247 constexpr auto backup_dir = "backup";
1199 const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir); 1248 const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
1200 const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, "")); 1249 const auto file_name =
1250 fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
1201 1251
1202 if (!Common::FS::Exists(yuzu_amiibo_dir / backup_dir / file_name)) { 1252 if (!Common::FS::Exists(yuzu_amiibo_dir / backup_dir / file_name)) {
1203 return ResultUnableToAccessBackupFile; 1253 return ResultUnableToAccessBackupFile;
@@ -1206,10 +1256,19 @@ Result NfcDevice::HasBackup(const NFC::UniqueSerialNumber& uid) const {
1206 return ResultSuccess; 1256 return ResultSuccess;
1207} 1257}
1208 1258
1209Result NfcDevice::ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const { 1259Result NfcDevice::HasBackup(const NFP::TagUuid& tag_uid) const {
1260 UniqueSerialNumber uuid{};
1261 memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
1262 return HasBackup(uuid, sizeof(NFP::TagUuid));
1263}
1264
1265Result NfcDevice::ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
1266 std::span<u8> data) const {
1267 ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
1210 constexpr auto backup_dir = "backup"; 1268 constexpr auto backup_dir = "backup";
1211 const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir); 1269 const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
1212 const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, "")); 1270 const auto file_name =
1271 fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
1213 1272
1214 const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name, 1273 const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
1215 Common::FS::FileAccessMode::Read, 1274 Common::FS::FileAccessMode::Read,
@@ -1228,12 +1287,21 @@ Result NfcDevice::ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u
1228 return ResultSuccess; 1287 return ResultSuccess;
1229} 1288}
1230 1289
1231Result NfcDevice::WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data) { 1290Result NfcDevice::ReadBackupData(const NFP::TagUuid& tag_uid, std::span<u8> data) const {
1291 UniqueSerialNumber uuid{};
1292 memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
1293 return ReadBackupData(uuid, sizeof(NFP::TagUuid), data);
1294}
1295
1296Result NfcDevice::WriteBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
1297 std::span<const u8> data) {
1298 ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
1232 constexpr auto backup_dir = "backup"; 1299 constexpr auto backup_dir = "backup";
1233 const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir); 1300 const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
1234 const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, "")); 1301 const auto file_name =
1302 fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
1235 1303
1236 if (HasBackup(uid).IsError()) { 1304 if (HasBackup(uid, uuid_size).IsError()) {
1237 if (!Common::FS::CreateDir(yuzu_amiibo_dir / backup_dir)) { 1305 if (!Common::FS::CreateDir(yuzu_amiibo_dir / backup_dir)) {
1238 return ResultBackupPathAlreadyExist; 1306 return ResultBackupPathAlreadyExist;
1239 } 1307 }
@@ -1260,6 +1328,12 @@ Result NfcDevice::WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<
1260 return ResultSuccess; 1328 return ResultSuccess;
1261} 1329}
1262 1330
1331Result NfcDevice::WriteBackupData(const NFP::TagUuid& tag_uid, std::span<const u8> data) {
1332 UniqueSerialNumber uuid{};
1333 memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
1334 return WriteBackupData(uuid, sizeof(NFP::TagUuid), data);
1335}
1336
1263Result NfcDevice::WriteNtf(std::span<const u8> data) { 1337Result NfcDevice::WriteNtf(std::span<const u8> data) {
1264 if (device_state != DeviceState::TagMounted) { 1338 if (device_state != DeviceState::TagMounted) {
1265 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1339 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index 6f049b687..7560210d6 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -86,9 +86,14 @@ public:
86 Result GetAll(NFP::NfpData& data) const; 86 Result GetAll(NFP::NfpData& data) const;
87 Result SetAll(const NFP::NfpData& data); 87 Result SetAll(const NFP::NfpData& data);
88 Result BreakTag(NFP::BreakType break_type); 88 Result BreakTag(NFP::BreakType break_type);
89 Result HasBackup(const NFC::UniqueSerialNumber& uid) const; 89 Result HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const;
90 Result ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const; 90 Result HasBackup(const NFP::TagUuid& tag_uid) const;
91 Result WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data); 91 Result ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
92 std::span<u8> data) const;
93 Result ReadBackupData(const NFP::TagUuid& tag_uid, std::span<u8> data) const;
94 Result WriteBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
95 std::span<const u8> data);
96 Result WriteBackupData(const NFP::TagUuid& tag_uid, std::span<const u8> data);
92 Result WriteNtf(std::span<const u8> data); 97 Result WriteNtf(std::span<const u8> data);
93 98
94 u64 GetHandle() const; 99 u64 GetHandle() const;
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index cffd602df..b0456508e 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -550,7 +550,7 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons
550 } 550 }
551 551
552 if (result.IsSuccess()) { 552 if (result.IsSuccess()) {
553 result = device->ReadBackupData(tag_info.uuid, data); 553 result = device->ReadBackupData(tag_info.uuid, tag_info.uuid_length, data);
554 result = VerifyDeviceResult(device, result); 554 result = VerifyDeviceResult(device, result);
555 } 555 }
556 556
@@ -569,7 +569,7 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat
569 } 569 }
570 570
571 if (result.IsSuccess()) { 571 if (result.IsSuccess()) {
572 result = device->WriteBackupData(tag_info.uuid, data); 572 result = device->WriteBackupData(tag_info.uuid, tag_info.uuid_length, data);
573 result = VerifyDeviceResult(device, result); 573 result = VerifyDeviceResult(device, result);
574 } 574 }
575 575
diff --git a/src/core/hle/service/nfc/mifare_result.h b/src/core/hle/service/nfc/mifare_result.h
index 4b60048a5..16a9171e6 100644
--- a/src/core/hle/service/nfc/mifare_result.h
+++ b/src/core/hle/service/nfc/mifare_result.h
@@ -12,6 +12,6 @@ constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65);
12constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73); 12constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73);
13constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80); 13constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80);
14constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97); 14constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97);
15constexpr Result ResultReadError(ErrorModule::NFCMifare, 288); 15constexpr Result ResultNotAMifare(ErrorModule::NFCMifare, 288);
16 16
17} // namespace Service::NFC::Mifare 17} // namespace Service::NFC::Mifare
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index 198d0f2b9..130fb7f78 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -142,9 +142,13 @@ void NfcInterface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
142void NfcInterface::StartDetection(HLERequestContext& ctx) { 142void NfcInterface::StartDetection(HLERequestContext& ctx) {
143 IPC::RequestParser rp{ctx}; 143 IPC::RequestParser rp{ctx};
144 const auto device_handle{rp.Pop<u64>()}; 144 const auto device_handle{rp.Pop<u64>()};
145 const auto tag_protocol{rp.PopEnum<NfcProtocol>()}; 145 auto tag_protocol{NfcProtocol::All};
146 LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol); 146
147 if (backend_type == BackendType::Nfc) {
148 tag_protocol = rp.PopEnum<NfcProtocol>();
149 }
147 150
151 LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
148 auto result = GetManager()->StartDetection(device_handle, tag_protocol); 152 auto result = GetManager()->StartDetection(device_handle, tag_protocol);
149 result = TranslateResultToServiceError(result); 153 result = TranslateResultToServiceError(result);
150 154
@@ -355,7 +359,7 @@ Result NfcInterface::TranslateResultToNfp(Result result) const {
355 if (result == ResultApplicationAreaExist) { 359 if (result == ResultApplicationAreaExist) {
356 return NFP::ResultApplicationAreaExist; 360 return NFP::ResultApplicationAreaExist;
357 } 361 }
358 if (result == ResultNotAnAmiibo) { 362 if (result == ResultInvalidTagType) {
359 return NFP::ResultNotAnAmiibo; 363 return NFP::ResultNotAnAmiibo;
360 } 364 }
361 if (result == ResultUnableToAccessBackupFile) { 365 if (result == ResultUnableToAccessBackupFile) {
@@ -381,6 +385,9 @@ Result NfcInterface::TranslateResultToMifare(Result result) const {
381 if (result == ResultTagRemoved) { 385 if (result == ResultTagRemoved) {
382 return Mifare::ResultTagRemoved; 386 return Mifare::ResultTagRemoved;
383 } 387 }
388 if (result == ResultInvalidTagType) {
389 return Mifare::ResultNotAMifare;
390 }
384 LOG_WARNING(Service_NFC, "Result conversion not handled"); 391 LOG_WARNING(Service_NFC, "Result conversion not handled");
385 return result; 392 return result;
386} 393}
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h
index 59a808740..715c0e80c 100644
--- a/src/core/hle/service/nfc/nfc_result.h
+++ b/src/core/hle/service/nfc/nfc_result.h
@@ -24,7 +24,8 @@ constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136);
24constexpr Result ResultCorruptedData(ErrorModule::NFC, 144); 24constexpr Result ResultCorruptedData(ErrorModule::NFC, 144);
25constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFC, 152); 25constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFC, 152);
26constexpr Result ResultApplicationAreaExist(ErrorModule::NFC, 168); 26constexpr Result ResultApplicationAreaExist(ErrorModule::NFC, 168);
27constexpr Result ResultNotAnAmiibo(ErrorModule::NFC, 178); 27constexpr Result ResultInvalidTagType(ErrorModule::NFC, 178);
28constexpr Result ResultBackupPathAlreadyExist(ErrorModule::NFC, 216); 28constexpr Result ResultBackupPathAlreadyExist(ErrorModule::NFC, 216);
29constexpr Result ResultMifareError288(ErrorModule::NFC, 288);
29 30
30} // namespace Service::NFC 31} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_types.h b/src/core/hle/service/nfc/nfc_types.h
index c7ebd1fdb..68e724442 100644
--- a/src/core/hle/service/nfc/nfc_types.h
+++ b/src/core/hle/service/nfc/nfc_types.h
@@ -35,32 +35,35 @@ enum class State : u32 {
35 35
36// This is nn::nfc::TagType 36// This is nn::nfc::TagType
37enum class TagType : u32 { 37enum class TagType : u32 {
38 None, 38 None = 0,
39 Type1, // ISO14443A RW 96-2k bytes 106kbit/s 39 Type1 = 1U << 0, // ISO14443A RW. Topaz
40 Type2, // ISO14443A RW/RO 540 bytes 106kbit/s 40 Type2 = 1U << 1, // ISO14443A RW. Ultralight, NTAGX, ST25TN
41 Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s 41 Type3 = 1U << 2, // ISO14443A RW/RO. Sony FeliCa
42 Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s 42 Type4A = 1U << 3, // ISO14443A RW/RO. DESFire
43 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s 43 Type4B = 1U << 4, // ISO14443B RW/RO. DESFire
44 Type5 = 1U << 5, // ISO15693 RW/RO. SLI, SLIX, ST25TV
45 Mifare = 1U << 6, // Mifare classic. Skylanders
46 All = 0xFFFFFFFF,
44}; 47};
45 48
46enum class PackedTagType : u8 { 49enum class PackedTagType : u8 {
47 None, 50 None = 0,
48 Type1, // ISO14443A RW 96-2k bytes 106kbit/s 51 Type1 = 1U << 0, // ISO14443A RW. Topaz
49 Type2, // ISO14443A RW/RO 540 bytes 106kbit/s 52 Type2 = 1U << 1, // ISO14443A RW. Ultralight, NTAGX, ST25TN
50 Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s 53 Type3 = 1U << 2, // ISO14443A RW/RO. Sony FeliCa
51 Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s 54 Type4A = 1U << 3, // ISO14443A RW/RO. DESFire
52 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s 55 Type4B = 1U << 4, // ISO14443B RW/RO. DESFire
56 Type5 = 1U << 5, // ISO15693 RW/RO. SLI, SLIX, ST25TV
57 Mifare = 1U << 6, // Mifare classic. Skylanders
58 All = 0xFF,
53}; 59};
54 60
55// This is nn::nfc::NfcProtocol 61// This is nn::nfc::NfcProtocol
56// Verify this enum. It might be completely wrong default protocol is 0x48
57enum class NfcProtocol : u32 { 62enum class NfcProtocol : u32 {
58 None, 63 None,
59 TypeA = 1U << 0, // ISO14443A 64 TypeA = 1U << 0, // ISO14443A
60 TypeB = 1U << 1, // ISO14443B 65 TypeB = 1U << 1, // ISO14443B
61 TypeF = 1U << 2, // Sony FeliCa 66 TypeF = 1U << 2, // Sony FeliCa
62 Unknown1 = 1U << 3,
63 Unknown2 = 1U << 5,
64 All = 0xFFFFFFFFU, 67 All = 0xFFFFFFFFU,
65}; 68};
66 69
@@ -69,8 +72,7 @@ enum class TestWaveType : u32 {
69 Unknown, 72 Unknown,
70}; 73};
71 74
72using UniqueSerialNumber = std::array<u8, 7>; 75using UniqueSerialNumber = std::array<u8, 10>;
73using UniqueSerialNumberExtension = std::array<u8, 3>;
74 76
75// This is nn::nfc::DeviceHandle 77// This is nn::nfc::DeviceHandle
76using DeviceHandle = u64; 78using DeviceHandle = u64;
@@ -78,7 +80,6 @@ using DeviceHandle = u64;
78// This is nn::nfc::TagInfo 80// This is nn::nfc::TagInfo
79struct TagInfo { 81struct TagInfo {
80 UniqueSerialNumber uuid; 82 UniqueSerialNumber uuid;
81 UniqueSerialNumberExtension uuid_extension;
82 u8 uuid_length; 83 u8 uuid_length;
83 INSERT_PADDING_BYTES(0x15); 84 INSERT_PADDING_BYTES(0x15);
84 NfcProtocol protocol; 85 NfcProtocol protocol;
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h
index 7d36d5ee6..aed12a7f8 100644
--- a/src/core/hle/service/nfp/nfp_types.h
+++ b/src/core/hle/service/nfp/nfp_types.h
@@ -85,7 +85,7 @@ enum class CabinetMode : u8 {
85 StartFormatter, 85 StartFormatter,
86}; 86};
87 87
88using LockBytes = std::array<u8, 2>; 88using UuidPart = std::array<u8, 3>;
89using HashData = std::array<u8, 0x20>; 89using HashData = std::array<u8, 0x20>;
90using ApplicationArea = std::array<u8, 0xD8>; 90using ApplicationArea = std::array<u8, 0xD8>;
91using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; 91using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
@@ -93,12 +93,20 @@ using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
93// This is nn::nfp::TagInfo 93// This is nn::nfp::TagInfo
94using TagInfo = NFC::TagInfo; 94using TagInfo = NFC::TagInfo;
95 95
96struct NtagTagUuid {
97 UuidPart part1;
98 UuidPart part2;
99 u8 nintendo_id;
100};
101static_assert(sizeof(NtagTagUuid) == 7, "NtagTagUuid is an invalid size");
102
96struct TagUuid { 103struct TagUuid {
97 NFC::UniqueSerialNumber uid; 104 UuidPart part1;
105 u8 crc_check1;
106 UuidPart part2;
98 u8 nintendo_id; 107 u8 nintendo_id;
99 LockBytes lock_bytes;
100}; 108};
101static_assert(sizeof(TagUuid) == 10, "TagUuid is an invalid size"); 109static_assert(sizeof(TagUuid) == 8, "TagUuid is an invalid size");
102 110
103struct WriteDate { 111struct WriteDate {
104 u16 year; 112 u16 year;
@@ -231,7 +239,8 @@ struct EncryptedAmiiboFile {
231static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); 239static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size");
232 240
233struct NTAG215File { 241struct NTAG215File {
234 LockBytes lock_bytes; // Tag UUID 242 u8 uid_crc_check2;
243 u8 internal_number;
235 u16 static_lock; // Set defined pages as read only 244 u16 static_lock; // Set defined pages as read only
236 u32 compability_container; // Defines available memory 245 u32 compability_container; // Defines available memory
237 HashData hmac_data; // Hash 246 HashData hmac_data; // Hash
@@ -250,8 +259,7 @@ struct NTAG215File {
250 u32_be register_info_crc; 259 u32_be register_info_crc;
251 ApplicationArea application_area; // Encrypted Game data 260 ApplicationArea application_area; // Encrypted Game data
252 HashData hmac_tag; // Hash 261 HashData hmac_tag; // Hash
253 NFC::UniqueSerialNumber uid; // Unique serial number 262 TagUuid uid;
254 u8 nintendo_id; // Tag UUID
255 AmiiboModelInfo model_info; 263 AmiiboModelInfo model_info;
256 HashData keygen_salt; // Salt 264 HashData keygen_salt; // Salt
257 u32 dynamic_lock; // Dynamic lock 265 u32 dynamic_lock; // Dynamic lock
@@ -264,7 +272,9 @@ static_assert(std::is_trivially_copyable_v<NTAG215File>, "NTAG215File must be tr
264#pragma pack() 272#pragma pack()
265 273
266struct EncryptedNTAG215File { 274struct EncryptedNTAG215File {
267 TagUuid uuid; // Unique serial number 275 TagUuid uuid;
276 u8 uuid_crc_check2;
277 u8 internal_number;
268 u16 static_lock; // Set defined pages as read only 278 u16 static_lock; // Set defined pages as read only
269 u32 compability_container; // Defines available memory 279 u32 compability_container; // Defines available memory
270 EncryptedAmiiboFile user_memory; // Writable data 280 EncryptedAmiiboFile user_memory; // Writable data