Move mii to own namespace and add checksummed mii data

This commit is contained in:
PabloMK7 2023-07-28 00:13:58 +02:00
parent 539a1a0b6e
commit fa0c99c987
12 changed files with 359 additions and 135 deletions

View File

@ -27,7 +27,8 @@ QtMiiSelectorDialog::QtMiiSelectorDialog(QWidget* parent, QtMiiSelector* mii_sel
? tr("Mii Selector") ? tr("Mii Selector")
: QString::fromStdString(config.title)); : QString::fromStdString(config.title));
miis.push_back(HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data); miis.push_back(
HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data.GetMiiData());
combobox->addItem(tr("Standard Mii")); combobox->addItem(tr("Standard Mii"));
for (const auto& mii : Frontend::LoadMiis()) { for (const auto& mii : Frontend::LoadMiis()) {
miis.push_back(mii); miis.push_back(mii);
@ -67,6 +68,5 @@ void QtMiiSelector::OpenDialog() {
dialog.return_code, index); dialog.return_code, index);
const auto mii_data = dialog.miis.at(index); const auto mii_data = dialog.miis.at(index);
Finalize(dialog.return_code, Finalize(dialog.return_code, dialog.return_code == 0 ? std::move(mii_data) : Mii::MiiData{});
dialog.return_code == 0 ? std::move(mii_data) : HLE::Applets::MiiData{});
} }

View File

@ -24,7 +24,7 @@ private:
QVBoxLayout* layout; QVBoxLayout* layout;
QtMiiSelector* mii_selector; QtMiiSelector* mii_selector;
u32 return_code = 0; u32 return_code = 0;
std::vector<HLE::Applets::MiiData> miis; std::vector<Mii::MiiData> miis;
friend class QtMiiSelector; friend class QtMiiSelector;
}; };

View File

