Merge miirefactor

This commit is contained in:
PabloMK7 2023-07-28 18:56:49 +02:00
commit 5825797a95
6 changed files with 62 additions and 125 deletions

View File

@ -53,7 +53,7 @@ void AndroidMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) {
const u32 return_code = static_cast<u32>( const u32 return_code = static_cast<u32>(
env->GetLongField(data, env->GetFieldID(s_mii_selector_data_class, "return_code", "J"))); env->GetLongField(data, env->GetFieldID(s_mii_selector_data_class, "return_code", "J")));
if (return_code == 1) { if (return_code == 1) {
Finalize(return_code, HLE::Applets::MiiData{}); Finalize(return_code, Mii::MiiData{});
return; return;
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <boost/serialization/base_object.hpp> #include <boost/serialization/base_object.hpp>
#include <boost/serialization/binary_object.hpp>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
@ -10,7 +11,7 @@ namespace Mii {
// Reference: https://github.com/devkitPro/libctru/blob/master/libctru/include/3ds/mii.h // Reference: https://github.com/devkitPro/libctru/blob/master/libctru/include/3ds/mii.h
class MiiData { class MiiData {
public: public:
u8 magic{}; ///< Always 3? u8 magic; ///< Always 3?
/// Mii options /// Mii options
union { union {
@ -20,7 +21,7 @@ public:
BitField<1, 1, u8> is_private_name; ///< Private name? 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<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) BitField<4, 2, u8> char_set; ///< Character set (0=JPN+USA+EUR, 1=CHN, 2=KOR, 3=TWN)
} mii_options{}; } mii_options;
/// Mii position in Mii selector or Mii maker /// Mii position in Mii selector or Mii maker
union { union {
@ -28,7 +29,7 @@ public:
BitField<0, 4, u8> page_index; ///< Page index of Mii BitField<0, 4, u8> page_index; ///< Page index of Mii
BitField<4, 4, u8> slot_index; ///< Slot offset of Mii on its Page BitField<4, 4, u8> slot_index; ///< Slot offset of Mii on its Page
} mii_pos{}; } mii_pos;
/// Console Identity /// Console Identity
union { union {
@ -37,12 +38,12 @@ public:
BitField<0, 4, u8> unknown0; ///< Mabye padding (always seems to be 0)? BitField<0, 4, u8> unknown0; ///< Mabye padding (always seems to be 0)?
BitField<4, 3, u8> BitField<4, 3, u8>
origin_console; ///< Console that the Mii was created on (1=WII, 2=DSI, 3=3DS) origin_console; ///< Console that the Mii was created on (1=WII, 2=DSI, 3=3DS)
} console_identity{}; } console_identity;
u64_be system_id{}; ///< Identifies the system that the Mii was created on (Determines pants) u64_be system_id; ///< Identifies the system that the Mii was created on (Determines pants)
u32_be mii_id{}; ///< ID of Mii u32_be mii_id; ///< ID of Mii
std::array<u8, 6> mac{}; ///< Creator's system's full MAC address std::array<u8, 6> mac; ///< Creator's system's full MAC address
u16 pad{}; ///< Padding u16 pad; ///< Padding
/// Mii details /// Mii details
union { union {
@ -53,11 +54,11 @@ public:
BitField<5, 5, u16> bday_day; ///< Day 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<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 BitField<14, 1, u16> favorite; ///< Whether the Mii is one of your 10 favorite Mii's
} mii_details{}; } mii_details;
std::array<u16_le, 10> mii_name{}; ///< Name of Mii (Encoded using UTF16) std::array<u16_le, 10> mii_name; ///< Name of Mii (Encoded using UTF16)
u8 height{}; ///< How tall the Mii is u8 height; ///< How tall the Mii is
u8 width{}; ///< How wide the Mii is u8 width; ///< How wide the Mii is
/// Face style /// Face style
union { union {
@ -66,7 +67,7 @@ public:
BitField<0, 1, u8> disable_sharing; ///< Whether or not Sharing of the Mii is allowed BitField<0, 1, u8> disable_sharing; ///< Whether or not Sharing of the Mii is allowed
BitField<1, 4, u8> shape; ///< Face shape BitField<1, 4, u8> shape; ///< Face shape
BitField<5, 3, u8> skin_color; ///< Color of skin BitField<5, 3, u8> skin_color; ///< Color of skin
} face_style{}; } face_style;
/// Face details /// Face details
union { union {
@ -74,9 +75,9 @@ public:
BitField<0, 4, u8> wrinkles; BitField<0, 4, u8> wrinkles;
BitField<4, 4, u8> makeup; BitField<4, 4, u8> makeup;
} face_details{}; } face_details;
u8 hair_style{}; u8 hair_style;
/// Hair details /// Hair details
union { union {
@ -84,7 +85,7 @@ public:
BitField<0, 3, u8> color; BitField<0, 3, u8> color;
BitField<3, 1, u8> flip; BitField<3, 1, u8> flip;
} hair_details{}; } hair_details;
/// Eye details /// Eye details
union { union {
@ -97,7 +98,7 @@ public:
BitField<16, 5, u32> rotation; BitField<16, 5, u32> rotation;
BitField<21, 4, u32> xspacing; BitField<21, 4, u32> xspacing;
BitField<25, 5, u32> yposition; BitField<25, 5, u32> yposition;
} eye_details{}; } eye_details;
/// Eyebrow details /// Eyebrow details
union { union {
@ -111,7 +112,7 @@ public:
BitField<16, 5, u32> rotation; BitField<16, 5, u32> rotation;
BitField<21, 4, u32> xspacing; BitField<21, 4, u32> xspacing;
BitField<25, 5, u32> yposition; BitField<25, 5, u32> yposition;
} eyebrow_details{}; } eyebrow_details;
/// Nose details /// Nose details
union { union {
@ -120,7 +121,7 @@ public:
BitField<0, 5, u16> style; BitField<0, 5, u16> style;
BitField<5, 4, u16> scale; BitField<5, 4, u16> scale;
BitField<9, 5, u16> yposition; BitField<9, 5, u16> yposition;
} nose_details{}; } nose_details;
/// Mouth details /// Mouth details
union { union {
@ -130,7 +131,7 @@ public:
BitField<6, 3, u16> color; BitField<6, 3, u16> color;
BitField<9, 4, u16> scale; BitField<9, 4, u16> scale;
BitField<13, 3, u16> yscale; BitField<13, 3, u16> yscale;
} mouth_details{}; } mouth_details;
/// Mustache details /// Mustache details
union { union {
@ -139,7 +140,7 @@ public:
BitField<0, 5, u16> mouth_yposition; BitField<0, 5, u16> mouth_yposition;
BitField<5, 3, u16> mustach_style; BitField<5, 3, u16> mustach_style;
BitField<8, 2, u16> pad; BitField<8, 2, u16> pad;
} mustache_details{}; } mustache_details;
/// Beard details /// Beard details
union { union {
@ -149,7 +150,7 @@ public:
BitField<3, 3, u16> color; BitField<3, 3, u16> color;
BitField<6, 4, u16> scale; BitField<6, 4, u16> scale;
BitField<10, 5, u16> ypos; BitField<10, 5, u16> ypos;
} beard_details{}; } beard_details;
/// Glasses details /// Glasses details
union { union {
@ -159,7 +160,7 @@ public:
BitField<4, 3, u16> color; BitField<4, 3, u16> color;
BitField<7, 4, u16> scale; BitField<7, 4, u16> scale;
BitField<11, 5, u16> ypos; BitField<11, 5, u16> ypos;
} glasses_details{}; } glasses_details;
/// Mole details /// Mole details
union { union {
@ -169,64 +170,20 @@ public:
BitField<1, 5, u16> scale; BitField<1, 5, u16> scale;
BitField<6, 5, u16> xpos; BitField<6, 5, u16> xpos;
BitField<11, 5, u16> ypos; BitField<11, 5, u16> ypos;
} mole_details{}; } mole_details;
std::array<u16_le, 10> author_name{}; ///< Name of Mii's author (Encoded using UTF16) std::array<u16_le, 10> author_name; ///< Name of Mii's author (Encoded using UTF16)
private: private:
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int) { void serialize(Archive& ar, const unsigned int) {
ar& magic; ar& boost::serialization::make_binary_object(this, sizeof(MiiData));
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; friend class boost::serialization::access;
}; };
static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size"); static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size");
static_assert(std::is_trivial_v<MiiData>, "MiiData must be trivial.");
static_assert(std::is_trivially_copyable_v<MiiData>, "MiiData must be trivially copyable.");
class ChecksummedMiiData { class ChecksummedMiiData {
public: public:
@ -258,7 +215,7 @@ public:
return *this; return *this;
} }
MiiData& GetMiiData() { operator MiiData() const {
return mii_data; return mii_data;
} }
@ -277,19 +234,21 @@ private:
crc16 = CalcChecksum(); crc16 = CalcChecksum();
} }
private:
MiiData mii_data;
[[maybe_unused]] INSERT_PADDING_BYTES(0x2);
u16_be crc16;
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int) { void serialize(Archive& ar, const unsigned int) {
ar& mii_data; ar& boost::serialization::make_binary_object(this, sizeof(ChecksummedMiiData));
u16 unknown_ = unknown;
ar& unknown_;
unknown = unknown_;
u16 crc16_ = crc16;
ar& crc16_;
crc16 = crc16_;
} }
friend class boost::serialization::access; friend class boost::serialization::access;
}; };
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(ChecksummedMiiData) == 0x60, static_assert(sizeof(ChecksummedMiiData) == 0x60,
"ChecksummedMiiData structure has incorrect size"); "ChecksummedMiiData structure has incorrect size");
static_assert(std::is_trivial_v<ChecksummedMiiData>, "ChecksummedMiiData must be trivial.");
static_assert(std::is_trivially_copyable_v<ChecksummedMiiData>,
"ChecksummedMiiData must be trivially copyable.");
} // namespace Mii } // 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

