mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-26 08:42:45 +01:00
Merge pull request #9953 from german77/amiibo_crc
service: nfp: Actually write correct crc
This commit is contained in:
commit
8bcaa8c2e4
7 changed files with 154 additions and 49 deletions
|
@ -510,7 +510,7 @@ CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const {
|
||||||
return mii;
|
return mii;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
|
Ver3StoreData MiiManager::BuildFromStoreData(const CharInfo& mii) const {
|
||||||
Service::Mii::MiiManager manager;
|
Service::Mii::MiiManager manager;
|
||||||
Ver3StoreData mii_v3{};
|
Ver3StoreData mii_v3{};
|
||||||
|
|
||||||
|
@ -534,16 +534,13 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
|
||||||
mii_v3.region_information.character_set.Assign(mii.font_region);
|
mii_v3.region_information.character_set.Assign(mii.font_region);
|
||||||
|
|
||||||
mii_v3.appearance_bits1.face_shape.Assign(mii.faceline_type);
|
mii_v3.appearance_bits1.face_shape.Assign(mii.faceline_type);
|
||||||
mii_v3.appearance_bits1.skin_color.Assign(mii.faceline_color);
|
|
||||||
mii_v3.appearance_bits2.wrinkles.Assign(mii.faceline_wrinkle);
|
mii_v3.appearance_bits2.wrinkles.Assign(mii.faceline_wrinkle);
|
||||||
mii_v3.appearance_bits2.makeup.Assign(mii.faceline_make);
|
mii_v3.appearance_bits2.makeup.Assign(mii.faceline_make);
|
||||||
|
|
||||||
mii_v3.hair_style = mii.hair_type;
|
mii_v3.hair_style = mii.hair_type;
|
||||||
mii_v3.appearance_bits3.hair_color.Assign(mii.hair_color);
|
|
||||||
mii_v3.appearance_bits3.flip_hair.Assign(mii.hair_flip);
|
mii_v3.appearance_bits3.flip_hair.Assign(mii.hair_flip);
|
||||||
|
|
||||||
mii_v3.appearance_bits4.eye_type.Assign(mii.eye_type);
|
mii_v3.appearance_bits4.eye_type.Assign(mii.eye_type);
|
||||||
mii_v3.appearance_bits4.eye_color.Assign(mii.eye_color);
|
|
||||||
mii_v3.appearance_bits4.eye_scale.Assign(mii.eye_scale);
|
mii_v3.appearance_bits4.eye_scale.Assign(mii.eye_scale);
|
||||||
mii_v3.appearance_bits4.eye_vertical_stretch.Assign(mii.eye_aspect);
|
mii_v3.appearance_bits4.eye_vertical_stretch.Assign(mii.eye_aspect);
|
||||||
mii_v3.appearance_bits4.eye_rotation.Assign(mii.eye_rotate);
|
mii_v3.appearance_bits4.eye_rotation.Assign(mii.eye_rotate);
|
||||||
|
@ -551,7 +548,6 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
|
||||||
mii_v3.appearance_bits4.eye_y_position.Assign(mii.eye_y);
|
mii_v3.appearance_bits4.eye_y_position.Assign(mii.eye_y);
|
||||||
|
|
||||||
mii_v3.appearance_bits5.eyebrow_style.Assign(mii.eyebrow_type);
|
mii_v3.appearance_bits5.eyebrow_style.Assign(mii.eyebrow_type);
|
||||||
mii_v3.appearance_bits5.eyebrow_color.Assign(mii.eyebrow_color);
|
|
||||||
mii_v3.appearance_bits5.eyebrow_scale.Assign(mii.eyebrow_scale);
|
mii_v3.appearance_bits5.eyebrow_scale.Assign(mii.eyebrow_scale);
|
||||||
mii_v3.appearance_bits5.eyebrow_yscale.Assign(mii.eyebrow_aspect);
|
mii_v3.appearance_bits5.eyebrow_yscale.Assign(mii.eyebrow_aspect);
|
||||||
mii_v3.appearance_bits5.eyebrow_rotation.Assign(mii.eyebrow_rotate);
|
mii_v3.appearance_bits5.eyebrow_rotation.Assign(mii.eyebrow_rotate);
|
||||||
|
@ -563,7 +559,6 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
|
||||||
mii_v3.appearance_bits6.nose_y_position.Assign(mii.nose_y);
|
mii_v3.appearance_bits6.nose_y_position.Assign(mii.nose_y);
|
||||||
|
|
||||||
mii_v3.appearance_bits7.mouth_type.Assign(mii.mouth_type);
|
mii_v3.appearance_bits7.mouth_type.Assign(mii.mouth_type);
|
||||||
mii_v3.appearance_bits7.mouth_color.Assign(mii.mouth_color);
|
|
||||||
mii_v3.appearance_bits7.mouth_scale.Assign(mii.mouth_scale);
|
mii_v3.appearance_bits7.mouth_scale.Assign(mii.mouth_scale);
|
||||||
mii_v3.appearance_bits7.mouth_horizontal_stretch.Assign(mii.mouth_aspect);
|
mii_v3.appearance_bits7.mouth_horizontal_stretch.Assign(mii.mouth_aspect);
|
||||||
mii_v3.appearance_bits8.mouth_y_position.Assign(mii.mouth_y);
|
mii_v3.appearance_bits8.mouth_y_position.Assign(mii.mouth_y);
|
||||||
|
@ -573,10 +568,7 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
|
||||||
mii_v3.appearance_bits9.mustache_y_position.Assign(mii.mustache_y);
|
mii_v3.appearance_bits9.mustache_y_position.Assign(mii.mustache_y);
|
||||||
|
|
||||||
mii_v3.appearance_bits9.bear_type.Assign(mii.beard_type);
|
mii_v3.appearance_bits9.bear_type.Assign(mii.beard_type);
|
||||||
mii_v3.appearance_bits9.facial_hair_color.Assign(mii.beard_color);
|
|
||||||
|
|
||||||
mii_v3.appearance_bits10.glasses_type.Assign(mii.glasses_type);
|
|
||||||
mii_v3.appearance_bits10.glasses_color.Assign(mii.glasses_color);
|
|
||||||
mii_v3.appearance_bits10.glasses_scale.Assign(mii.glasses_scale);
|
mii_v3.appearance_bits10.glasses_scale.Assign(mii.glasses_scale);
|
||||||
mii_v3.appearance_bits10.glasses_y_position.Assign(mii.glasses_y);
|
mii_v3.appearance_bits10.glasses_y_position.Assign(mii.glasses_y);
|
||||||
|
|
||||||
|
@ -585,11 +577,36 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
|
||||||
mii_v3.appearance_bits11.mole_x_position.Assign(mii.mole_x);
|
mii_v3.appearance_bits11.mole_x_position.Assign(mii.mole_x);
|
||||||
mii_v3.appearance_bits11.mole_y_position.Assign(mii.mole_y);
|
mii_v3.appearance_bits11.mole_y_position.Assign(mii.mole_y);
|
||||||
|
|
||||||
|
// These types are converted to V3 from a table
|
||||||
|
mii_v3.appearance_bits1.skin_color.Assign(Ver3FacelineColorTable[mii.faceline_color]);
|
||||||
|
mii_v3.appearance_bits3.hair_color.Assign(Ver3HairColorTable[mii.hair_color]);
|
||||||
|
mii_v3.appearance_bits4.eye_color.Assign(Ver3EyeColorTable[mii.eye_color]);
|
||||||
|
mii_v3.appearance_bits5.eyebrow_color.Assign(Ver3HairColorTable[mii.eyebrow_color]);
|
||||||
|
mii_v3.appearance_bits7.mouth_color.Assign(Ver3MouthlineColorTable[mii.mouth_color]);
|
||||||
|
mii_v3.appearance_bits9.facial_hair_color.Assign(Ver3HairColorTable[mii.beard_color]);
|
||||||
|
mii_v3.appearance_bits10.glasses_color.Assign(Ver3GlassColorTable[mii.glasses_color]);
|
||||||
|
mii_v3.appearance_bits10.glasses_type.Assign(Ver3GlassTypeTable[mii.glasses_type]);
|
||||||
|
|
||||||
|
mii_v3.crc = GenerateCrc16(&mii_v3, sizeof(Ver3StoreData) - sizeof(u16));
|
||||||
|
|
||||||
// TODO: Validate mii_v3 data
|
// TODO: Validate mii_v3 data
|
||||||
|
|
||||||
return mii_v3;
|
return mii_v3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NfpStoreDataExtension MiiManager::SetFromStoreData(const CharInfo& mii) const {
|
||||||
|
return {
|
||||||
|
.faceline_color = static_cast<u8>(mii.faceline_color & 0xf),
|
||||||
|
.hair_color = static_cast<u8>(mii.hair_color & 0x7f),
|
||||||
|
.eye_color = static_cast<u8>(mii.eyebrow_color & 0x7f),
|
||||||
|
.eyebrow_color = static_cast<u8>(mii.eyebrow_color & 0x7f),
|
||||||
|
.mouth_color = static_cast<u8>(mii.mouth_color & 0x7f),
|
||||||
|
.beard_color = static_cast<u8>(mii.beard_color & 0x7f),
|
||||||
|
.glass_color = static_cast<u8>(mii.glasses_color & 0x7f),
|
||||||
|
.glass_type = static_cast<u8>(mii.glasses_type & 0x1f),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const {
|
bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const {
|
||||||
bool is_valid = mii_v3.version == 0 || mii_v3.version == 3;
|
bool is_valid = mii_v3.version == 0 || mii_v3.version == 3;
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,16 @@ public:
|
||||||
CharInfo BuildRandom(Age age, Gender gender, Race race);
|
CharInfo BuildRandom(Age age, Gender gender, Race race);
|
||||||
CharInfo BuildDefault(std::size_t index);
|
CharInfo BuildDefault(std::size_t index);
|
||||||
CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const;
|
CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const;
|
||||||
Ver3StoreData ConvertCharInfoToV3(const CharInfo& mii) const;
|
|
||||||
bool ValidateV3Info(const Ver3StoreData& mii_v3) const;
|
bool ValidateV3Info(const Ver3StoreData& mii_v3) const;
|
||||||
ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag);
|
ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag);
|
||||||
Result GetIndex(const CharInfo& info, u32& index);
|
Result GetIndex(const CharInfo& info, u32& index);
|
||||||
|
|
||||||
|
// This is nn::mii::detail::Ver::StoreDataRaw::BuildFromStoreData
|
||||||
|
Ver3StoreData BuildFromStoreData(const CharInfo& mii) const;
|
||||||
|
|
||||||
|
// This is nn::mii::detail::NfpStoreDataExtentionRaw::SetFromStoreData
|
||||||
|
NfpStoreDataExtension SetFromStoreData(const CharInfo& mii) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Common::UUID user_id{};
|
const Common::UUID user_id{};
|
||||||
u64 update_counter{};
|
u64 update_counter{};
|
||||||
|
|
|
@ -365,10 +365,68 @@ struct Ver3StoreData {
|
||||||
} appearance_bits11;
|
} appearance_bits11;
|
||||||
|
|
||||||
std::array<u16_le, 0xA> author_name;
|
std::array<u16_le, 0xA> author_name;
|
||||||
INSERT_PADDING_BYTES(0x4);
|
INSERT_PADDING_BYTES(0x2);
|
||||||
|
u16_be crc;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Ver3StoreData) == 0x60, "Ver3StoreData is an invalid size");
|
static_assert(sizeof(Ver3StoreData) == 0x60, "Ver3StoreData is an invalid size");
|
||||||
|
|
||||||
|
struct NfpStoreDataExtension {
|
||||||
|
u8 faceline_color;
|
||||||
|
u8 hair_color;
|
||||||
|
u8 eye_color;
|
||||||
|
u8 eyebrow_color;
|
||||||
|
u8 mouth_color;
|
||||||
|
u8 beard_color;
|
||||||
|
u8 glass_color;
|
||||||
|
u8 glass_type;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NfpStoreDataExtension) == 0x8, "NfpStoreDataExtension is an invalid size");
|
||||||
|
|
||||||
|
constexpr std::array<u8, 0x10> Ver3FacelineColorTable{
|
||||||
|
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x0, 0x1, 0x5, 0x5,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::array<u8, 100> Ver3HairColorTable{
|
||||||
|
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x4, 0x3, 0x5, 0x4, 0x4, 0x6, 0x2, 0x0,
|
||||||
|
0x6, 0x4, 0x3, 0x2, 0x2, 0x7, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||||
|
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x4,
|
||||||
|
0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5,
|
||||||
|
0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x7, 0x5, 0x7, 0x7, 0x7, 0x7, 0x7, 0x6, 0x7,
|
||||||
|
0x7, 0x7, 0x7, 0x7, 0x3, 0x7, 0x7, 0x7, 0x7, 0x7, 0x0, 0x4, 0x4, 0x4, 0x4,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::array<u8, 100> Ver3EyeColorTable{
|
||||||
|
0x0, 0x2, 0x2, 0x2, 0x1, 0x3, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x2, 0x2, 0x4,
|
||||||
|
0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||||
|
0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x0, 0x4, 0x4,
|
||||||
|
0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5,
|
||||||
|
0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x2, 0x2,
|
||||||
|
0x3, 0x3, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::array<u8, 100> Ver3MouthlineColorTable{
|
||||||
|
0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x4,
|
||||||
|
0x4, 0x4, 0x0, 0x1, 0x2, 0x3, 0x4, 0x4, 0x2, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x1, 0x4,
|
||||||
|
0x4, 0x2, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4,
|
||||||
|
0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4,
|
||||||
|
0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3,
|
||||||
|
0x3, 0x3, 0x3, 0x3, 0x4, 0x0, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, 0x3, 0x3,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::array<u8, 100> Ver3GlassColorTable{
|
||||||
|
0x0, 0x1, 0x1, 0x1, 0x5, 0x1, 0x1, 0x4, 0x0, 0x5, 0x1, 0x1, 0x3, 0x5, 0x1, 0x2, 0x3,
|
||||||
|
0x4, 0x5, 0x4, 0x2, 0x2, 0x4, 0x4, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||||
|
0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3,
|
||||||
|
0x3, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x0, 0x5, 0x5,
|
||||||
|
0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x1, 0x4,
|
||||||
|
0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::array<u8, 20> Ver3GlassTypeTable{
|
||||||
|
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1,
|
||||||
|
0x2, 0x1, 0x3, 0x7, 0x7, 0x6, 0x7, 0x8, 0x7, 0x7,
|
||||||
|
};
|
||||||
|
|
||||||
struct MiiStoreData {
|
struct MiiStoreData {
|
||||||
using Name = std::array<char16_t, 10>;
|
using Name = std::array<char16_t, 10>;
|
||||||
|
|
||||||
|
|
|
@ -88,8 +88,9 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
|
||||||
encoded_data.application_area_id = nfc_data.user_memory.application_area_id;
|
encoded_data.application_area_id = nfc_data.user_memory.application_area_id;
|
||||||
encoded_data.application_id_byte = nfc_data.user_memory.application_id_byte;
|
encoded_data.application_id_byte = nfc_data.user_memory.application_id_byte;
|
||||||
encoded_data.unknown = nfc_data.user_memory.unknown;
|
encoded_data.unknown = nfc_data.user_memory.unknown;
|
||||||
|
encoded_data.mii_extension = nfc_data.user_memory.mii_extension;
|
||||||
encoded_data.unknown2 = nfc_data.user_memory.unknown2;
|
encoded_data.unknown2 = nfc_data.user_memory.unknown2;
|
||||||
encoded_data.application_area_crc = nfc_data.user_memory.application_area_crc;
|
encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc;
|
||||||
encoded_data.application_area = nfc_data.user_memory.application_area;
|
encoded_data.application_area = nfc_data.user_memory.application_area;
|
||||||
encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag;
|
encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag;
|
||||||
encoded_data.lock_bytes = nfc_data.uuid.lock_bytes;
|
encoded_data.lock_bytes = nfc_data.uuid.lock_bytes;
|
||||||
|
@ -122,8 +123,9 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
|
||||||
nfc_data.user_memory.application_area_id = encoded_data.application_area_id;
|
nfc_data.user_memory.application_area_id = encoded_data.application_area_id;
|
||||||
nfc_data.user_memory.application_id_byte = encoded_data.application_id_byte;
|
nfc_data.user_memory.application_id_byte = encoded_data.application_id_byte;
|
||||||
nfc_data.user_memory.unknown = encoded_data.unknown;
|
nfc_data.user_memory.unknown = encoded_data.unknown;
|
||||||
|
nfc_data.user_memory.mii_extension = encoded_data.mii_extension;
|
||||||
nfc_data.user_memory.unknown2 = encoded_data.unknown2;
|
nfc_data.user_memory.unknown2 = encoded_data.unknown2;
|
||||||
nfc_data.user_memory.application_area_crc = encoded_data.application_area_crc;
|
nfc_data.user_memory.register_info_crc = encoded_data.register_info_crc;
|
||||||
nfc_data.user_memory.application_area = encoded_data.application_area;
|
nfc_data.user_memory.application_area = encoded_data.application_area;
|
||||||
nfc_data.user_memory.hmac_tag = encoded_data.hmac_tag;
|
nfc_data.user_memory.hmac_tag = encoded_data.hmac_tag;
|
||||||
nfc_data.user_memory.model_info = encoded_data.model_info;
|
nfc_data.user_memory.model_info = encoded_data.model_info;
|
||||||
|
|
|
@ -3,6 +3,17 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/crc.hpp>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common/input.h"
|
#include "common/input.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
@ -448,7 +459,7 @@ Result NfpDevice::DeleteRegisterInfo() {
|
||||||
rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8));
|
rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8));
|
||||||
rng.GenerateRandomBytes(&tag_data.unknown2[0], sizeof(u32));
|
rng.GenerateRandomBytes(&tag_data.unknown2[0], sizeof(u32));
|
||||||
rng.GenerateRandomBytes(&tag_data.unknown2[1], sizeof(u32));
|
rng.GenerateRandomBytes(&tag_data.unknown2[1], sizeof(u32));
|
||||||
rng.GenerateRandomBytes(&tag_data.application_area_crc, sizeof(u32));
|
rng.GenerateRandomBytes(&tag_data.register_info_crc, sizeof(u32));
|
||||||
rng.GenerateRandomBytes(&tag_data.settings.init_date, sizeof(u32));
|
rng.GenerateRandomBytes(&tag_data.settings.init_date, sizeof(u32));
|
||||||
tag_data.settings.settings.font_region.Assign(0);
|
tag_data.settings.settings.font_region.Assign(0);
|
||||||
tag_data.settings.settings.amiibo_initialized.Assign(0);
|
tag_data.settings.settings.amiibo_initialized.Assign(0);
|
||||||
|
@ -471,6 +482,7 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::Mii::MiiManager manager;
|
Service::Mii::MiiManager manager;
|
||||||
|
const auto mii = manager.BuildDefault(0);
|
||||||
auto& settings = tag_data.settings;
|
auto& settings = tag_data.settings;
|
||||||
|
|
||||||
if (tag_data.settings.settings.amiibo_initialized == 0) {
|
if (tag_data.settings.settings.amiibo_initialized == 0) {
|
||||||
|
@ -479,16 +491,15 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAmiiboName(settings, amiibo_name);
|
SetAmiiboName(settings, amiibo_name);
|
||||||
tag_data.owner_mii = manager.ConvertCharInfoToV3(manager.BuildDefault(0));
|
tag_data.owner_mii = manager.BuildFromStoreData(mii);
|
||||||
|
tag_data.mii_extension = manager.SetFromStoreData(mii);
|
||||||
tag_data.unknown = 0;
|
tag_data.unknown = 0;
|
||||||
tag_data.unknown2[6] = 0;
|
tag_data.unknown2 = {};
|
||||||
settings.country_code_id = 0;
|
settings.country_code_id = 0;
|
||||||
settings.settings.font_region.Assign(0);
|
settings.settings.font_region.Assign(0);
|
||||||
settings.settings.amiibo_initialized.Assign(1);
|
settings.settings.amiibo_initialized.Assign(1);
|
||||||
|
|
||||||
// TODO: this is a mix of tag.file input
|
UpdateRegisterInfoCrc();
|
||||||
std::array<u8, 0x7e> unknown_input{};
|
|
||||||
tag_data.application_area_crc = CalculateCrc(unknown_input);
|
|
||||||
|
|
||||||
return Flush();
|
return Flush();
|
||||||
}
|
}
|
||||||
|
@ -685,6 +696,11 @@ Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat
|
||||||
return WrongDeviceState;
|
return WrongDeviceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_app_area_open) {
|
||||||
|
LOG_ERROR(Service_NFP, "Application area is open");
|
||||||
|
return WrongDeviceState;
|
||||||
|
}
|
||||||
|
|
||||||
if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
|
if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
|
||||||
LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
|
LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
|
||||||
return WrongDeviceState;
|
return WrongDeviceState;
|
||||||
|
@ -715,10 +731,9 @@ Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat
|
||||||
tag_data.settings.settings.appdata_initialized.Assign(1);
|
tag_data.settings.settings.appdata_initialized.Assign(1);
|
||||||
tag_data.application_area_id = access_id;
|
tag_data.application_area_id = access_id;
|
||||||
tag_data.unknown = {};
|
tag_data.unknown = {};
|
||||||
|
tag_data.unknown2 = {};
|
||||||
|
|
||||||
// TODO: this is a mix of tag_data input
|
UpdateRegisterInfoCrc();
|
||||||
std::array<u8, 0x7e> unknown_input{};
|
|
||||||
tag_data.application_area_crc = CalculateCrc(unknown_input);
|
|
||||||
|
|
||||||
return Flush();
|
return Flush();
|
||||||
}
|
}
|
||||||
|
@ -752,6 +767,10 @@ Result NfpDevice::DeleteApplicationArea() {
|
||||||
rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8));
|
rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8));
|
||||||
tag_data.settings.settings.appdata_initialized.Assign(0);
|
tag_data.settings.settings.appdata_initialized.Assign(0);
|
||||||
tag_data.unknown = {};
|
tag_data.unknown = {};
|
||||||
|
tag_data.unknown2 = {};
|
||||||
|
is_app_area_open = false;
|
||||||
|
|
||||||
|
UpdateRegisterInfoCrc();
|
||||||
|
|
||||||
return Flush();
|
return Flush();
|
||||||
}
|
}
|
||||||
|
@ -835,32 +854,34 @@ void NfpDevice::UpdateSettingsCrc() {
|
||||||
|
|
||||||
// TODO: this reads data from a global, find what it is
|
// TODO: this reads data from a global, find what it is
|
||||||
std::array<u8, 8> unknown_input{};
|
std::array<u8, 8> unknown_input{};
|
||||||
settings.crc = CalculateCrc(unknown_input);
|
boost::crc_32_type crc;
|
||||||
|
crc.process_bytes(&unknown_input, sizeof(unknown_input));
|
||||||
|
settings.crc = crc.checksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 NfpDevice::CalculateCrc(std::span<const u8> data) {
|
void NfpDevice::UpdateRegisterInfoCrc() {
|
||||||
constexpr u32 magic = 0xedb88320;
|
#pragma pack(push, 1)
|
||||||
u32 crc = 0xffffffff;
|
struct CrcData {
|
||||||
|
Mii::Ver3StoreData mii;
|
||||||
|
u8 application_id_byte;
|
||||||
|
u8 unknown;
|
||||||
|
Mii::NfpStoreDataExtension mii_extension;
|
||||||
|
std::array<u32, 0x5> unknown2;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CrcData) == 0x7e, "CrcData is an invalid size");
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
if (data.size() == 0) {
|
const CrcData crc_data{
|
||||||
return 0;
|
.mii = tag_data.owner_mii,
|
||||||
}
|
.application_id_byte = tag_data.application_id_byte,
|
||||||
|
.unknown = tag_data.unknown,
|
||||||
|
.mii_extension = tag_data.mii_extension,
|
||||||
|
.unknown2 = tag_data.unknown2,
|
||||||
|
};
|
||||||
|
|
||||||
for (u8 input : data) {
|
boost::crc_32_type crc;
|
||||||
u32 temp = (crc ^ input) >> 1;
|
crc.process_bytes(&crc_data, sizeof(CrcData));
|
||||||
if (((crc ^ input) & 1) != 0) {
|
tag_data.register_info_crc = crc.checksum();
|
||||||
temp = temp ^ magic;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t step = 0; step < 7; ++step) {
|
|
||||||
crc = temp >> 1;
|
|
||||||
if ((temp & 1) != 0) {
|
|
||||||
crc = temp >> 1 ^ magic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ~crc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::NFP
|
} // namespace Service::NFP
|
||||||
|
|
|
@ -80,7 +80,7 @@ private:
|
||||||
AmiiboDate GetAmiiboDate(s64 posix_time) const;
|
AmiiboDate GetAmiiboDate(s64 posix_time) const;
|
||||||
u64 RemoveVersionByte(u64 application_id) const;
|
u64 RemoveVersionByte(u64 application_id) const;
|
||||||
void UpdateSettingsCrc();
|
void UpdateSettingsCrc();
|
||||||
u32 CalculateCrc(std::span<const u8>);
|
void UpdateRegisterInfoCrc();
|
||||||
|
|
||||||
bool is_controller_set{};
|
bool is_controller_set{};
|
||||||
int callback_key;
|
int callback_key;
|
||||||
|
|
|
@ -259,8 +259,9 @@ struct EncryptedAmiiboFile {
|
||||||
u32_be application_area_id; // Encrypted Game id
|
u32_be application_area_id; // Encrypted Game id
|
||||||
u8 application_id_byte;
|
u8 application_id_byte;
|
||||||
u8 unknown;
|
u8 unknown;
|
||||||
std::array<u32, 0x7> unknown2;
|
Service::Mii::NfpStoreDataExtension mii_extension;
|
||||||
u32_be application_area_crc;
|
std::array<u32, 0x5> unknown2;
|
||||||
|
u32_be register_info_crc;
|
||||||
ApplicationArea application_area; // Encrypted Game data
|
ApplicationArea application_area; // Encrypted Game data
|
||||||
};
|
};
|
||||||
static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size");
|
static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size");
|
||||||
|
@ -280,8 +281,9 @@ struct NTAG215File {
|
||||||
u32_be application_area_id;
|
u32_be application_area_id;
|
||||||
u8 application_id_byte;
|
u8 application_id_byte;
|
||||||
u8 unknown;
|
u8 unknown;
|
||||||
std::array<u32, 0x7> unknown2;
|
Service::Mii::NfpStoreDataExtension mii_extension;
|
||||||
u32_be application_area_crc;
|
std::array<u32, 0x5> unknown2;
|
||||||
|
u32_be register_info_crc;
|
||||||
ApplicationArea application_area; // Encrypted Game data
|
ApplicationArea application_area; // Encrypted Game data
|
||||||
HashData hmac_tag; // Hash
|
HashData hmac_tag; // Hash
|
||||||
UniqueSerialNumber uid; // Unique serial number
|
UniqueSerialNumber uid; // Unique serial number
|
||||||
|
|
Loading…
Reference in a new issue