@ -184,6 +184,8 @@ add_library(citra_core STATIC
hle/kernel/wait_object.h hle/kernel/wait_object.h
hle/lock.cpp hle/lock.cpp
hle/lock.h hle/lock.h
hle/mii.h
hle/mii.cpp
hle/result.h hle/result.h
hle/romfs.cpp hle/romfs.cpp
hle/romfs.h hle/romfs.h

View File

@ -11,12 +11,12 @@
namespace Frontend { namespace Frontend {
void MiiSelector::Finalize(u32 return_code, HLE::Applets::MiiData mii) { void MiiSelector::Finalize(u32 return_code, Mii::MiiData mii) {
data = {return_code, mii}; data = {return_code, mii};
} }
std::vector<HLE::Applets::MiiData> LoadMiis() { std::vector<Mii::MiiData> LoadMiis() {
std::vector<HLE::Applets::MiiData> miis; std::vector<Mii::MiiData> miis;
std::string nand_directory{FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)}; std::string nand_directory{FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)};
FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true);
@ -36,7 +36,7 @@ std::vector<HLE::Applets::MiiData> LoadMiis() {
u32 saved_miis_offset = 0x8; u32 saved_miis_offset = 0x8;
// The Mii Maker has a 100 Mii limit on the 3ds // The Mii Maker has a 100 Mii limit on the 3ds
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {
HLE::Applets::MiiData mii; Mii::MiiData mii;
std::array<u8, sizeof(mii)> mii_raw; std::array<u8, sizeof(mii)> mii_raw;
file->Read(saved_miis_offset, sizeof(mii), mii_raw.data()); file->Read(saved_miis_offset, sizeof(mii), mii_raw.data());
std::memcpy(&mii, mii_raw.data(), sizeof(mii)); std::memcpy(&mii, mii_raw.data(), sizeof(mii));
@ -53,7 +53,7 @@ std::vector<HLE::Applets::MiiData> LoadMiis() {
void DefaultMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) { void DefaultMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) {
MiiSelector::Setup(config); MiiSelector::Setup(config);
Finalize(0, HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data); Finalize(0, HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data.GetMiiData());
} }
} // namespace Frontend } // namespace Frontend

View File

@ -25,7 +25,7 @@ struct MiiSelectorConfig {
struct MiiSelectorData { struct MiiSelectorData {
u32 return_code; u32 return_code;
HLE::Applets::MiiData mii; Mii::MiiData mii;
}; };
class MiiSelector { class MiiSelector {
@ -43,14 +43,14 @@ public:
* Stores the data so that the HLE applet in core can * Stores the data so that the HLE applet in core can
* send this to the calling application * send this to the calling application
*/ */
void Finalize(u32 return_code, HLE::Applets::MiiData mii); void Finalize(u32 return_code, Mii::MiiData mii);
protected: protected:
MiiSelectorConfig config; MiiSelectorConfig config;
MiiSelectorData data; MiiSelectorData data;
}; };
std::vector<HLE::Applets::MiiData> LoadMiis(); std::vector<Mii::MiiData> LoadMiis();
class DefaultMiiSelector final : public MiiSelector { class DefaultMiiSelector final : public MiiSelector {
public: public:

View File

@ -71,9 +71,6 @@ void MiiSelector::Update() {
const MiiSelectorData& data = frontend_applet->ReceiveData(); const MiiSelectorData& data = frontend_applet->ReceiveData();
result.return_code = data.return_code; result.return_code = data.return_code;
result.selected_mii_data = data.mii; result.selected_mii_data = data.mii;
// Calculate the checksum of the selected Mii, see https://www.3dbrew.org/wiki/Mii#Checksum
result.mii_data_checksum = boost::crc<16, 0x1021, 0, 0, false, false>(
&result.selected_mii_data, sizeof(HLE::Applets::MiiData) + sizeof(result.unknown1));
result.selected_guest_mii_index = 0xFFFFFFFF; result.selected_guest_mii_index = 0xFFFFFFFF;
// TODO(Subv): We're finalizing the applet immediately after it's started, // TODO(Subv): We're finalizing the applet immediately after it's started,
@ -92,29 +89,31 @@ MiiResult MiiSelector::GetStandardMiiResult() {
// This data was obtained by writing the returned buffer in AppletManager::GlanceParameter of // This data was obtained by writing the returned buffer in AppletManager::GlanceParameter of
// the LLEd Mii picker of version system version 11.8.0 to a file and then matching the values // the LLEd Mii picker of version system version 11.8.0 to a file and then matching the values
// to the members of the MiiResult struct // to the members of the MiiResult struct
MiiData mii_data; Mii::MiiData mii_data;
mii_data.mii_id = 0x03001030; mii_data.magic = 0x03;
mii_data.mii_options.raw = 0x00;
mii_data.mii_pos.raw = 0x10;
mii_data.console_identity.raw = 0x30;
mii_data.system_id = 0xD285B6B300C8850A; mii_data.system_id = 0xD285B6B300C8850A;
mii_data.specialness_and_creation_date = 0x98391EE4; mii_data.mii_id = 0x98391EE4;
mii_data.creator_mac = {0x40, 0xF4, 0x07, 0xB7, 0x37, 0x10}; mii_data.mac = {0x40, 0xF4, 0x07, 0xB7, 0x37, 0x10};
mii_data.padding = 0x0; mii_data.pad = 0x0000;
mii_data.mii_information = 0xA600; mii_data.mii_details.raw = 0xA600;
mii_data.mii_name = {'C', 'i', 't', 'r', 'a', 0x0, 0x0, 0x0, 0x0, 0x0}; mii_data.mii_name = {'C', 'i', 't', 'r', 'a', 0x0, 0x0, 0x0, 0x0, 0x0};
mii_data.width_height = 0x4040; mii_data.height = 0x40;
mii_data.appearance_bits1.raw = 0x0; mii_data.width = 0x40;
mii_data.appearance_bits2.raw = 0x0; mii_data.face_style.raw = 0x00;
mii_data.face_details.raw = 0x00;
mii_data.hair_style = 0x21; mii_data.hair_style = 0x21;
mii_data.appearance_bits3.hair_color.Assign(0x1); mii_data.hair_details.raw = 0x01;
mii_data.appearance_bits3.flip_hair.Assign(0x0); mii_data.eye_details.raw = 0x02684418;
mii_data.unknown1 = 0x02684418; mii_data.eyebrow_details.raw = 0x26344614;
mii_data.appearance_bits4.eyebrow_style.Assign(0x6); mii_data.nose_details.raw = 0x8112;
mii_data.appearance_bits4.eyebrow_color.Assign(0x1); mii_data.mouth_details.raw = 0x1768;
mii_data.appearance_bits5.eyebrow_scale.Assign(0x4); mii_data.mustache_details.raw = 0x0D00;
mii_data.appearance_bits5.eyebrow_yscale.Assign(0x3); mii_data.beard_details.raw = 0x0029;
mii_data.appearance_bits6 = 0x4614; mii_data.glasses_details.raw = 0x0052;
mii_data.unknown2 = 0x81121768; mii_data.mole_details.raw = 0x4850;
mii_data.allow_copying = 0x0D;
mii_data.unknown3 = {0x0, 0x0, 0x29, 0x0, 0x52, 0x48, 0x50};
mii_data.author_name = {'f', 'l', 'T', 'o', 'b', 'i', 0x0, 0x0, 0x0, 0x0}; mii_data.author_name = {'f', 'l', 'T', 'o', 'b', 'i', 0x0, 0x0, 0x0, 0x0};
MiiResult result; MiiResult result;
@ -122,8 +121,6 @@ MiiResult MiiSelector::GetStandardMiiResult() {
result.is_guest_mii_selected = 0x0; result.is_guest_mii_selected = 0x0;
result.selected_guest_mii_index = 0xFFFFFFFF; result.selected_guest_mii_index = 0xFFFFFFFF;
result.selected_mii_data = mii_data; result.selected_mii_data = mii_data;
result.unknown1 = 0x0;
result.mii_data_checksum = 0x056C;
result.guest_mii_name.fill(0x0); result.guest_mii_name.fill(0x0);
return result; return result;

View File

@ -9,6 +9,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/applets/applet.h" #include "core/hle/applets/applet.h"
#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/shared_memory.h"
#include "core/hle/mii.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/apt/apt.h" #include "core/hle/service/apt/apt.h"
@ -44,65 +45,11 @@ ASSERT_REG_POSITION(initially_selected_mii_index, 0x90);
ASSERT_REG_POSITION(guest_mii_whitelist, 0x94); ASSERT_REG_POSITION(guest_mii_whitelist, 0x94);
#undef ASSERT_REG_POSITION #undef ASSERT_REG_POSITION
#pragma pack(push, 1)
struct MiiData {
u32_be mii_id;
u64_be system_id;
u32_be specialness_and_creation_date;
std::array<u8, 0x6> creator_mac;
u16_be padding;
u16_be mii_information;
std::array<u16_le, 0xA> mii_name;
u16_be width_height;
union {
u8 raw;
BitField<0, 1, u8> disable_sharing;
BitField<1, 4, u8> face_shape;
BitField<5, 3, u8> skin_color;
} appearance_bits1;
union {
u8 raw;
BitField<0, 4, u8> wrinkles;
BitField<4, 4, u8> makeup;
} appearance_bits2;
u8 hair_style;
union {
u8 raw;
BitField<0, 3, u8> hair_color;
BitField<3, 1, u8> flip_hair;
} appearance_bits3;
u32_be unknown1;
union {
u8 raw;
BitField<0, 5, u8> eyebrow_style;
BitField<5, 3, u8> eyebrow_color;
} appearance_bits4;
union {
u8 raw;
BitField<0, 4, u8> eyebrow_scale;
BitField<4, 3, u8> eyebrow_yscale;
} appearance_bits5;
u16_be appearance_bits6;
u32_be unknown2;
u8 allow_copying;
std::array<u8, 0x7> unknown3;
std::array<u16_le, 0xA> author_name;
};
static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size");
#pragma pack(pop)
struct MiiResult { struct MiiResult {
u32_be return_code; u32_be return_code;
u32_be is_guest_mii_selected; u32_be is_guest_mii_selected;
u32_be selected_guest_mii_index; u32_be selected_guest_mii_index;
MiiData selected_mii_data; Mii::ChecksummedMiiData selected_mii_data;
u16_be unknown1;
u16_be mii_data_checksum;
std::array<u16_le, 0xC> guest_mii_name; std::array<u16_le, 0xC> guest_mii_name;
}; };
static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size"); static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size");

9
src/core/hle/mii.cpp Normal file
View File

@ -0,0 +1,9 @@
#include <boost/crc.hpp>
#include "core/hle/mii.h"
namespace Mii {
u16 ChecksummedMiiData::CalcChecksum() {
// Calculate the checksum of the selected Mii, see https://www.3dbrew.org/wiki/Mii#Checksum
return boost::crc<16, 0x1021, 0, 0, false, false>(this, offsetof(ChecksummedMiiData, crc16));
}
} // namespace Mii

292
src/core/hle/mii.h Normal file
View File

@ -0,0 +1,292 @@
#pragma once
#include <boost/serialization/base_object.hpp>
#include "common/bit_field.h"
#include "common/common_types.h"
namespace Mii {
#pragma pack(push, 1)
// Reference: https://github.com/devkitPro/libctru/blob/master/libctru/include/3ds/mii.h
class MiiData {
public:
u8 magic{}; ///< Always 3?
/// Mii options
union {
u8 raw;
BitField<0, 1, u8> allow_copying; ///< True if copying is allowed
BitField<1, 1, u8> is_private_name; ///< Private name?
BitField<2, 2, u8> region_lock; ///< Region lock (0=no lock, 1=JPN, 2=USA, 3=EUR)
BitField<4, 2, u8> char_set; ///< Character set (0=JPN+USA+EUR, 1=CHN, 2=KOR, 3=TWN)
} mii_options{};
/// Mii position in Mii selector or Mii maker
union {
u8 raw;
BitField<0, 4, u8> page_index; ///< Page index of Mii
BitField<4, 4, u8> slot_index; ///< Slot offset of Mii on its Page
} mii_pos{};
/// Console Identity
union {
u8 raw;
BitField<0, 4, u8> unknown0; ///< Mabye padding (always seems to be 0)?
BitField<4, 3, u8>
origin_console; ///< Console that the Mii was created on (1=WII, 2=DSI, 3=3DS)
} console_identity{};
u64_be system_id{}; ///< Identifies the system that the Mii was created on (Determines pants)
u32_be mii_id{}; ///< ID of Mii
std::array<u8, 6> mac{}; ///< Creator's system's full MAC address
u16 pad{}; ///< Padding
/// Mii details
union {
u16_be raw;
BitField<0, 1, u16> sex; ///< Sex of Mii (False=Male, True=Female)
BitField<1, 4, u16> bday_month; ///< Month of Mii's birthday
BitField<5, 5, u16> bday_day; ///< Day of Mii's birthday
BitField<10, 4, u16> shirt_color; ///< Color of Mii's shirt
BitField<14, 1, u16> favorite; ///< Whether the Mii is one of your 10 favorite Mii's
} mii_details{};
std::array<u16_le, 10> mii_name{}; ///< Name of Mii (Encoded using UTF16)
u8 height{}; ///< How tall the Mii is
u8 width{}; ///< How wide the Mii is
/// Face style
union {
u8 raw;
BitField<0, 1, u8> disable_sharing; ///< Whether or not Sharing of the Mii is allowed
BitField<1, 4, u8> shape; ///< Face shape
BitField<5, 3, u8> skin_color; ///< Color of skin
} face_style{};
/// Face details
union {
u8 raw;
BitField<0, 4, u8> wrinkles;
BitField<4, 4, u8> makeup;
} face_details{};
u8 hair_style{};
/// Hair details
union {
u8 raw;
BitField<0, 3, u8> color;
BitField<3, 1, u8> flip;
} hair_details{};
/// Eye details
union {
u32_be raw;
BitField<0, 6, u32> style;
BitField<6, 3, u32> color;
BitField<9, 4, u32> scale;
BitField<13, 3, u32> yscale;
BitField<16, 5, u32> rotation;
BitField<21, 4, u32> xspacing;
BitField<25, 5, u32> yposition;
} eye_details{};
/// Eyebrow details
union {
u32_be raw;
BitField<0, 5, u32> style;
BitField<5, 3, u32> color;
BitField<8, 4, u32> scale;
BitField<12, 3, u32> yscale;
BitField<15, 1, u32> pad;
BitField<16, 5, u32> rotation;
BitField<21, 4, u32> xspacing;
BitField<25, 5, u32> yposition;
} eyebrow_details{};
/// Nose details
union {
u16_be raw;
BitField<0, 5, u16> style;
BitField<5, 4, u16> scale;
BitField<9, 5, u16> yposition;
} nose_details{};
/// Mouth details
union {
u16_be raw;
BitField<0, 6, u16> style;
BitField<6, 3, u16> color;
BitField<9, 4, u16> scale;
BitField<13, 3, u16> yscale;
} mouth_details{};
/// Mustache details
union {
u16_be raw;
BitField<0, 5, u16> mouth_yposition;
BitField<5, 3, u16> mustach_style;
BitField<8, 2, u16> pad;
} mustache_details{};
/// Beard details
union {
u16_be raw;
BitField<0, 3, u16> style;
BitField<3, 3, u16> color;
BitField<6, 4, u16> scale;
BitField<10, 5, u16> ypos;
} beard_details{};
/// Glasses details
union {
u16_be raw;
BitField<0, 4, u16> style;
BitField<4, 3, u16> color;
BitField<7, 4, u16> scale;
BitField<11, 5, u16> ypos;
} glasses_details{};
/// Mole details
union {
u16_be raw;
BitField<0, 1, u16> enable;
BitField<1, 5, u16> scale;
BitField<6, 5, u16> xpos;
BitField<11, 5, u16> ypos;
} mole_details{};
std::array<u16_le, 10> author_name{}; ///< Name of Mii's author (Encoded using UTF16)
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& magic;
ar& mii_options.raw;
ar& mii_pos.raw;
ar& console_identity.raw;
u64 system_id_ = system_id;
ar& system_id_;
system_id = system_id_;
u32 mii_id_ = mii_id;
ar& mii_id_;
mii_id = mii_id_;
ar& mac;
ar& pad;
u16 mii_details_ = mii_details.raw;
ar& mii_details_;
mii_details.raw = mii_details_;
ar& mii_name;
ar& height;
ar& width;
ar& face_style.raw;
ar& face_details.raw;
ar& hair_style;
ar& hair_details.raw;
u32 eye_details_ = eye_details.raw;
ar& eye_details_;
eye_details.raw = eye_details_;
u32 eyebrow_details_ = eyebrow_details.raw;
ar& eyebrow_details_;
eyebrow_details.raw = eyebrow_details_;
u16 nose_details_ = nose_details.raw;
ar& nose_details_;
nose_details.raw = nose_details_;
u16 mouth_details_ = mouth_details.raw;
ar& mouth_details_;
mouth_details.raw = mouth_details_;
u16 mustache_details_ = mustache_details.raw;
ar& mustache_details_;
mustache_details.raw = mustache_details_;
u16 beard_details_ = beard_details.raw;
ar& beard_details_;
beard_details.raw = beard_details_;
u16 glasses_details_ = glasses_details.raw;
ar& glasses_details_;
glasses_details.raw = glasses_details_;
u16 mole_details_ = mole_details.raw;
ar& mole_details_;
mole_details.raw = mole_details_;
ar& author_name;
}
friend class boost::serialization::access;
};
static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size");
class ChecksummedMiiData {
public:
ChecksummedMiiData() {
FixChecksum();
}
ChecksummedMiiData(const ChecksummedMiiData& data) = default;
ChecksummedMiiData(ChecksummedMiiData&& data) = default;
ChecksummedMiiData& operator=(const ChecksummedMiiData&) = default;
ChecksummedMiiData& operator=(ChecksummedMiiData&&) = default;
ChecksummedMiiData(const MiiData& data) : mii_data(data) {
FixChecksum();
}
ChecksummedMiiData(MiiData&& data) : mii_data(data) {
FixChecksum();
}
ChecksummedMiiData& operator=(const MiiData& data) {
mii_data = data;
FixChecksum();
return *this;
}
ChecksummedMiiData& operator=(MiiData&& data) {
mii_data = std::move(data);
FixChecksum();
return *this;
}
MiiData& GetMiiData() {
return mii_data;
}
bool IsChecksumValid() {
return crc16 == CalcChecksum();
}
u16 CalcChecksum();
void FixChecksum() {
crc16 = CalcChecksum();
}
private:
MiiData mii_data{};
INSERT_PADDING_BYTES(0x2);
u16_be crc16;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& mii_data;
u16 crc16_ = crc16;
ar& crc16_;
crc16 = crc16_;
}
friend class boost::serialization::access;
};
#pragma pack(pop)
static_assert(sizeof(ChecksummedMiiData) == 0x60,
"ChecksummedMiiData structure has incorrect size");
} // namespace Mii

View File

@ -86,8 +86,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
encoded_data.amiibo_version = nfc_data.user_memory.amiibo_version; encoded_data.amiibo_version = nfc_data.user_memory.amiibo_version;
encoded_data.settings = nfc_data.user_memory.settings; encoded_data.settings = nfc_data.user_memory.settings;
encoded_data.owner_mii = nfc_data.user_memory.owner_mii; encoded_data.owner_mii = nfc_data.user_memory.owner_mii;
encoded_data.padding = nfc_data.user_memory.padding;
encoded_data.owner_mii_aes_ccm = nfc_data.user_memory.owner_mii_aes_ccm;
encoded_data.application_id = nfc_data.user_memory.application_id; encoded_data.application_id = nfc_data.user_memory.application_id;
encoded_data.application_write_counter = nfc_data.user_memory.application_write_counter; encoded_data.application_write_counter = nfc_data.user_memory.application_write_counter;
encoded_data.application_area_id = nfc_data.user_memory.application_area_id; encoded_data.application_area_id = nfc_data.user_memory.application_area_id;
@ -123,8 +121,6 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
nfc_data.user_memory.amiibo_version = encoded_data.amiibo_version; nfc_data.user_memory.amiibo_version = encoded_data.amiibo_version;
nfc_data.user_memory.settings = encoded_data.settings; nfc_data.user_memory.settings = encoded_data.settings;
nfc_data.user_memory.owner_mii = encoded_data.owner_mii; nfc_data.user_memory.owner_mii = encoded_data.owner_mii;
nfc_data.user_memory.padding = encoded_data.padding;
nfc_data.user_memory.owner_mii_aes_ccm = encoded_data.owner_mii_aes_ccm;
nfc_data.user_memory.application_id = encoded_data.application_id; nfc_data.user_memory.application_id = encoded_data.application_id;
nfc_data.user_memory.application_write_counter = encoded_data.application_write_counter; nfc_data.user_memory.application_write_counter = encoded_data.application_write_counter;
nfc_data.user_memory.application_area_id = encoded_data.application_area_id; nfc_data.user_memory.application_area_id = encoded_data.application_area_id;

View File

@ -538,7 +538,6 @@ ResultCode NfcDevice::GetRegisterInfo(RegisterInfo& register_info) const {
// TODO: Validate this data // TODO: Validate this data
register_info = { register_info = {
.mii_data = tag.file.owner_mii, .mii_data = tag.file.owner_mii,
.owner_mii_aes_ccm = tag.file.owner_mii_aes_ccm,
.amiibo_name = settings.amiibo_name, .amiibo_name = settings.amiibo_name,
.flags = static_cast<u8>(settings.settings.raw & 0xf), .flags = static_cast<u8>(settings.settings.raw & 0xf),
.font_region = settings.country_code_id, .font_region = settings.country_code_id,
@ -627,8 +626,7 @@ ResultCode NfcDevice::DeleteRegisterInfo() {
} }
CryptoPP::AutoSeededRandomPool rng; CryptoPP::AutoSeededRandomPool rng;
const std::size_t mii_data_size = const std::size_t mii_data_size = sizeof(tag.file.owner_mii);
sizeof(tag.file.owner_mii) + sizeof(tag.file.padding) + sizeof(tag.file.owner_mii_aes_ccm);
std::array<CryptoPP::byte, mii_data_size> buffer{}; std::array<CryptoPP::byte, mii_data_size> buffer{};
rng.GenerateBlock(buffer.data(), mii_data_size); rng.GenerateBlock(buffer.data(), mii_data_size);
@ -663,12 +661,9 @@ ResultCode NfcDevice::SetRegisterInfoPrivate(const RegisterInfoPrivate& register
settings.write_date = GetAmiiboDate(); settings.write_date = GetAmiiboDate();
} }
// Calculate mii CRC with the padding
tag.file.owner_mii_aes_ccm = boost::crc<16, 0x1021, 0, 0, false, false>(
&register_info.mii_data, sizeof(HLE::Applets::MiiData) + sizeof(u16));
settings.amiibo_name = register_info.amiibo_name; settings.amiibo_name = register_info.amiibo_name;
tag.file.owner_mii = register_info.mii_data; tag.file.owner_mii = register_info.mii_data;
tag.file.owner_mii.FixChecksum();
tag.file.mii_extension = {}; tag.file.mii_extension = {};
tag.file.unknown = 0; tag.file.unknown = 0;
tag.file.unknown2 = {}; tag.file.unknown2 = {};
@ -1060,9 +1055,7 @@ void NfcDevice::UpdateSettingsCrc() {
void NfcDevice::UpdateRegisterInfoCrc() { void NfcDevice::UpdateRegisterInfoCrc() {
#pragma pack(push, 1) #pragma pack(push, 1)
struct CrcData { struct CrcData {
HLE::Applets::MiiData mii; Mii::ChecksummedMiiData mii;
INSERT_PADDING_BYTES(0x2);
u16 mii_crc;
u8 application_id_byte; u8 application_id_byte;
u8 unknown; u8 unknown;
u64 mii_extension; u64 mii_extension;
@ -1073,7 +1066,6 @@ void NfcDevice::UpdateRegisterInfoCrc() {
const CrcData crc_data{ const CrcData crc_data{
.mii = tag.file.owner_mii, .mii = tag.file.owner_mii,
.mii_crc = tag.file.owner_mii_aes_ccm,
.application_id_byte = tag.file.application_id_byte, .application_id_byte = tag.file.application_id_byte,
.unknown = tag.file.unknown, .unknown = tag.file.unknown,
.mii_extension = tag.file.mii_extension, .mii_extension = tag.file.mii_extension,
@ -1101,8 +1093,6 @@ void NfcDevice::BuildAmiiboWithoutKeys() {
settings.settings.font_region.Assign(0); settings.settings.font_region.Assign(0);
settings.init_date = GetAmiiboDate(); settings.init_date = GetAmiiboDate();
tag.file.owner_mii = default_mii.selected_mii_data; tag.file.owner_mii = default_mii.selected_mii_data;
tag.file.padding = default_mii.unknown1;
tag.file.owner_mii_aes_ccm = default_mii.mii_data_checksum;
// Admin info // Admin info
settings.settings.amiibo_initialized.Assign(1); settings.settings.amiibo_initialized.Assign(1);

View File

@ -277,9 +277,7 @@ struct EncryptedAmiiboFile {
AmiiboModelInfo model_info; // Encrypted amiibo model info AmiiboModelInfo model_info; // Encrypted amiibo model info
HashData keygen_salt; // Salt HashData keygen_salt; // Salt
HashData hmac_data; // Hash HashData hmac_data; // Hash
HLE::Applets::MiiData owner_mii; // Encrypted Mii data Mii::ChecksummedMiiData owner_mii; // Encrypted Mii data
u16 padding; // Mii Padding
u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC
u64_be application_id; // Encrypted Game id u64_be application_id; // Encrypted Game id
u16_be application_write_counter; // Encrypted Counter u16_be application_write_counter; // Encrypted Counter
u32_be application_area_id; // Encrypted Game id u32_be application_area_id; // Encrypted Game id
@ -301,9 +299,7 @@ struct NTAG215File {
u16_be write_counter; // Number of times the amiibo has been written? u16_be write_counter; // Number of times the amiibo has been written?
u8 amiibo_version; // Amiibo file version u8 amiibo_version; // Amiibo file version
AmiiboSettings settings; AmiiboSettings settings;
HLE::Applets::MiiData owner_mii; // Mii data Mii::ChecksummedMiiData owner_mii; // Mii data
u16 padding; // Mii Padding
u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC
u64_be application_id; // Game id u64_be application_id; // Game id
u16_be application_write_counter; // Counter u16_be application_write_counter; // Counter
u32_be application_area_id; u32_be application_area_id;
@ -417,9 +413,7 @@ struct ModelInfo {
static_assert(sizeof(ModelInfo) == 0x36, "ModelInfo is an invalid size"); static_assert(sizeof(ModelInfo) == 0x36, "ModelInfo is an invalid size");
struct RegisterInfo { struct RegisterInfo {
HLE::Applets::MiiData mii_data; Mii::ChecksummedMiiData mii_data;
INSERT_PADDING_BYTES(0x2);
u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC
AmiiboName amiibo_name; AmiiboName amiibo_name;
INSERT_PADDING_BYTES(0x2); // Zero string terminator INSERT_PADDING_BYTES(0x2); // Zero string terminator
u8 flags; u8 flags;
@ -430,9 +424,7 @@ struct RegisterInfo {
static_assert(sizeof(RegisterInfo) == 0xA8, "RegisterInfo is an invalid size"); static_assert(sizeof(RegisterInfo) == 0xA8, "RegisterInfo is an invalid size");
struct RegisterInfoPrivate { struct RegisterInfoPrivate {
HLE::Applets::MiiData mii_data; Mii::ChecksummedMiiData mii_data;
INSERT_PADDING_BYTES(0x2);
u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC
AmiiboName amiibo_name; AmiiboName amiibo_name;
INSERT_PADDING_BYTES(0x2); // Zero string terminator INSERT_PADDING_BYTES(0x2); // Zero string terminator
u8 flags; u8 flags;
@ -441,7 +433,6 @@ struct RegisterInfoPrivate {
INSERT_PADDING_BYTES(0x28); INSERT_PADDING_BYTES(0x28);
}; };
static_assert(sizeof(RegisterInfoPrivate) == 0xA4, "RegisterInfoPrivate is an invalid size"); static_assert(sizeof(RegisterInfoPrivate) == 0xA4, "RegisterInfoPrivate is an invalid size");
static_assert(std::is_trivial_v<RegisterInfoPrivate>, "RegisterInfoPrivate must be trivial.");
static_assert(std::is_trivially_copyable_v<RegisterInfoPrivate>, static_assert(std::is_trivially_copyable_v<RegisterInfoPrivate>,
"RegisterInfoPrivate must be trivially copyable."); "RegisterInfoPrivate must be trivially copyable.");