From 35e208b447039ff95bb7b839b4cf5296f44c8137 Mon Sep 17 00:00:00 2001
From: PabloMK7 <hackyglitch2@gmail.com>
Date: Tue, 1 Aug 2023 05:38:47 +0200
Subject: [PATCH] Move MiiData to its own namespace and add ChecksummedMiiData
 (#6824)

* Move mii to own namespace and add checksummed mii data

* Fix compile issues

* Make mii classes trivial and add cast operator

* Fix Android side

* Add new line at the end of files.

* Make miidata a struct and crc16 a u32_be as per switch code.

* Apply suggestions

* Change back crc to u16 and set padding to 0.
---
 .../app/src/main/jni/applets/mii_selector.cpp |   2 +-
 src/citra_qt/applets/mii_selector.cpp         |   3 +-
 src/citra_qt/applets/mii_selector.h           |   2 +-
 src/core/CMakeLists.txt                       |   2 +
 src/core/frontend/applets/mii_selector.cpp    |   8 +-
 src/core/frontend/applets/mii_selector.h      |   6 +-
 src/core/hle/applets/mii_selector.cpp         |  47 ++--
 src/core/hle/applets/mii_selector.h           |  57 +----
 src/core/hle/mii.cpp                          |  13 +
 src/core/hle/mii.h                            | 239 ++++++++++++++++++
 src/core/hle/service/nfc/amiibo_crypto.cpp    |   4 -
 src/core/hle/service/nfc/nfc_device.cpp       |  16 +-
 src/core/hle/service/nfc/nfc_types.h          |  42 ++-
 13 files changed, 308 insertions(+), 133 deletions(-)
 create mode 100644 src/core/hle/mii.cpp
 create mode 100644 src/core/hle/mii.h

diff --git a/src/android/app/src/main/jni/applets/mii_selector.cpp b/src/android/app/src/main/jni/applets/mii_selector.cpp
index 2009a84ec..2bb48db9a 100644
--- a/src/android/app/src/main/jni/applets/mii_selector.cpp
+++ b/src/android/app/src/main/jni/applets/mii_selector.cpp
@@ -53,7 +53,7 @@ void AndroidMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) {
     const u32 return_code = static_cast<u32>(
         env->GetLongField(data, env->GetFieldID(s_mii_selector_data_class, "return_code", "J")));
     if (return_code == 1) {
-        Finalize(return_code, HLE::Applets::MiiData{});
+        Finalize(return_code, Mii::MiiData{});
         return;
     }
 
diff --git a/src/citra_qt/applets/mii_selector.cpp b/src/citra_qt/applets/mii_selector.cpp
index 2099e675e..199b3f924 100644
--- a/src/citra_qt/applets/mii_selector.cpp
+++ b/src/citra_qt/applets/mii_selector.cpp
@@ -67,6 +67,5 @@ void QtMiiSelector::OpenDialog() {
              dialog.return_code, index);
 
     const auto mii_data = dialog.miis.at(index);
-    Finalize(dialog.return_code,
-             dialog.return_code == 0 ? std::move(mii_data) : HLE::Applets::MiiData{});
+    Finalize(dialog.return_code, dialog.return_code == 0 ? std::move(mii_data) : Mii::MiiData{});
 }
diff --git a/src/citra_qt/applets/mii_selector.h b/src/citra_qt/applets/mii_selector.h
index c34549344..6b8867466 100644
--- a/src/citra_qt/applets/mii_selector.h
+++ b/src/citra_qt/applets/mii_selector.h
@@ -24,7 +24,7 @@ private:
     QVBoxLayout* layout;
     QtMiiSelector* mii_selector;
     u32 return_code = 0;
-    std::vector<HLE::Applets::MiiData> miis;
+    std::vector<Mii::MiiData> miis;
 
     friend class QtMiiSelector;
 };
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 186f50fe3..ae71ccc37 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -184,6 +184,8 @@ add_library(citra_core STATIC
     hle/kernel/wait_object.h
     hle/lock.cpp
     hle/lock.h
+    hle/mii.h
+    hle/mii.cpp
     hle/result.h
     hle/romfs.cpp
     hle/romfs.h
diff --git a/src/core/frontend/applets/mii_selector.cpp b/src/core/frontend/applets/mii_selector.cpp
index 6325e7a04..13a864f68 100644
--- a/src/core/frontend/applets/mii_selector.cpp
+++ b/src/core/frontend/applets/mii_selector.cpp
@@ -11,12 +11,12 @@
 
 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};
 }
 