@ -269,20 +269,18 @@ static_assert(sizeof(NTAG215Password) == 0x8, "NTAG215Password is an invalid siz
#pragma pack(1) #pragma pack(1)
struct EncryptedAmiiboFile { struct EncryptedAmiiboFile {
u8 constant_value; // Must be A5 u8 constant_value; // Must be A5
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; // Encrypted amiibo settings AmiiboSettings settings; // Encrypted amiibo settings
HashData hmac_tag; // Hash HashData hmac_tag; // Hash
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 u64_be application_id; // Encrypted Game id
u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC u16_be application_write_counter; // Encrypted Counter
u64_be application_id; // Encrypted Game id u32_be application_area_id; // Encrypted Game id
u16_be application_write_counter; // Encrypted Counter
u32_be application_area_id; // Encrypted Game id
u8 application_id_byte; u8 application_id_byte;
u8 unknown; u8 unknown;
u64 mii_extension; u64 mii_extension;
@ -301,11 +299,9 @@ 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 u64_be application_id; // Game id
u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC u16_be application_write_counter; // Counter
u64_be application_id; // Game id
u16_be application_write_counter; // Counter
u32_be application_area_id; u32_be application_area_id;
u8 application_id_byte; u8 application_id_byte;
u8 unknown; u8 unknown;
@ -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;