-std::vector<HLE::Applets::MiiData> LoadMiis() {
-    std::vector<HLE::Applets::MiiData> miis;
+std::vector<Mii::MiiData> LoadMiis() {
+    std::vector<Mii::MiiData> miis;
 
     std::string nand_directory{FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)};
     FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true);
@@ -36,7 +36,7 @@ std::vector<HLE::Applets::MiiData> LoadMiis() {
             u32 saved_miis_offset = 0x8;
             // The Mii Maker has a 100 Mii limit on the 3ds
             for (int i = 0; i < 100; ++i) {
-                HLE::Applets::MiiData mii;
+                Mii::MiiData mii;
                 std::array<u8, sizeof(mii)> mii_raw;
                 file->Read(saved_miis_offset, sizeof(mii), mii_raw.data());
                 std::memcpy(&mii, mii_raw.data(), sizeof(mii));
diff --git a/src/core/frontend/applets/mii_selector.h b/src/core/frontend/applets/mii_selector.h
index 0cb095055..7dc404d37 100644
--- a/src/core/frontend/applets/mii_selector.h
+++ b/src/core/frontend/applets/mii_selector.h
@@ -25,7 +25,7 @@ struct MiiSelectorConfig {
 
 struct MiiSelectorData {
     u32 return_code;
-    HLE::Applets::MiiData mii;
+    Mii::MiiData mii;
 };
 
 class MiiSelector {
@@ -43,14 +43,14 @@ public:
      * Stores the data so that the HLE applet in core can
      * send this to the calling application
      */
-    void Finalize(u32 return_code, HLE::Applets::MiiData mii);
+    void Finalize(u32 return_code, Mii::MiiData mii);
 
 protected:
     MiiSelectorConfig config;
     MiiSelectorData data;
 };
 
-std::vector<HLE::Applets::MiiData> LoadMiis();
+std::vector<Mii::MiiData> LoadMiis();
 
 class DefaultMiiSelector final : public MiiSelector {
 public:
diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp
index f4ff0b408..573f9d052 100644
--- a/src/core/hle/applets/mii_selector.cpp
+++ b/src/core/hle/applets/mii_selector.cpp
@@ -71,9 +71,6 @@ void MiiSelector::Update() {
     const MiiSelectorData& data = frontend_applet->ReceiveData();
     result.return_code = data.return_code;
     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;
 
     // 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
     // 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
-    MiiData mii_data;
-    mii_data.mii_id = 0x03001030;
+    Mii::MiiData mii_data;
+    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.specialness_and_creation_date = 0x98391EE4;
-    mii_data.creator_mac = {0x40, 0xF4, 0x07, 0xB7, 0x37, 0x10};
-    mii_data.padding = 0x0;
-    mii_data.mii_information = 0xA600;
+    mii_data.mii_id = 0x98391EE4;
+    mii_data.mac = {0x40, 0xF4, 0x07, 0xB7, 0x37, 0x10};
+    mii_data.pad = 0x0000;
+    mii_data.mii_details.raw = 0xA600;
     mii_data.mii_name = {'C', 'i', 't', 'r', 'a', 0x0, 0x0, 0x0, 0x0, 0x0};
-    mii_data.width_height = 0x4040;
-    mii_data.appearance_bits1.raw = 0x0;
-    mii_data.appearance_bits2.raw = 0x0;
+    mii_data.height = 0x40;
+    mii_data.width = 0x40;
+    mii_data.face_style.raw = 0x00;
+    mii_data.face_details.raw = 0x00;
     mii_data.hair_style = 0x21;
-    mii_data.appearance_bits3.hair_color.Assign(0x1);
-    mii_data.appearance_bits3.flip_hair.Assign(0x0);
-    mii_data.unknown1 = 0x02684418;
-    mii_data.appearance_bits4.eyebrow_style.Assign(0x6);
-    mii_data.appearance_bits4.eyebrow_color.Assign(0x1);
-    mii_data.appearance_bits5.eyebrow_scale.Assign(0x4);
-    mii_data.appearance_bits5.eyebrow_yscale.Assign(0x3);
-    mii_data.appearance_bits6 = 0x4614;
-    mii_data.unknown2 = 0x81121768;
-    mii_data.allow_copying = 0x0D;
-    mii_data.unknown3 = {0x0, 0x0, 0x29, 0x0, 0x52, 0x48, 0x50};
+    mii_data.hair_details.raw = 0x01;
+    mii_data.eye_details.raw = 0x02684418;
+    mii_data.eyebrow_details.raw = 0x26344614;
+    mii_data.nose_details.raw = 0x8112;
+    mii_data.mouth_details.raw = 0x1768;
+    mii_data.mustache_details.raw = 0x0D00;
+    mii_data.beard_details.raw = 0x0029;
+    mii_data.glasses_details.raw = 0x0052;
+    mii_data.mole_details.raw = 0x4850;
     mii_data.author_name = {'f', 'l', 'T', 'o', 'b', 'i', 0x0, 0x0, 0x0, 0x0};
 
     MiiResult result;
@@ -122,8 +121,6 @@ MiiResult MiiSelector::GetStandardMiiResult() {
     result.is_guest_mii_selected = 0x0;
     result.selected_guest_mii_index = 0xFFFFFFFF;
     result.selected_mii_data = mii_data;
-    result.unknown1 = 0x0;
-    result.mii_data_checksum = 0x056C;
     result.guest_mii_name.fill(0x0);
 
     return result;
diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h
index 50cf1bf4a..63d7298de 100644
--- a/src/core/hle/applets/mii_selector.h
+++ b/src/core/hle/applets/mii_selector.h
@@ -9,6 +9,7 @@
 #include "common/common_types.h"
 #include "core/hle/applets/applet.h"
 #include "core/hle/kernel/shared_memory.h"
+#include "core/hle/mii.h"
 #include "core/hle/result.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);
 #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 {
     u32_be return_code;
     u32_be is_guest_mii_selected;
     u32_be selected_guest_mii_index;
-    MiiData selected_mii_data;
-    u16_be unknown1;
-    u16_be mii_data_checksum;
+    Mii::ChecksummedMiiData selected_mii_data;
     std::array<u16_le, 0xC> guest_mii_name;
 };
 static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size");
diff --git a/src/core/hle/mii.cpp b/src/core/hle/mii.cpp
new file mode 100644
index 000000000..09d4f2f47
--- /dev/null
+++ b/src/core/hle/mii.cpp
@@ -0,0 +1,13 @@
+// Copyright 2023 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <boost/crc.hpp>
+#include "core/hle/mii.h"
+
+namespace Mii {
+u16 ChecksummedMiiData::CalculateChecksum() {
+    // 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
diff --git a/src/core/hle/mii.h b/src/core/hle/mii.h
new file mode 100644
index 000000000..bd5784131
--- /dev/null
+++ b/src/core/hle/mii.h
@@ -0,0 +1,239 @@
+// Copyright 2023 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/binary_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
+struct MiiData {
+    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> y_scale;
+        BitField<16, 5, u32> rotation;
+        BitField<21, 4, u32> x_spacing;
+        BitField<25, 5, u32> y_position;
+    } 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> y_scale;
+        BitField<15, 1, u32> pad;
+        BitField<16, 5, u32> rotation;
+        BitField<21, 4, u32> x_spacing;
+        BitField<25, 5, u32> y_position;
+    } eyebrow_details;
+
+    /// Nose details
+    union {
+        u16_be raw;
+
+        BitField<0, 5, u16> style;
+        BitField<5, 4, u16> scale;
+        BitField<9, 5, u16> y_position;
+    } 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> y_scale;
+    } 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> y_pos;
+    } 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> y_pos;
+    } glasses_details;
+
+    /// Mole details
+    union {
+        u16_be raw;
+
+        BitField<0, 1, u16> enable;
+        BitField<1, 5, u16> scale;
+        BitField<6, 5, u16> x_pos;
+        BitField<11, 5, u16> y_pos;
+    } 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& boost::serialization::make_binary_object(this, sizeof(MiiData));
+    }
+    friend class boost::serialization::access;
+};
+
+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.");
+
+struct ChecksummedMiiData {
+private:
+    MiiData mii_data;
+    u16 padding;
+    u16_be crc16;
+
+public:
+    ChecksummedMiiData& operator=(const MiiData& data) {
+        mii_data = data;
+        padding = 0;
+        FixChecksum();
+        return *this;
+    }
+
+    ChecksummedMiiData& operator=(MiiData&& data) {
+        mii_data = std::move(data);
+        padding = 0;
+        FixChecksum();
+        return *this;
+    }
+
+    operator MiiData() const {
+        return mii_data;
+    }
+
+    bool IsChecksumValid() {
+        return crc16 == CalculateChecksum();
+    }
+
+    u16 CalculateChecksum();
+
+    void FixChecksum() {
+        crc16 = CalculateChecksum();
+    }
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::make_binary_object(this, sizeof(ChecksummedMiiData));
+    }
+    friend class boost::serialization::access;
+};
+#pragma pack(pop)
+static_assert(sizeof(ChecksummedMiiData) == 0x60,
+              "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
diff --git a/src/core/hle/service/nfc/amiibo_crypto.cpp b/src/core/hle/service/nfc/amiibo_crypto.cpp
index dc90f0855..a46da923b 100644
--- a/src/core/hle/service/nfc/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfc/amiibo_crypto.cpp
@@ -86,8 +86,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
     encoded_data.amiibo_version = nfc_data.user_memory.amiibo_version;
     encoded_data.settings = nfc_data.user_memory.settings;
     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_write_counter = nfc_data.user_memory.application_write_counter;
     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.settings = encoded_data.settings;
     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_write_counter = encoded_data.application_write_counter;
     nfc_data.user_memory.application_area_id = encoded_data.application_area_id;
diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp
index ff0ba6244..18ac135cc 100644
--- a/src/core/hle/service/nfc/nfc_device.cpp
+++ b/src/core/hle/service/nfc/nfc_device.cpp
@@ -539,7 +539,6 @@ ResultCode NfcDevice::GetRegisterInfo(RegisterInfo& register_info) const {
     // TODO: Validate this data
     register_info = {
         .mii_data = tag.file.owner_mii,
-        .owner_mii_aes_ccm = tag.file.owner_mii_aes_ccm,
         .amiibo_name = settings.amiibo_name,
         .flags = static_cast<u8>(settings.settings.raw & 0xf),
         .font_region = settings.country_code_id,
@@ -628,8 +627,7 @@ ResultCode NfcDevice::DeleteRegisterInfo() {
     }
 
     CryptoPP::AutoSeededRandomPool rng;
-    const std::size_t mii_data_size =
-        sizeof(tag.file.owner_mii) + sizeof(tag.file.padding) + sizeof(tag.file.owner_mii_aes_ccm);
+    const std::size_t mii_data_size = sizeof(tag.file.owner_mii);
     std::array<CryptoPP::byte, mii_data_size> buffer{};
     rng.GenerateBlock(buffer.data(), mii_data_size);
 
@@ -664,12 +662,9 @@ ResultCode NfcDevice::SetRegisterInfoPrivate(const RegisterInfoPrivate& register
         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;
     tag.file.owner_mii = register_info.mii_data;
+    tag.file.owner_mii.FixChecksum();
     tag.file.mii_extension = {};
     tag.file.unknown = 0;
     tag.file.unknown2 = {};
@@ -1061,9 +1056,7 @@ void NfcDevice::UpdateSettingsCrc() {
 void NfcDevice::UpdateRegisterInfoCrc() {
 #pragma pack(push, 1)
     struct CrcData {
-        HLE::Applets::MiiData mii;
-        INSERT_PADDING_BYTES(0x2);
-        u16 mii_crc;
+        Mii::ChecksummedMiiData mii;
         u8 application_id_byte;
         u8 unknown;
         u64 mii_extension;
@@ -1074,7 +1067,6 @@ void NfcDevice::UpdateRegisterInfoCrc() {
 
     const CrcData crc_data{
         .mii = tag.file.owner_mii,
-        .mii_crc = tag.file.owner_mii_aes_ccm,
         .application_id_byte = tag.file.application_id_byte,
         .unknown = tag.file.unknown,
         .mii_extension = tag.file.mii_extension,
@@ -1102,8 +1094,6 @@ void NfcDevice::BuildAmiiboWithoutKeys() {
     settings.settings.font_region.Assign(0);
     settings.init_date = GetAmiiboDate();
     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
     settings.settings.amiibo_initialized.Assign(1);
diff --git a/src/core/hle/service/nfc/nfc_types.h b/src/core/hle/service/nfc/nfc_types.h
index 2a31a16dc..8b08aca9c 100644
--- a/src/core/hle/service/nfc/nfc_types.h
+++ b/src/core/hle/service/nfc/nfc_types.h
@@ -269,20 +269,18 @@ static_assert(sizeof(NTAG215Password) == 0x8, "NTAG215Password is an invalid siz
 
 #pragma pack(1)
 struct EncryptedAmiiboFile {
-    u8 constant_value;                // Must be A5
-    u16_be write_counter;             // Number of times the amiibo has been written?
-    u8 amiibo_version;                // Amiibo file version
-    AmiiboSettings settings;          // Encrypted amiibo settings
-    HashData hmac_tag;                // Hash
-    AmiiboModelInfo model_info;       // Encrypted amiibo model info
-    HashData keygen_salt;             // Salt
-    HashData hmac_data;               // Hash
-    HLE::Applets::MiiData 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
-    u16_be application_write_counter; // Encrypted Counter
-    u32_be application_area_id;       // Encrypted Game id
+    u8 constant_value;                 // Must be A5
+    u16_be write_counter;              // Number of times the amiibo has been written?
+    u8 amiibo_version;                 // Amiibo file version
+    AmiiboSettings settings;           // Encrypted amiibo settings
+    HashData hmac_tag;                 // Hash
+    AmiiboModelInfo model_info;        // Encrypted amiibo model info
+    HashData keygen_salt;              // Salt
+    HashData hmac_data;                // Hash
+    Mii::ChecksummedMiiData owner_mii; // Encrypted Mii data
+    u64_be application_id;             // Encrypted Game id
+    u16_be application_write_counter;  // Encrypted Counter
+    u32_be application_area_id;        // Encrypted Game id
     u8 application_id_byte;
     u8 unknown;
     u64 mii_extension;
@@ -301,11 +299,9 @@ struct NTAG215File {
     u16_be write_counter;      // Number of times the amiibo has been written?
     u8 amiibo_version;         // Amiibo file version
     AmiiboSettings settings;
-    HLE::Applets::MiiData 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
-    u16_be application_write_counter; // Counter
+    Mii::ChecksummedMiiData owner_mii; // Mii data
+    u64_be application_id;             // Game id
+    u16_be application_write_counter;  // Counter
     u32_be application_area_id;
     u8 application_id_byte;
     u8 unknown;
@@ -417,9 +413,7 @@ struct ModelInfo {
 static_assert(sizeof(ModelInfo) == 0x36, "ModelInfo is an invalid size");
 
 struct RegisterInfo {
-    HLE::Applets::MiiData mii_data;
-    INSERT_PADDING_BYTES(0x2);
-    u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC
+    Mii::ChecksummedMiiData mii_data;
     AmiiboName amiibo_name;
     INSERT_PADDING_BYTES(0x2); // Zero string terminator
     u8 flags;
@@ -430,9 +424,7 @@ struct RegisterInfo {
 static_assert(sizeof(RegisterInfo) == 0xA8, "RegisterInfo is an invalid size");
 
 struct RegisterInfoPrivate {
-    HLE::Applets::MiiData mii_data;
-    INSERT_PADDING_BYTES(0x2);
-    u16_be owner_mii_aes_ccm; // Mii data AES-CCM MAC
+    Mii::ChecksummedMiiData mii_data;
     AmiiboName amiibo_name;
     INSERT_PADDING_BYTES(0x2); // Zero string terminator
     u8 flags;