From 3b9a76eec807e38656b1acbbf7208c6dc1ccc504 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Fri, 31 Mar 2023 23:56:25 -0700 Subject: [PATCH] implement save file decryption/encryption --- CMakeLists.txt | 14 +- README.md | 1 + src/BMLArchive.cc | 28 ++-- src/BMLArchive.hh | 2 +- src/CommandFormats.hh | 20 +-- src/CommonItemSet.cc | 8 +- src/CommonItemSet.hh | 10 +- src/Episode3/DataIndex.cc | 30 +++++ src/Episode3/DataIndex.hh | 7 +- src/FunctionCompiler.cc | 8 +- src/FunctionCompiler.hh | 2 +- src/GSLArchive.cc | 16 ++- src/GSLArchive.hh | 2 +- src/ItemCreator.hh | 2 +- src/Main.cc | 110 ++++++++++++++- src/Map.cc | 8 +- src/Map.hh | 2 +- src/PSOEncryption.cc | 36 ++++- src/PSOEncryption.hh | 10 +- src/Player.hh | 17 +-- src/Quest.cc | 166 +++++------------------ src/SaveFileFormats.cc | 89 +++++++++++++ src/SaveFileFormats.hh | 229 ++++++++++++++++++++++++++++++++ test-decode-gci.sh | 36 +++++ test-decode-vms.sh | 18 +++ tests/GCICharFile.gcid | Bin 0 -> 122944 bytes tests/GCIEpisode3.dec | Bin 0 -> 2030 bytes tests/GCIEpisode3.gci | Bin 0 -> 24640 bytes tests/GCISystemFile.gci | Bin 0 -> 24640 bytes tests/GCIWIthoutEncryption.gci | Bin 0 -> 24640 bytes tests/GCIWithEmbeddedKey.dec | Bin 0 -> 5740 bytes tests/GCIWithEmbeddedKey.gci | Bin 0 -> 24640 bytes tests/GCIWithoutEmbeddedKey.dec | Bin 0 -> 1932 bytes tests/GCIWithoutEmbeddedKey.gci | Bin 0 -> 24640 bytes tests/GCIWithoutEncryption.dec | Bin 0 -> 7182 bytes tests/LionelV1.dec | Bin 0 -> 4374 bytes tests/LionelV1.vms | Bin 0 -> 6144 bytes tests/LionelV2.dec | Bin 0 -> 4402 bytes tests/LionelV2.vms | Bin 0 -> 5632 bytes 39 files changed, 666 insertions(+), 205 deletions(-) create mode 100644 src/SaveFileFormats.cc create mode 100644 src/SaveFileFormats.hh create mode 100755 test-decode-gci.sh create mode 100755 test-decode-vms.sh create mode 100755 tests/GCICharFile.gcid create mode 100755 tests/GCIEpisode3.dec create mode 100644 tests/GCIEpisode3.gci create mode 100644 tests/GCISystemFile.gci create mode 100644 tests/GCIWIthoutEncryption.gci create mode 100755 tests/GCIWithEmbeddedKey.dec create mode 100644 tests/GCIWithEmbeddedKey.gci create mode 100755 tests/GCIWithoutEmbeddedKey.dec create mode 100644 tests/GCIWithoutEmbeddedKey.gci create mode 100755 tests/GCIWithoutEncryption.dec create mode 100755 tests/LionelV1.dec create mode 100644 tests/LionelV1.vms create mode 100755 tests/LionelV2.dec create mode 100644 tests/LionelV2.vms diff --git a/CMakeLists.txt b/CMakeLists.txt index e13e8ff3..c7eb44a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ add_executable(newserv src/ReceiveCommands.cc src/ReceiveSubcommands.cc src/ReplaySession.cc + src/SaveFileFormats.cc src/SendCommands.cc src/Server.cc src/ServerShell.cc @@ -125,14 +126,23 @@ foreach(TestCase IN ITEMS ${TestCases}) endforeach() add_test( - NAME compression-prs + NAME "compression-prs" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${CMAKE_SOURCE_DIR}/test-compression.sh prs ${CMAKE_BINARY_DIR}/newserv) add_test( - NAME compression-bc0 + NAME "compression-bc0" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${CMAKE_SOURCE_DIR}/test-compression.sh bc0 ${CMAKE_BINARY_DIR}/newserv) +add_test( + NAME "decode-vms" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ${CMAKE_SOURCE_DIR}/test-decode-vms.sh ${CMAKE_BINARY_DIR}/newserv) + +add_test( + NAME "decode-gci" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ${CMAKE_SOURCE_DIR}/test-decode-gci.sh ${CMAKE_BINARY_DIR}/newserv) # Installation configuration diff --git a/README.md b/README.md index f9d688a0..6a88edeb 100644 --- a/README.md +++ b/README.md @@ -367,6 +367,7 @@ newserv has many CLI options, which can be used to access functionality other th * Compute the decompressed size of compressed PRS data without decompressing it * Encrypt or decrypt data using any PSO version's network encryption scheme * Encrypt or decrypt data using Episode 3's trivial scheme +* Encrypt or decrypt PSO GC save data (.gci files) * Run a brute-force search for a decryption seed * Decode Shift-JIS text to UTF-16 * Convert quests in .gci, .vms, .dlq, or .qst format to .bin/.dat format diff --git a/src/BMLArchive.cc b/src/BMLArchive.cc index f07bafed..c9020f62 100644 --- a/src/BMLArchive.cc +++ b/src/BMLArchive.cc @@ -10,33 +10,37 @@ using namespace std; -template +template struct BMLHeader { + using U32T = typename std::conditional::type; + parray unknown_a1; - LongT num_entries; + U32T num_entries; parray unknown_a2; } __attribute__((packed)); -template +template struct BMLHeaderEntry { + using U32T = typename std::conditional::type; + ptext filename; - LongT compressed_size; + U32T compressed_size; parray unknown_a1; - LongT decompressed_size; - LongT compressed_gvm_size; - LongT decompressed_gvm_size; + U32T decompressed_size; + U32T compressed_gvm_size; + U32T decompressed_gvm_size; parray unknown_a2; } __attribute__((packed)); -template +template void BMLArchive::load_t() { StringReader r(*this->data); - const auto& header = r.get>(); + const auto& header = r.get>(); size_t offset = 0x800; while (this->entries.size() < header.num_entries) { - const auto& entry = r.get>(); + const auto& entry = r.get>(); if (offset + entry.compressed_size > this->data->size()) { throw runtime_error("BML data entry extends beyond end of data"); @@ -58,9 +62,9 @@ void BMLArchive::load_t() { BMLArchive::BMLArchive(shared_ptr data, bool big_endian) : data(data) { if (big_endian) { - this->load_t(); + this->load_t(); } else { - this->load_t(); + this->load_t(); } } diff --git a/src/BMLArchive.hh b/src/BMLArchive.hh index bc7b5a87..a29fec31 100644 --- a/src/BMLArchive.hh +++ b/src/BMLArchive.hh @@ -29,7 +29,7 @@ public: StringReader get_reader(const std::string& name) const; private: - template + template void load_t(); std::shared_ptr data; diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 17f39909..77d98357 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -1905,8 +1905,11 @@ struct S_ExecuteCode_B2 { // The code immediately follows, ending with an S_ExecuteCode_Footer_B2 } __packed__; -template +template struct S_ExecuteCode_Footer_B2 { + using U16T = typename std::conditional:: type; + using U32T = typename std::conditional:: type; + // Relocations is a list of words (le_uint16_t on DC/PC/XB/BB, be_uint16_t on // GC) containing the number of doublewords (uint32_t) to skip for each // relocation. The relocation pointer starts immediately after the @@ -1925,19 +1928,18 @@ struct S_ExecuteCode_Footer_B2 { // relocations_offset points there, so those 12 bytes may also be omitted from // the command entirely (without changing code_size - so code_size would // technically extend beyond the end of the B2 command). - LongT relocations_offset = 0; // Relative to code base (after checksum_size) - LongT num_relocations = 0; - parray unused1; + U32T relocations_offset = 0; // Relative to code base (after checksum_size) + U32T num_relocations = 0; + parray unused1; // entrypoint_offset is doubly indirect - it points to a pointer to a 32-bit // value that itself is the actual entrypoint. This is presumably done so the // entrypoint can be optionally relocated. - LongT entrypoint_addr_offset = 0; // Relative to code base (after checksum_size). - parray unused2; + U32T entrypoint_addr_offset = 0; // Relative to code base (after checksum_size). + parray unused2; } __packed__; -struct S_ExecuteCode_Footer_GC_B2 : S_ExecuteCode_Footer_B2 { } __packed__; -struct S_ExecuteCode_Footer_DC_PC_XB_BB_B2 - : S_ExecuteCode_Footer_B2 { } __packed__; +struct S_ExecuteCode_Footer_GC_B2 : S_ExecuteCode_Footer_B2 { } __packed__; +struct S_ExecuteCode_Footer_DC_PC_XB_BB_B2 : S_ExecuteCode_Footer_B2 { } __packed__; // B3 (C->S): Execute code and/or checksum memory result // Not used on versions that don't support the B2 command (see above). diff --git a/src/CommonItemSet.cc b/src/CommonItemSet.cc index 74c9f2e5..b73762be 100644 --- a/src/CommonItemSet.cc +++ b/src/CommonItemSet.cc @@ -7,7 +7,7 @@ CommonItemSet::CommonItemSet(shared_ptr data) : gsl(data, true) { } -const CommonItemSet::BETable& CommonItemSet::get_table( +const CommonItemSet::Table& CommonItemSet::get_table( Episode episode, GameMode mode, uint8_t difficulty, uint8_t secid) const { // TODO: What should we do for Ep4? string filename = string_printf("ItemPT%s%s%c%1d.rel", @@ -16,12 +16,12 @@ const CommonItemSet::BETable& CommonItemSet::get_table( tolower(abbreviation_for_difficulty(difficulty)), secid); auto data = this->gsl.get(filename); - if (data.second < sizeof(BETable)) { + if (data.second < sizeof(Table)) { throw runtime_error(string_printf( "ItemPT entry %s is too small (received %zX bytes, expected %zX bytes)", - filename.c_str(), data.second, sizeof(BETable))); + filename.c_str(), data.second, sizeof(Table))); } - return *reinterpret_cast(data.first); + return *reinterpret_cast*>(data.first); } diff --git a/src/CommonItemSet.hh b/src/CommonItemSet.hh index b8880b85..3db53edf 100644 --- a/src/CommonItemSet.hh +++ b/src/CommonItemSet.hh @@ -23,9 +23,10 @@ public: // (is_ep2 ? "l" : ""), // char_for_difficulty(difficulty), // One of "nhvu" // section_id); - // For GC, use be_uint16_t/be_uint32_t; for other platforms use le variants - template + template struct Table { + using U16T = typename std::conditional::type; + using U32T = typename std::conditional::type; // This data structure uses index probability tables in multiple places. An // index probability table is a table where each entry holds the probability // that that entry's index is used. For example, if the armor slot count @@ -240,10 +241,7 @@ public: CommonItemSet(std::shared_ptr data); - using BETable = Table; - using LETable = Table; - - const BETable& get_table( + const Table& get_table( Episode episode, GameMode mode, uint8_t difficulty, uint8_t secid) const; private: diff --git a/src/Episode3/DataIndex.cc b/src/Episode3/DataIndex.cc index eb77dec9..c51f2654 100644 --- a/src/Episode3/DataIndex.cc +++ b/src/Episode3/DataIndex.cc @@ -10,6 +10,7 @@ #include "../Loggers.hh" #include "../Compression.hh" +#include "../PSOEncryption.hh" #include "../Text.hh" #include "../Quest.hh" @@ -1712,4 +1713,33 @@ shared_ptr DataIndex::random_com_deck() const { +void PlayerConfig::decrypt() { + if (!this->is_encrypted) { + return; + } + decrypt_trivial_gci_data( + &this->card_counts, + offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts), + this->basis); + this->is_encrypted = 0; + this->basis = 0; +} + +void PlayerConfig::encrypt(uint8_t basis) { + if (this->is_encrypted) { + if (this->basis == basis) { + return; + } + this->decrypt(); + } + decrypt_trivial_gci_data( + &this->card_counts, + offsetof(PlayerConfig, decks) - offsetof(PlayerConfig, card_counts), + basis); + this->is_encrypted = 1; + this->basis = basis; +} + + + } // namespace Episode3 diff --git a/src/Episode3/DataIndex.hh b/src/Episode3/DataIndex.hh index 683090c6..b15447c0 100644 --- a/src/Episode3/DataIndex.hh +++ b/src/Episode3/DataIndex.hh @@ -582,8 +582,8 @@ struct DeckDefinition { } __attribute__((packed)); // 0x84 bytes in total struct PlayerConfig { - // The first offsets in the comments in this struct are relative to start of - // 61/98 command; the second are relative to the start of the + // The first offsets in the comments in this struct are relative to the start + // of the 61/98 command; the second are relative to the start of the // Ep3PlayerDataSegment structure in the reverse-engineering project. // TODO: Fill in the unknown fields here by looking around callsites of // get_player_data_segment @@ -626,6 +626,9 @@ struct PlayerConfig { /* 299C:2120 */ ptext name; /* 29AC:2130 */ parray unknown_a11; /* 2A78:21FC */ + + void decrypt(); + void encrypt(uint8_t basis); } __attribute__((packed)); enum class HPType : uint8_t { diff --git a/src/FunctionCompiler.cc b/src/FunctionCompiler.cc index 86811133..07cba109 100644 --- a/src/FunctionCompiler.cc +++ b/src/FunctionCompiler.cc @@ -40,7 +40,7 @@ const char* name_for_architecture(CompiledFunctionCode::Architecture arch) { -template +template string CompiledFunctionCode::generate_client_command_t( const unordered_map& label_writes, const string& suffix) const { @@ -71,7 +71,7 @@ string CompiledFunctionCode::generate_client_command_t( footer.relocations_offset = w.size(); for (uint16_t delta : this->relocation_deltas) { - w.put(delta); + w.put(delta); } if (this->relocation_deltas.size() & 1) { w.put_u16(0); @@ -85,10 +85,10 @@ string CompiledFunctionCode::generate_client_command( const unordered_map& label_writes, const string& suffix) const { if (this->arch == Architecture::POWERPC) { - return this->generate_client_command_t( + return this->generate_client_command_t( label_writes, suffix); } else if ((this->arch == Architecture::X86) || (this->arch == Architecture::SH4)) { - return this->generate_client_command_t( + return this->generate_client_command_t( label_writes, suffix); } else { throw logic_error("invalid architecture"); diff --git a/src/FunctionCompiler.hh b/src/FunctionCompiler.hh index 1e949b72..b7f94d4c 100644 --- a/src/FunctionCompiler.hh +++ b/src/FunctionCompiler.hh @@ -37,7 +37,7 @@ struct CompiledFunctionCode { bool is_big_endian() const; - template + template std::string generate_client_command_t( const std::unordered_map& label_writes, const std::string& suffix) const; diff --git a/src/GSLArchive.cc b/src/GSLArchive.cc index 06df2e04..abdabcdc 100644 --- a/src/GSLArchive.cc +++ b/src/GSLArchive.cc @@ -10,20 +10,22 @@ using namespace std; -template +template struct GSLHeaderEntry { + using U32T = typename std::conditional::type; + ptext filename; - LongT offset; // In pages, so actual offset is this * 0x800 - LongT size; + U32T offset; // In pages, so actual offset is this * 0x800 + U32T size; uint64_t unused; } __attribute__((packed)); -template +template void GSLArchive::load_t() { StringReader r(*this->data); uint64_t min_data_offset = 0xFFFFFFFFFFFFFFFF; while (r.where() < min_data_offset) { - const auto& entry = r.get>(); + const auto& entry = r.get>(); if (entry.filename.len() == 0) { break; } @@ -38,9 +40,9 @@ void GSLArchive::load_t() { GSLArchive::GSLArchive(shared_ptr data, bool big_endian) : data(data) { if (big_endian) { - this->load_t(); + this->load_t(); } else { - this->load_t(); + this->load_t(); } } diff --git a/src/GSLArchive.hh b/src/GSLArchive.hh index 96c863b4..48453506 100644 --- a/src/GSLArchive.hh +++ b/src/GSLArchive.hh @@ -26,7 +26,7 @@ public: StringReader get_reader(const std::string& name) const; private: - template + template void load_t(); std::shared_ptr data; diff --git a/src/ItemCreator.hh b/src/ItemCreator.hh index 9e9c813c..55eacbc8 100644 --- a/src/ItemCreator.hh +++ b/src/ItemCreator.hh @@ -86,7 +86,7 @@ private: std::shared_ptr tool_random_set; std::shared_ptr weapon_random_set; std::shared_ptr item_parameter_table; - const CommonItemSet::Table* pt; + const CommonItemSet::Table* pt; const RareItemSet::Table* rt; std::shared_ptr restrictions; diff --git a/src/Main.cc b/src/Main.cc index 7d227a23..2d21afdc 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -24,6 +24,7 @@ #include "ProxyServer.hh" #include "PSOGCObjectGraph.hh" #include "ReplaySession.hh" +#include "SaveFileFormats.hh" #include "SendCommands.hh" #include "Server.hh" #include "ServerShell.hh" @@ -124,6 +125,12 @@ The actions are:\n\ trivial algorithm. If SEED is given, it should be specified as one hex\n\ byte. If SEED is not given, newserv will try all possible seeds and return\n\ the one that results in the greatest number of zero bytes in the output.\n\ + encrypt-gci-save CRYPT-OPTION INPUT-FILENAME [OUTPUT-FILENAME]\n\ + decrypt-gci-save CRYPT-OPTION INPUT-FILENAME [OUTPUT-FILENAME]\n\ + Encrypt or decrypt a character or Guild Card file. If encrypting, the\n\ + checksum is also recomputed and stored in the encrypted file. CRYPT-OPTION\n\ + is required; it can be either --sys=SYSTEM-FILENAME or --seed=ROUND1-SEED\n\ + (specified in hex).\n\ find-decryption-seed \n\ Perform a brute-force search for a decryption seed of the given data. The\n\ ciphertext is specified with the --encrypted=DATA option and the expected\n\ @@ -197,6 +204,8 @@ enum class Behavior { ENCRYPT_DATA, DECRYPT_DATA, DECRYPT_TRIVIAL_DATA, + ENCRYPT_GCI_SAVE, + DECRYPT_GCI_SAVE, FIND_DECRYPTION_SEED, DECODE_QUEST_FILE, DECODE_SJIS, @@ -220,6 +229,8 @@ static bool behavior_takes_input_filename(Behavior b) { (b == Behavior::ENCRYPT_DATA) || (b == Behavior::DECRYPT_DATA) || (b == Behavior::DECRYPT_TRIVIAL_DATA) || + (b == Behavior::DECRYPT_GCI_SAVE) || + (b == Behavior::ENCRYPT_GCI_SAVE) || (b == Behavior::DECODE_QUEST_FILE) || (b == Behavior::DECODE_SJIS) || (b == Behavior::FORMAT_ITEMRT_ENTRY) || @@ -239,6 +250,8 @@ static bool behavior_takes_output_filename(Behavior b) { (b == Behavior::ENCRYPT_DATA) || (b == Behavior::DECRYPT_DATA) || (b == Behavior::DECRYPT_TRIVIAL_DATA) || + (b == Behavior::DECRYPT_GCI_SAVE) || + (b == Behavior::ENCRYPT_GCI_SAVE) || (b == Behavior::DECODE_SJIS) || (b == Behavior::EXTRACT_GSL) || (b == Behavior::EXTRACT_BML); @@ -267,6 +280,7 @@ int main(int argc, char** argv) { vector find_decryption_seed_plaintexts; const char* input_filename = nullptr; const char* output_filename = nullptr; + const char* system_filename = nullptr; const char* replay_required_access_key = ""; const char* replay_required_password = ""; uint32_t root_object_address = 0; @@ -291,6 +305,8 @@ int main(int argc, char** argv) { cli_version = GameVersion::BB; } else if (!strncmp(argv[x], "--seed=", 7)) { seed = &argv[x][7]; + } else if (!strncmp(argv[x], "--sys=", 6)) { + system_filename = &argv[x][6]; } else if (!strncmp(argv[x], "--key=", 6)) { key_file_name = &argv[x][6]; } else if (!strncmp(argv[x], "--encrypted=", 12)) { @@ -337,6 +353,10 @@ int main(int argc, char** argv) { behavior = Behavior::DECRYPT_DATA; } else if (!strcmp(argv[x], "decrypt-trivial-data")) { behavior = Behavior::DECRYPT_TRIVIAL_DATA; + } else if (!strcmp(argv[x], "decrypt-gci-save")) { + behavior = Behavior::DECRYPT_GCI_SAVE; + } else if (!strcmp(argv[x], "encrypt-gci-save")) { + behavior = Behavior::ENCRYPT_GCI_SAVE; } else if (!strcmp(argv[x], "find-decryption-seed")) { behavior = Behavior::FIND_DECRYPTION_SEED; } else if (!strcmp(argv[x], "decode-sjis")) { @@ -408,13 +428,29 @@ int main(int argc, char** argv) { } else if (!output_filename && input_filename && strcmp(input_filename, "-")) { string filename = input_filename; if (behavior == Behavior::COMPRESS_PRS) { - if (ends_with(filename, ".bind") || ends_with(filename, ".datd") || ends_with(filename, ".mnmd")) { + if (ends_with(filename, ".bind") || + ends_with(filename, ".datd") || + ends_with(filename, ".mnmd")) { filename.resize(filename.size() - 1); } else { filename += ".prs"; } } else if (behavior == Behavior::DECOMPRESS_PRS) { - if (ends_with(filename, ".bin") || ends_with(filename, ".dat") || ends_with(filename, ".mnm")) { + if (ends_with(filename, ".bin") || + ends_with(filename, ".dat") || + ends_with(filename, ".mnm")) { + filename += "d"; + } else { + filename += ".dec"; + } + } else if (behavior == Behavior::ENCRYPT_GCI_SAVE) { + if (ends_with(filename, ".gcid")) { + filename.resize(filename.size() - 1); + } else { + filename += ".gci"; + } + } else if (behavior == Behavior::DECRYPT_GCI_SAVE) { + if (ends_with(filename, ".gci")) { filename += "d"; } else { filename += ".dec"; @@ -575,6 +611,76 @@ int main(int argc, char** argv) { break; } + case Behavior::ENCRYPT_GCI_SAVE: + case Behavior::DECRYPT_GCI_SAVE: { + uint32_t round1_seed; + if (system_filename) { + string system_data = load_file(system_filename); + StringReader r(system_data); + const auto& header = r.get(); + header.check(); + const auto& system = r.get(); + round1_seed = system.creation_internet_time; + } else if (!seed.empty()) { + round1_seed = stoul(seed, nullptr, 16); + } else { + // TODO: We can support brute-forcing character file encryption, but I'm + // lazy and this would probably not be useful for anyone. + throw runtime_error("either --sys or --seed must be given"); + } + + bool is_decrypt = (behavior == Behavior::DECRYPT_GCI_SAVE); + + auto data = read_input_data(); + StringReader r(data); + const auto& header = r.get(); + header.check(); + + size_t data_start_offset = r.where(); + + auto process_file = [&]() { + if (is_decrypt) { + const void* data_section = r.getv(header.data_size); + auto decrypted = decrypt_gci_fixed_size_file_data_section( + data_section, header.data_size, round1_seed); + *reinterpret_cast(data.data() + data_start_offset) = decrypted; + } else { + const auto& s = r.get(); + auto encrypted = encrypt_gci_fixed_size_file_data_section( + s, round1_seed); + if (data_start_offset + encrypted.size() > data.size()) { + throw runtime_error("encrypted result exceeds file size"); + } + memcpy(data.data() + data_start_offset, encrypted.data(), encrypted.size()); + } + }; + + if (header.data_size == sizeof(PSOGCGuildCardFile)) { + process_file.template operator()(); + } else if (header.is_ep12() && (header.data_size == sizeof(PSOGCCharacterFile))) { + process_file.template operator()(); + } else if (header.is_ep3() && (header.data_size == sizeof(PSOGCEp3CharacterFile))) { + auto* charfile = reinterpret_cast(data.data() + data_start_offset); + if (!is_decrypt) { + for (size_t z = 0; z < charfile->characters.size(); z++) { + charfile->characters[z].ep3_config.encrypt(random_object()); + } + } + process_file.template operator()(); + if (is_decrypt) { + for (size_t z = 0; z < charfile->characters.size(); z++) { + charfile->characters[z].ep3_config.decrypt(); + } + } + } else { + throw runtime_error("unrecognized save type"); + } + + write_output_data(data.data(), data.size()); + + break; + } + case Behavior::FIND_DECRYPTION_SEED: { if (find_decryption_seed_plaintexts.empty() || !find_decryption_seed_ciphertext) { throw runtime_error("both --encrypted and --decrypted must be specified"); diff --git a/src/Map.cc b/src/Map.cc index a9deb000..e2a1bbc4 100644 --- a/src/Map.cc +++ b/src/Map.cc @@ -461,14 +461,16 @@ vector parse_map( SetDataTable::SetDataTable(shared_ptr data, bool big_endian) { if (big_endian) { - this->load_table_t(data); + this->load_table_t(data); } else { - this->load_table_t(data); + this->load_table_t(data); } } -template +template void SetDataTable::load_table_t(shared_ptr data) { + using U32T = typename conditional::type; + StringReader r(*data); struct Footer { diff --git a/src/Map.hh b/src/Map.hh index 8dcfbeb9..7cbf4183 100644 --- a/src/Map.hh +++ b/src/Map.hh @@ -113,7 +113,7 @@ public: void print(FILE* stream) const; private: - template + template void load_table_t(std::shared_ptr data); // Indexes are [area_id][variation1][variation2] diff --git a/src/PSOEncryption.cc b/src/PSOEncryption.cc index fd1ace08..40ae54bc 100644 --- a/src/PSOEncryption.cc +++ b/src/PSOEncryption.cc @@ -38,8 +38,10 @@ uint32_t PSOLFGEncryption::next(bool advance) { return ret; } -template +template void PSOLFGEncryption::encrypt_t(void* vdata, size_t size, bool advance) { + using U32T = typename std::conditional::type; + if (size & 3) { throw invalid_argument("size must be a multiple of 4"); } @@ -48,18 +50,44 @@ void PSOLFGEncryption::encrypt_t(void* vdata, size_t size, bool advance) { } size >>= 2; - LongT* data = reinterpret_cast(vdata); + U32T* data = reinterpret_cast(vdata); for (size_t x = 0; x < size; x++) { data[x] ^= this->next(advance); } } +template +void PSOLFGEncryption::encrypt_minus_t(void* vdata, size_t size, bool advance) { + using U32T = typename std::conditional::type; + + if (size & 3) { + throw invalid_argument("size must be a multiple of 4"); + } + if (!advance && (size != 4)) { + throw logic_error("cannot peek-encrypt/decrypt with size > 4"); + } + size >>= 2; + + U32T* data = reinterpret_cast(vdata); + for (size_t x = 0; x < size; x++) { + data[x] = this->next(advance) - data[x]; + } +} + void PSOLFGEncryption::encrypt(void* vdata, size_t size, bool advance) { - this->encrypt_t(vdata, size, advance); + this->encrypt_t(vdata, size, advance); } void PSOLFGEncryption::encrypt_big_endian(void* vdata, size_t size, bool advance) { - this->encrypt_t(vdata, size, advance); + this->encrypt_t(vdata, size, advance); +} + +void PSOLFGEncryption::encrypt_minus(void* vdata, size_t size, bool advance) { + this->encrypt_minus_t(vdata, size, advance); +} + +void PSOLFGEncryption::encrypt_big_endian_minus(void* vdata, size_t size, bool advance) { + this->encrypt_minus_t(vdata, size, advance); } void PSOLFGEncryption::encrypt_both_endian( diff --git a/src/PSOEncryption.hh b/src/PSOEncryption.hh index c0a63f23..3c85376c 100644 --- a/src/PSOEncryption.hh +++ b/src/PSOEncryption.hh @@ -45,16 +45,20 @@ class PSOLFGEncryption : public PSOEncryption { public: virtual void encrypt(void* data, size_t size, bool advance = true); void encrypt_big_endian(void* data, size_t size, bool advance = true); + void encrypt_minus(void* data, size_t size, bool advance = true); + void encrypt_big_endian_minus(void* data, size_t size, bool advance = true); void encrypt_both_endian(void* le_data, void* be_data, size_t size, bool advance = true); + template + void encrypt_t(void* data, size_t size, bool advance = true); + template + void encrypt_minus_t(void* data, size_t size, bool advance = true); + uint32_t next(bool advance = true); protected: explicit PSOLFGEncryption(uint32_t seed, size_t stream_length, size_t end_offset); - template - void encrypt_t(void* data, size_t size, bool advance); - virtual void update_stream() = 0; std::vector stream; diff --git a/src/Player.hh b/src/Player.hh index a415a337..c572ba05 100644 --- a/src/Player.hh +++ b/src/Player.hh @@ -204,14 +204,15 @@ struct PlayerDispDataBB { // TODO: Is this the same for XB as it is for GC? (This struct is based on the // GC format) struct GuildCardV3 { - le_uint32_t player_tag; - le_uint32_t guild_card_number; - ptext name; - ptext description; - uint8_t present; // should be 1 - uint8_t language; - uint8_t section_id; - uint8_t char_class; + /* 00 */ le_uint32_t player_tag; + /* 04 */ le_uint32_t guild_card_number; + /* 08 */ ptext name; + /* 20 */ ptext description; + /* 8C */ uint8_t present; // should be 1 + /* 8D */ uint8_t language; + /* 8E */ uint8_t section_id; + /* 8F */ uint8_t char_class; + /* 90 */ GuildCardV3() noexcept; } __attribute__((packed)); diff --git a/src/Quest.cc b/src/Quest.cc index 5cf0cd9a..6ac2d65e 100644 --- a/src/Quest.cc +++ b/src/Quest.cc @@ -12,6 +12,7 @@ #include #include "Loggers.hh" +#include "SaveFileFormats.hh" #include "CommandFormats.hh" #include "Compression.hh" #include "PSOEncryption.hh" @@ -23,81 +24,10 @@ using namespace std; // GCI decoding logic -struct ShuffleTables { - uint8_t forward_table[0x100]; - uint8_t reverse_table[0x100]; +template +struct PSOMemCardDLQFileEncryptedHeader { + using U32T = typename std::conditional::type; - ShuffleTables(PSOV2Encryption& crypt) { - for (size_t x = 0; x < 0x100; x++) { - this->forward_table[x] = x; - } - - int32_t r28 = 0xFF; - uint8_t* r31 = &this->forward_table[0xFF]; - while (r28 >= 0) { - uint32_t r3 = this->pseudorand(crypt, r28 + 1); - if (r3 >= 0x100) { - throw logic_error("bad r3"); - } - uint8_t t = this->forward_table[r3]; - this->forward_table[r3] = *r31; - *r31 = t; - - this->reverse_table[t] = r28; - r31--; - r28--; - } - } - - static uint32_t pseudorand(PSOV2Encryption& crypt, uint32_t prev) { - return (((prev & 0xFFFF) * ((crypt.next() >> 16) & 0xFFFF)) >> 16) & 0xFFFF; - } - - void shuffle(void* vdest, const void* vsrc, size_t size, bool reverse) { - uint8_t* dest = reinterpret_cast(vdest); - const uint8_t* src = reinterpret_cast(vsrc); - const uint8_t* table = reverse ? this->reverse_table : this->forward_table; - - for (size_t block_offset = 0; block_offset < (size & 0xFFFFFF00); block_offset += 0x100) { - for (size_t z = 0; z < 0x100; z++) { - dest[block_offset + table[z]] = src[block_offset + z]; - } - } - - // Any remaining bytes that don't fill an entire block are not shuffled - memcpy(&dest[size & 0xFFFFFF00], &src[size & 0xFFFFFF00], size & 0xFF); - } -}; - -struct PSOGCIFileHeader { - parray game_id; // 'GPOE', 'GPSP', etc. - parray developer_id; // '8P' for Sega - parray remaining_gci_header; // There is a structure for this but we don't use it - ptext game_name; // e.g. "PSO EPISODE I & II" or "PSO EPISODE III" - be_uint32_t embedded_seed; // Used in some of Ralf's quest packs - ptext quest_name; - parray banner_and_icon; - // data_size specifies the number of bytes in the encrypted section, including - // the encrypted header (below) and all encrypted data after it. - be_uint32_t data_size; - // To compute checksum, set checksum to zero, then compute the CRC32 of all - // fields in this struct starting with game_name. (Yes, including the checksum - // field, which is temporarily zero.) - be_uint32_t checksum; - - bool checksum_correct() const { - uint32_t cs = crc32(&this->game_name, sizeof(this->game_name)); - cs = crc32(&this->embedded_seed, sizeof(this->embedded_seed), cs); - cs = crc32(&this->quest_name, sizeof(this->quest_name), cs); - cs = crc32(&this->banner_and_icon, sizeof(this->banner_and_icon), cs); - cs = crc32(&this->data_size, sizeof(this->data_size), cs); - cs = crc32("\0\0\0\0", 4, cs); - return (cs == this->checksum); - } -} __attribute__((packed)); - -template -struct PSOMemCardFileEncryptedHeader { U32T round2_seed; // To compute checksum, set checksum to zero, then compute the CRC32 of the // entire data section, including this header struct (but not the unencrypted @@ -108,50 +38,27 @@ struct PSOMemCardFileEncryptedHeader { // Data follows here. } __attribute__((packed)); -struct PSOVMSFileEncryptedHeader : PSOMemCardFileEncryptedHeader { } __attribute__((packed)); -struct PSOGCIFileEncryptedHeader : PSOMemCardFileEncryptedHeader { } __attribute__((packed)); +struct PSOVMSDLQFileEncryptedHeader : PSOMemCardDLQFileEncryptedHeader { } __attribute__((packed)); +struct PSOGCIDLQFileEncryptedHeader : PSOMemCardDLQFileEncryptedHeader { } __attribute__((packed)); template -string decrypt_gci_or_vms_v2_data_section( +string decrypt_gci_or_vms_v2_download_quest_data_section( const void* data_section, size_t size, uint32_t seed) { - - string decrypted(size, '\0'); - { - PSOV2Encryption shuf_crypt(seed); - ShuffleTables shuf(shuf_crypt); - shuf.shuffle(decrypted.data(), data_section, size, true); - } + string decrypted = decrypt_gci_or_vms_v2_data_section( + data_section, size, seed); size_t orig_size = decrypted.size(); decrypted.resize((decrypted.size() + 3) & (~3)); - PSOV2Encryption crypt(seed); - if (IsBigEndian) { - auto* be_dwords = reinterpret_cast(decrypted.data()); - for (size_t z = 0; z < decrypted.size() / sizeof(be_uint32_t); z++) { - be_dwords[z] = crypt.next() - be_dwords[z]; - } - } else { - auto* le_dwords = reinterpret_cast(decrypted.data()); - for (size_t z = 0; z < decrypted.size() / sizeof(le_uint32_t); z++) { - le_dwords[z] = crypt.next() - le_dwords[z]; - } - } - // Note: Other PSO save files have the round 2 seed at the end of the data, // not at the beginning. Presumably they did this because the system, // character, and Guild Card files are a constant size, but download quest // files can vary in size. - using HeaderT = typename conditional, PSOMemCardFileEncryptedHeader>::type; + using HeaderT = PSOMemCardDLQFileEncryptedHeader; auto* header = reinterpret_cast(decrypted.data()); PSOV2Encryption round2_crypt(header->round2_seed); - if (IsBigEndian) { - round2_crypt.encrypt_big_endian( - decrypted.data() + 4, (decrypted.size() - 4)); - } else { - round2_crypt.decrypt( - decrypted.data() + 4, (decrypted.size() - 4)); - } + round2_crypt.encrypt_t( + decrypted.data() + 4, (decrypted.size() - 4)); if (header->decompressed_size & 0xFFF00000) { throw runtime_error(string_printf( @@ -168,14 +75,17 @@ string decrypt_gci_or_vms_v2_data_section( expected_crc, actual_crc)); } + // Unlike the above rounds, round 3 is always little-endian (it corresponds to + // the round of encryption done on the server before sending the file to the + // client in the first place) PSOV2Encryption(header->round3_seed).decrypt( decrypted.data() + sizeof(HeaderT), decrypted.size() - sizeof(HeaderT)); decrypted.resize(orig_size); - // Some GCI files have decompressed_size fields that are 8 bytes smaller than - // the actual decompressed size of the data. They seem to work fine, so we - // accept both cases as correct. + // Some download quest GCI files have decompressed_size fields that are 8 + // bytes smaller than the actual decompressed size of the data. They seem to + // work fine, so we accept both cases as correct. size_t decompressed_size = prs_decompress_size( decrypted.data() + sizeof(HeaderT), decrypted.size() - sizeof(HeaderT)); @@ -212,13 +122,13 @@ string decrypt_vms_v1_data_section(const void* data_section, size_t size) { } template -string find_seed_and_decrypt_gci_or_vms_v2_data_section( +string find_seed_and_decrypt_gci_or_vms_v2_download_quest_data_section( const void* data_section, size_t size, size_t num_threads) { mutex result_lock; string result; uint64_t result_seed = parallel_range([&](uint64_t seed, size_t) { try { - string ret = decrypt_gci_or_vms_v2_data_section( + string ret = decrypt_gci_or_vms_v2_download_quest_data_section( data_section, size, seed); lock_guard g(result_lock); result = move(ret); @@ -703,32 +613,20 @@ string Quest::decode_gci( StringReader r(data); const auto& header = r.get(); - if (!header.checksum_correct()) { - throw runtime_error("GCI file unencrypted header checksum is incorrect"); - } + header.check(); - if (header.developer_id[0] != '8' || header.developer_id[1] != 'P') { - throw runtime_error("GCI file is not for a Sega game"); - } - if (header.game_id[0] != 'G') { - throw runtime_error("GCI file is not for a GameCube game"); - } - if (header.game_id[1] != 'P') { - throw runtime_error("GCI file is not for Phantasy Star Online"); - } - - if (header.game_id[2] == 'O') { // Episodes 1&2 (GPO*) - const auto& encrypted_header = r.get(false); + if (header.is_ep12()) { + const auto& dlq_header = r.get(false); // Unencrypted GCI files appear to always have zeroes in these fields. // Encrypted GCI files are highly unlikely to have zeroes in ALL of these // fields, so assume it's encrypted if any of them are nonzero. - if (encrypted_header.round2_seed || encrypted_header.checksum || encrypted_header.round3_seed) { + if (dlq_header.round2_seed || dlq_header.checksum || dlq_header.round3_seed) { if (known_seed >= 0) { - return decrypt_gci_or_vms_v2_data_section( + return decrypt_gci_or_vms_v2_download_quest_data_section( r.getv(header.data_size), header.data_size, known_seed); } else if (header.embedded_seed != 0) { - return decrypt_gci_or_vms_v2_data_section( + return decrypt_gci_or_vms_v2_download_quest_data_section( r.getv(header.data_size), header.data_size, header.embedded_seed); } else { @@ -738,16 +636,16 @@ string Quest::decode_gci( if (find_seed_num_threads == 0) { find_seed_num_threads = thread::hardware_concurrency(); } - return find_seed_and_decrypt_gci_or_vms_v2_data_section( + return find_seed_and_decrypt_gci_or_vms_v2_download_quest_data_section( r.getv(header.data_size), header.data_size, find_seed_num_threads); } } else { // Unencrypted GCI format - r.skip(sizeof(PSOGCIFileEncryptedHeader)); - string compressed_data = r.readx(header.data_size - sizeof(PSOGCIFileEncryptedHeader)); + r.skip(sizeof(PSOGCIDLQFileEncryptedHeader)); + string compressed_data = r.readx(header.data_size - sizeof(PSOGCIDLQFileEncryptedHeader)); size_t decompressed_bytes = prs_decompress_size(compressed_data); - size_t expected_decompressed_bytes = encrypted_header.decompressed_size - 8; + size_t expected_decompressed_bytes = dlq_header.decompressed_size - 8; if (decompressed_bytes < expected_decompressed_bytes) { throw runtime_error(string_printf( "GCI decompressed data is smaller than expected size (have 0x%zX bytes, expected 0x%zX bytes)", @@ -810,7 +708,7 @@ string Quest::decode_vms( } catch (const exception& e) { } if (known_seed >= 0) { - return decrypt_gci_or_vms_v2_data_section( + return decrypt_gci_or_vms_v2_download_quest_data_section( data_section, header.data_size, known_seed); } else { @@ -820,7 +718,7 @@ string Quest::decode_vms( if (find_seed_num_threads == 0) { find_seed_num_threads = thread::hardware_concurrency(); } - return find_seed_and_decrypt_gci_or_vms_v2_data_section( + return find_seed_and_decrypt_gci_or_vms_v2_download_quest_data_section( data_section, header.data_size, find_seed_num_threads); } } diff --git a/src/SaveFileFormats.cc b/src/SaveFileFormats.cc new file mode 100644 index 00000000..45b0620f --- /dev/null +++ b/src/SaveFileFormats.cc @@ -0,0 +1,89 @@ +#include "SaveFileFormats.hh" + +#include +#include + +using namespace std; + + + +ShuffleTables::ShuffleTables(PSOV2Encryption& crypt) { + for (size_t x = 0; x < 0x100; x++) { + this->forward_table[x] = x; + } + + int32_t r28 = 0xFF; + uint8_t* r31 = &this->forward_table[0xFF]; + while (r28 >= 0) { + uint32_t r3 = this->pseudorand(crypt, r28 + 1); + if (r3 >= 0x100) { + throw logic_error("bad r3"); + } + uint8_t t = this->forward_table[r3]; + this->forward_table[r3] = *r31; + *r31 = t; + + this->reverse_table[t] = r28; + r31--; + r28--; + } +} + +uint32_t ShuffleTables::pseudorand(PSOV2Encryption& crypt, uint32_t prev) { + return (((prev & 0xFFFF) * ((crypt.next() >> 16) & 0xFFFF)) >> 16) & 0xFFFF; +} + +void ShuffleTables::shuffle(void* vdest, const void* vsrc, size_t size, bool reverse) const { + uint8_t* dest = reinterpret_cast(vdest); + const uint8_t* src = reinterpret_cast(vsrc); + const uint8_t* table = reverse ? this->reverse_table : this->forward_table; + + for (size_t block_offset = 0; block_offset < (size & 0xFFFFFF00); block_offset += 0x100) { + for (size_t z = 0; z < 0x100; z++) { + dest[block_offset + table[z]] = src[block_offset + z]; + } + } + + // Any remaining bytes that don't fill an entire block are not shuffled + memcpy(&dest[size & 0xFFFFFF00], &src[size & 0xFFFFFF00], size & 0xFF); +} + + + +bool PSOGCIFileHeader::checksum_correct() const { + uint32_t cs = crc32(&this->game_name, this->game_name.bytes()); + cs = crc32(&this->embedded_seed, sizeof(this->embedded_seed), cs); + cs = crc32(&this->file_name, this->file_name.bytes(), cs); + cs = crc32(&this->banner, this->banner.bytes(), cs); + cs = crc32(&this->icon, this->icon.bytes(), cs); + cs = crc32(&this->data_size, sizeof(this->data_size), cs); + cs = crc32("\0\0\0\0", 4, cs); // this->checksum (treated as zero) + return (cs == this->checksum); +} + +void PSOGCIFileHeader::check() const { + if (!this->checksum_correct()) { + throw runtime_error("GCI file unencrypted header checksum is incorrect"); + } + if (this->developer_id[0] != '8' || this->developer_id[1] != 'P') { + throw runtime_error("GCI file is not for a Sega game"); + } + if (this->game_id[0] != 'G') { + throw runtime_error("GCI file is not for a GameCube game"); + } + if (this->game_id[1] != 'P') { + throw runtime_error("GCI file is not for Phantasy Star Online"); + } + if ((this->game_id[1] != 'P') || + ((this->game_id[2] != 'S') && (this->game_id[2] != 'O'))) { + throw runtime_error("GCI file is not for Phantasy Star Online"); + } +} + +bool PSOGCIFileHeader::is_ep12() const { + return (this->game_id[2] == 'O'); +} + +bool PSOGCIFileHeader::is_ep3() const { + return (this->game_id[2] == 'S'); +} diff --git a/src/SaveFileFormats.hh b/src/SaveFileFormats.hh new file mode 100644 index 00000000..0c42b11c --- /dev/null +++ b/src/SaveFileFormats.hh @@ -0,0 +1,229 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include "PSOEncryption.hh" +#include "Text.hh" +#include "Player.hh" + + + +struct ShuffleTables { + uint8_t forward_table[0x100]; + uint8_t reverse_table[0x100]; + + ShuffleTables(PSOV2Encryption& crypt); + + static uint32_t pseudorand(PSOV2Encryption& crypt, uint32_t prev); + + void shuffle(void* vdest, const void* vsrc, size_t size, bool reverse) const; +}; + + + +struct PSOGCIFileHeader { + /* 0000 */ parray game_id; // 'GPOE', 'GPSP', etc. + /* 0004 */ parray developer_id; // '8P' for Sega + // There is a structure for this part of the header, but we don't use it + /* 0006 */ parray remaining_gci_header; + // game_name is e.g. "PSO EPISODE I & II" or "PSO EPISODE III" + /* 0040 */ ptext game_name; + /* 005C */ be_uint32_t embedded_seed; // Used in some of Ralf's quest packs + /* 0060 */ ptext file_name; + /* 0080 */ parray banner; + /* 1880 */ parray icon; + // data_size specifies the number of bytes remaining in the file. In all cases + // except for the system file, this data is encrypted. + /* 2080 */ be_uint32_t data_size; + // To compute checksum, set checksum to zero, then compute the CRC32 of all + // fields in this struct starting with gci_header.game_name. (Yes, including + // the checksum field, which is temporarily zero.) See checksum_correct below. + /* 2084 */ be_uint32_t checksum; + + bool checksum_correct() const; + void check() const; + + bool is_ep12() const; + bool is_ep3() const; +} __attribute__((packed)); + +struct PSOGCSystemFile { + /* 0000 */ be_uint32_t checksum; + /* 0004 */ be_uint16_t unknown_a1; + /* 0006 */ uint8_t unknown_a2; + /* 0007 */ uint8_t language; + /* 0008 */ be_uint32_t unknown_a3; + /* 000C */ be_uint16_t unknown_a4; + /* 000E */ be_uint16_t unknown_a5; + /* 0010 */ parray unknown_a6; + /* 0110 */ parray unknown_a7; + /* 0118 */ be_uint32_t creation_internet_time; // Character file round1 seed + /* 011C */ +} __attribute__((packed)); + +struct PSOGCEp3SystemFile { + /* 0000 */ PSOGCSystemFile base; + /* 011C */ int8_t unknown_a1; + /* 011D */ parray unknown_a2; + /* 0128 */ be_uint32_t unknown_a3; + /* 012C */ +} __attribute__((packed)); + +struct PSOGCCharacterFile { + /* 00000 */ be_uint32_t checksum; + /* 00004 */ parray unknown_a1; // TODO + /* 11568 */ be_uint32_t round2_seed; + /* 1156C */ +} __attribute__((packed)); + +struct PSOGCEp3CharacterFile { + /* 00000 */ be_uint32_t checksum; // crc32 of this field (as 0) through end of struct + struct Character { + /* 0000 */ PlayerInventory inventory; + /* 034C */ PlayerDispDataDCPCV3 disp; + /* 041C */ be_uint32_t unknown_a1; + /* 0420 */ be_uint32_t save_token; // Sent in 96 command + /* 0424 */ parray unknown_a2; + /* 0430 */ be_uint32_t save_count; // Sent in 96 command + /* 0434 */ parray unknown_a3; + /* 08CC */ GuildCardV3 guild_card; + struct SymbolChatEntry { + /* 00 */ be_uint32_t present; + /* 04 */ ptext name; + /* 1C */ be_uint16_t unused; + /* 1E */ uint8_t flags; + /* 1F */ uint8_t face_spec; + struct CornerObject { + uint8_t type; + uint8_t flags_color; + } __attribute__((packed)); + /* 20 */ parray corner_objects; + struct FacePart { + uint8_t type; + uint8_t x; + uint8_t y; + uint8_t flags; + } __attribute__((packed)); + /* 28 */ parray face_parts; + /* 58 */ + } __attribute__((packed)); + /* 095C */ parray symbol_chats; + struct ChatShortcut { + /* 00 */ be_uint32_t present_type; + /* 04 */ parray definition; + /* 54 */ + } __attribute__((packed)); + /* 0D7C */ parray chat_shortcuts; + /* 140C */ parray unknown_a4; + /* 14B8 */ ptext info_board; + /* 1564 */ parray unknown_a5; + /* 1658 */ Episode3::PlayerConfig ep3_config; + /* 39A8 */ be_uint32_t unknown_a7; + /* 39AC */ be_uint32_t unknown_a8; + /* 39B0 */ be_uint32_t unknown_a9; + /* 39B4 */ + } __attribute__((packed)); + /* 00004 */ parray characters; + /* 193F0 */ ptext serial_number; // As %08X (not decimal) + /* 19400 */ ptext access_key; + /* 19410 */ ptext password; + /* 19420 */ be_uint32_t unknown_a1; + /* 19424 */ be_uint32_t unknown_a2; + /* 19428 */ be_uint32_t unknown_a3; + /* 1942C */ parray unknown_a4; + /* 194AC */ be_uint32_t round2_seed; + /* 194B0 */ +} __attribute__((packed)); + +struct PSOGCGuildCardFile { + /* 0000 */ be_uint32_t checksum; + /* 0004 */ parray unknown_a1; + /* E288 */ be_uint32_t round2_seed; + /* E28C */ +} __attribute__((packed)); + + + +template +std::string decrypt_gci_or_vms_v2_data_section( + const void* data_section, size_t size, uint32_t round1_seed) { + + std::string decrypted(size, '\0'); + PSOV2Encryption shuf_crypt(round1_seed); + ShuffleTables shuf(shuf_crypt); + shuf.shuffle(decrypted.data(), data_section, size, true); + + size_t orig_size = decrypted.size(); + decrypted.resize((decrypted.size() + 3) & (~3)); + + PSOV2Encryption round1_crypt(round1_seed); + round1_crypt.encrypt_minus_t(decrypted.data(), decrypted.size()); + + decrypted.resize(orig_size); + return decrypted; +} + +template +std::string encrypt_gci_or_vms_v2_data_section( + const void* data_section, size_t size, uint32_t round1_seed) { + std::string encrypted(reinterpret_cast(data_section), size); + encrypted.resize((encrypted.size() + 3) & (~3)); + + PSOV2Encryption crypt(round1_seed); + crypt.encrypt_minus_t(encrypted.data(), encrypted.size()); + + std::string ret(size, '\0'); + PSOV2Encryption shuf_crypt(round1_seed); + ShuffleTables shuf(shuf_crypt); + shuf.shuffle(ret.data(), encrypted.data(), size, false); + + return ret; +} + +template +StructT decrypt_gci_fixed_size_file_data_section( + const void* data_section, size_t size, uint32_t round1_seed) { + std::string decrypted = decrypt_gci_or_vms_v2_data_section( + data_section, size, round1_seed); + + if (decrypted.size() < sizeof(StructT)) { + throw std::runtime_error("file too small for structure"); + } + StructT ret = *reinterpret_cast(decrypted.data()); + + PSOV2Encryption round2_crypt(ret.round2_seed); + round2_crypt.encrypt_big_endian(&ret, offsetof(StructT, round2_seed)); + + uint32_t expected_crc = ret.checksum; + ret.checksum = 0; + uint32_t actual_crc = crc32(&ret, sizeof(ret)); + ret.checksum = expected_crc; + if (expected_crc != actual_crc) { + throw std::runtime_error(string_printf( + "incorrect decrypted data section checksum: expected %08" PRIX32 "; received %08" PRIX32, + expected_crc, actual_crc)); + } + + return ret; +} + +template +std::string encrypt_gci_fixed_size_file_data_section( + const StructT& s, uint32_t round1_seed) { + StructT encrypted = s; + encrypted.checksum = 0; + encrypted.round2_seed = random_object(); + encrypted.checksum = crc32(&encrypted, sizeof(encrypted)); + + PSOV2Encryption round2_crypt(encrypted.round2_seed); + round2_crypt.encrypt_big_endian(&encrypted, offsetof(StructT, round2_seed)); + + return encrypt_gci_or_vms_v2_data_section( + &encrypted, sizeof(StructT), round1_seed); +} diff --git a/test-decode-gci.sh b/test-decode-gci.sh new file mode 100755 index 00000000..16ca7035 --- /dev/null +++ b/test-decode-gci.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +set -e + +EXECUTABLE="$1" +if [ "$EXECUTABLE" == "" ]; then + EXECUTABLE="./newserv" +fi + +echo "... decode GCIEpisode3.gci" +$EXECUTABLE decode-gci tests/GCIEpisode3.gci +diff tests/GCIEpisode3.dec tests/GCIEpisode3.gci.dec +echo "... decode GCIWithoutEncryption.gci" +$EXECUTABLE decode-gci tests/GCIWithoutEncryption.gci +diff tests/GCIWithoutEncryption.dec tests/GCIWithoutEncryption.gci.dec +echo "... decode GCIWithEmbeddedKey.gci" +$EXECUTABLE decode-gci tests/GCIWithEmbeddedKey.gci +diff tests/GCIWithEmbeddedKey.dec tests/GCIWithEmbeddedKey.gci.dec +echo "... decode GCIWithoutEmbeddedKey.gci" +$EXECUTABLE decode-gci tests/GCIWithoutEmbeddedKey.gci --seed=1705B11E +diff tests/GCIWithoutEmbeddedKey.dec tests/GCIWithoutEmbeddedKey.gci.dec + +echo "... re-encrypt GCICharFile.gci" +./newserv encrypt-gci-save --sys=tests/GCISystemFile.gci tests/GCICharFile.gcid tests/GCICharFile.gci +./newserv decrypt-gci-save --sys=tests/GCISystemFile.gci tests/GCICharFile.gci tests/GCICharFile-redec.gcid +hexdump -vC tests/GCICharFile.gcid > tests/GCICharFile.gcid.hex +hexdump -vC tests/GCICharFile-redec.gcid > tests/GCICharFile-redec.gcid.hex +# There should be differences on two lines: the checksum and the round2 seed +NUM_DIFF_LINES=$(diff -y --suppress-common-lines tests/GCICharFile.gcid.hex tests/GCICharFile-redec.gcid.hex | wc -l) +if [[ $NUM_DIFF_LINES -ne 2 ]]; then + diff -U3 tests/GCICharFile.gcid.hex tests/GCICharFile-redec.gcid.hex + exit 1 +fi + +echo "... clean up" +rm tests/*.gci.dec tests/GCICharFile.gci tests/GCICharFile-redec.gcid tests/*.hex diff --git a/test-decode-vms.sh b/test-decode-vms.sh new file mode 100755 index 00000000..b371abbe --- /dev/null +++ b/test-decode-vms.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +EXECUTABLE="$1" +if [ "$EXECUTABLE" == "" ]; then + EXECUTABLE="./newserv" +fi + +echo "... decode LionelV1.vms" +$EXECUTABLE decode-vms tests/LionelV1.vms +diff tests/LionelV1.dec tests/LionelV1.vms.dec +echo "... decode LionelV2.vms" +$EXECUTABLE decode-vms tests/LionelV2.vms --seed=D0231610 +diff tests/LionelV2.dec tests/LionelV2.vms.dec + +echo "... clean up" +rm tests/*.vms.dec diff --git a/tests/GCICharFile.gcid b/tests/GCICharFile.gcid new file mode 100755 index 0000000000000000000000000000000000000000..df574b60aaa413e1a0d96db6e43d2fceba290747 GIT binary patch literal 122944 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 Yi6kMYVPC1VEU2_c^9q?3F3D;9Pr$_|-v9sr literal 0 HcmV?d00001 diff --git a/tests/GCIEpisode3.gci b/tests/GCIEpisode3.gci new file mode 100644 index 0000000000000000000000000000000000000000..1b11dd3be6093039b004a385177f13e24db51d61 GIT binary patch literal 24640 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 literal 0 HcmV?d00001 diff --git a/tests/GCIWIthoutEncryption.gci b/tests/GCIWIthoutEncryption.gci new file mode 100644 index 0000000000000000000000000000000000000000..136998a2c59941e4ffdf202eeadee495dd4b75b1 GIT binary patch literal 24640 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 E4_|B57ytkO literal 0 HcmV?d00001 diff --git a/tests/GCIWithEmbeddedKey.dec b/tests/GCIWithEmbeddedKey.dec new file mode 100755 index 0000000000000000000000000000000000000000..3d2b23dc5827ec1b2248d8224d3efe8af7e2d3c1 GIT binary patch literal 5740 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 Hxdr|U`MsO2VNgVnES#6>1q^ASod;Btc}0H6ksD zu+aKjuT=}uf{JI?BE|y*LGj{LKoF8ekt2Z+j+unX{Fi=t*T?rhyudaV1l@LarisP0 z003qz2@1nCS_DLf?+!zP!o){ILO)VqF4&1_)e7tY1`rfZ!%zYTDkMRTC&MT}{*Eh= za6&8g0x=9fn*!T{m6bBUp_+M! z7ENjv4M*1^$=lN8%dCjR*l$uK2FtY%6Nxo{wFkgD?+@zb@fQOjP$9bEhMq69MN?o0 zb-%?fncj9X9QwCpHo5#9=~PFaCtcjhl1=1AJ5&tQP29--Cp_V*Cf>%6_D%M{b9Rx_ zH5XwoyR!GBonkz6MZKT@!8tL#_E{9;#sb1g_EV@KBKYhHd80XI8s1)fd8l!$b136; zsqlc@03ZPGlo?(dbQ~Rxa+93 zI9{@R)*xR+00AwHV%QN z1Uyw058od|v~sMzm+Dbt$tbt2Aw6pKuKku=mE!=W{vu$-I>+k2FcTdx*CAj_J@!RU zU4OqaczA<3SI7=C`g^dyy}{xFH(3|#0?xp<}er0LX zs2~Fnmd6T>M#1>B#No+=5=+uzg2_nB?y6^lNSZ>aygSH_Znjf5d?%H7Z0u+{j3yWx zk#wp{jm2RC#rLd<(X4UxKyK7=zB_LaG`Qx=MU%02Rw3)WLU47CoSzPk$6vW}Vd zn))R1Ooj|!tZ54 zsWCQv>}H##&Nd|?d1e?Ursi}$dlaFEEe!1UQW8I$bxQeKaX6X4)ml{LS)j#P+OnX- zan>c=vDmn|D{5iIB-{6?>ct^URkNyBg~R)e<5i2l!DHbxc9(paXvF3fUTT9AF$-}Q zjZ2yq45^P>qoVoH73W^~Lo}Jk=yo*6{8nj);WhPjmI&ugOucqBF<4tTQ>=5IGJYiI zcv-G~BEtb$%viD)yk(bM@xL5LqK7td51t0SselH>5oPQNR{z1aV(nWP< z5|7ihUdTx=`Qg>{wwsCXZ+>Y)5z;#i}QLt9WLD|!m5J|{M^)d zw%Pv)r=w0p1^(zlvFEsHI)c8dU|+p`$w}zLz2iFYph7Y*B?7!39Tfxae~68DW`YnP z4xud}G#?A0qrJPW1nY&>ow{fJgetdET_FrVlo5n7uD&5mv6W-ZrN+mog&)THF6p!B zY?vIvPLN4L|<_t4j`40xY5 z0AL`&Tj@y=a0{{x@9&@+t4CZ@DYG%Iv>U$dm7Bb+P7`2v(tZEAM z<>waC|{N-rYTAB?({|An4{k;GH literal 0 HcmV?d00001 diff --git a/tests/GCIWithoutEmbeddedKey.gci b/tests/GCIWithoutEmbeddedKey.gci new file mode 100644 index 0000000000000000000000000000000000000000..7495e19fb52c8d64b28ac3df8420e783f1cd905e GIT binary patch literal 24640 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 X%MaN`-7QZzCsu;L+9gY!{|cmAsg53g literal 0 HcmV?d00001 diff --git a/tests/GCIWithoutEncryption.dec b/tests/GCIWithoutEncryption.dec new file mode 100755 index 0000000000000000000000000000000000000000..346d41ba1182325b318a4225451b280670842392 GIT binary patch literal 7182 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 literal 0 HcmV?d00001 diff --git a/tests/LionelV1.dec b/tests/LionelV1.dec new file mode 100755 index 0000000000000000000000000000000000000000..e23b967f4149b316a4d92f96fb989891d9b83d52 GIT binary patch literal 4374 zcmWNLdpwhi1IG8FvbWS$y6AG+x||SxbW&6&4b$d+tx)RS_KvZeU1-#)i0DqvDVN%l*vy^5YsIP)?m=jU{Kz$ zKmZ$fI69BR!g>G4;ILsPN@G~Ek$_`~_|m>_LOyPe*$T!(7$q%L!iZDA1{zMl0R>U; zH5^IE{wm!zd{D^XFllx_b{=k~+3@4jd$!Jl0YX^A+XLcog#CBsaePK(#Yh50BpdJ1 z;~1#K2)`HxJCcSP3xCh2*5Wq3hnU|ubOSDm!E)II214*29!>LPr=z_+4)Ez?zl6Xa z_QKyi=l@XqTFjtssvV5xZ&j;}=d;b#CPVYLk^5SwdGx-*=lxn2Gwp|c!z{qw zfH8J77={066Gwxwy#eg2Z~+_*CU@-(s{r5zf2KxT`?s+sG@X^}p2mP!8TT=~w zyCw|KAcEWpk`D9%T9<0$=J#1G`X7LiMD_eOpa-w{rd-sD4ong@Ftw-a)C(Jv)wlFm zi`HDv2L#WlPg(mYPqB?ag&ysD!SQPIw+J16mzEx(gJQOF^~-nayk_lnW;K1afNQbZ zy!7+%iQxT=HCJ7hT`fKRMRIwcZJokdZTlM5tJ-E39aO|z+&6_hQ~<^@WNCqRx^DTe zrag5xn-K8qt~LZ%rDKkCtmr5{YV);84LVvXm;QKys1L+ECCxA0sR7DlQ|Mzf1aqud zZysi%Em!z-st0Z<_IF=buhF7^lc~(;VSRHp{bA})gpF}uOoq;5Nh9@u`21uI5jX^)5_tl~>XIJ}J_J5>1L z2qh1u!s%jiwz#aZT~kVj<8idTkSM(?lC!XkTy8lCK5c#VH7dE?2JSprLV~v$AMB(* zs^}l%+RcCsd>95;!>*4YWmHm66Nn9bzAzqQUo$y*WUV)g!#!Jikn>BZ1UGR0A^jDt zWmkJEg}3FwoOrzoqQ(FpNT|D}n8$fi>&wv`ig_Fq^?Diy2h4owDrqlpZnx*>ea5|a zR#$A8a3vauE~ulH_CUb0J)toFjnsEN>cF0UqaA<)kf`*7ynZ8ZOA)CKsr)GR^8&D? zCJv@AW{Seq$!q?hElCVe@WPV$ToY%tsVMS#g1^06;*N?-)odz(;Z)Fk?4kP3ypVfR zjfOl`9W0i;*g`H?TfKaifobVOvLFSY$%u^7R5DmF2rxfeL-8wAOXV9AK^o)1jG(DZ ze)(}pkRSaw9xAC`w0SxijPICW(v~YIR&ad$@~oe7`#|}{dUCb?*)-n{jk4Tv+eQs5 zczLmQ9<`NfxTZ_{{(+h??U}zWwI>1gxT~C4W1rPizX$HdC4utDyMe=Z^LfA#oB=$gxO*A z6uUSQ&69_h8Np5d0iWT{ED>i>4m280lUg74^3K;85%w*6^7 z^?*QQBZ-!QTv3I$maqs%5k79LpU$3S2Nj*4fgDB{smkJ=2RWUpbpjWo5ze7+Od(cQ zJM7-{GgRJ>SoP+gE3zGns+%5?qdGhAlmfd0hWGx(FCaeb{VncFIhgUyZj(cIe=7TK zHWw20#=9y&UVRyEn~=@)u3S{Q1wGEcSKR!KGI?mtSMVq@|DqWEBtJfDFsHbRC!glA z22w)%ne>--;0~fbTGgD?NvR@KuarOOK|8u^21zfvO01=#oJscE$WXNp?2hx(!} zAoxkLHs_n`44=b-|LVdGG?BS570XDnDI#~;nM)($m>{FB%T_9P9cDb7YLf_-OX|O~ z_6qq!!?D8k<1iTa?wt^#FyTX!XO%c9Xw8d(Gc!jb8Rkqcvip+exYrP7)iyF_r4l z;E)Oz-yg*RsZe1PC&?p!c1CqLh{MAVyY-kZW?dyPLYfC&+|qV#`+FqXRkdkwMjfQV z!(5yX2cZ3jn%YwJ0q*BTqUJ`c;|Md|ASFRbjNdTW_3V2*FSRt%g~7(ixa*a3Di*&e z#WDnF_bcc-@ig|kh@KK}DLJfdwpg)vlA_8IxoBGt0f)VSaQP_RHDiQG3;uwWTMQq` zWzhc7EGK49V??r4m7V)Z%O^GbiJ+P_ws?B4kLYm>V~QZEfx06JvFhRIyH7KE1kQ5l z=XgQQ0wt zLm9JfVe*6=)uKKZFqnuSS*3fIdA5WH!8w-aqsJS{s8N^z&?|c;kXE8dC|_W#{6+j` zK~5`P{?4rPQ)w+DZXJ`8Rn6bt8Th{C_VoAtbV1py4H*5twsf{(iuIB<3BpSnE$Gtx ziuBLCV~VOi2}b})8&|iIw!@;zsl0Y1f-Yp@LDG{KC4HhH@0T)endG{^1V4Z=+Wb5@ zKRmj-p}m?{N;?iTdI4hcnm3DCsj|^_FjfJDWDgh(clETi{WGY3F5Qhglrjw3r13xH zLzOK(9v3H4E^lS^PE;g^S3*PeuP!!>j27gv_k7_CGY9Fw-pMoVIe}AS->b&Ru5~X4 z;{sy7JVK9}J*f5`Cww*|d$dzt69u(Zscrl5ZDf_3QEX*;FwZ@sC8^(BjQ(c&y*psi zDPb({JumFsjPea&i*{Af&9d;YW?_nks###Jp#*A7G!RK+tihkqfEzTHDDf-T8Rg(0 zv_1LB#h`b*;X3iuzfZPV3OX9mTU2!HiqQ^QxYdZLGvJH#_-?T8in#@iGhZblbRd9Ej5%wYd?y?bFG$Gm z*S?C$Eo4HEV^!?f2hC$Jl=j%;%GWIP0K{h(4uIrXr64p_ySsLJ9D9!?`gRLJi{0(4 z+C_dj1JC;1ajEK@uPH2x>J&nmZ;bTOVaP!(g$BvKAt{2vdWP#8j(}7@5gO8&89mNn z$X=`@@^;8qQ$m8X$4upM8_x#eXbfCfhi{3w!{k9fa5!#x7b$z15x6hU8>Sy_xY;R<2tsj5S(+|?_z|dnDjEMwu zV@2YTbaPvNst3w8d1zpVCUM}xK9qQy2e`fGzAPJanB;L@=xdEiyDl|)78FR1%qLCg zgN*)O_f#3U!C=uw;1h#+lF%s#QcZgV6YuCV`_{_x$pL=`61C^1L~<4sic`8)Od%P;9&)2>sNdB`gyz7(r*)|tH#>=*xpAbd_CVC zkV;tAiYg^Yc@cWdt)Z-mPIT_`$|)j7zx`^=i8~u{RDv;GtAwJZy6BJ%8ShG(7`_T& zTPv@~BM=G;ohfPYacq9uoU{EEk0>BtoR1@xPBVBQeWTEqDj@IVeCSA!vvz*+t-b2| zs?)Fa9>bxe<0J9U4nbk;G(wGT{{QAa4j~l0nEm1wMKq%&_dKKZGm4r8)gguM z|L*MPb28K^qY{cYf&91UBVxpGW4xa)n9y;>?{InpbwQMKikMY0ARaL{wT4XSi}h#lrH+qvbJLzY&AXxFJt)=c|j?{ zl3ADlxvxLSUskPm<+yLzpVQBU0|`$C&dF9ZeJnt29Qjg7T3zLQjH%ofc*XUOj49yJLMjt8) zV=~;cxLNvk!ohb=b1N!Rmqr|q#W3oP^d-kE^{aAAyn&|U%aqpyhM?(VX@~_*vFrz;V-7EhJcrkQJ@lJmZw@N!owzJSQGvg4Po9 zYcb#}tC%xRA106?1Dr`H>mF>rnIDrDSZsIG5R`jpRK+UK2fOku4U0#6MX7WCx4=ty zkYBn#Z0y8`G&@%RO4=po(yErzl=(hL1a2~Jy}U^V{O=U#XnhMQvc4TT1`DCEvAt}s zHbNpsA8&OAFi9$;s0ZASSbYI`fq-r9l6vp=@^+w{#{6TxBtGx&`{OsYIq0kqcEPQN zi)HtVyLm$Pjc2PWuR!GU3)M7+=EX?tAJov!FzU6HYWE>l4&~)-(ELpF=Et^a%U=q5 zauj3m3CUDtqVn#>JygHYEx9D$^F+6fALk!Q|7d3rw#T2!hK6Xu3tH}q`pa;P zd7U<9d-w4tjZqY+FeC3TSr4z|6P4E0qAE(nKltvIM^Uu$I@KEzFQyND&<*5a-{jQ| zMcw$5ix{DI%_my#_MAv_+GT6yw6wuI&bV}HqwW*{a4qkQv-9VFGrqDlY5yt1t=maR z2ax<{HeWFV#{%e4lG@0E^s3i|be{<|_1gxm9h*m4YDSS3%>^Cmb(r%=;Y|uT{3#CF zq;k%@wH|yleE3CWRx{R%t2f`>YtPlMJhG0fU+ru+fUH`-b&vYF;Wf$xqcPkl`*j&^ ze(MQrg?{TqafSY8^^e>(55uXlHHO5Z9oTii#5T0-T|6>kRH3R~x^Adq4jrxFuKRdk z&UR1J@hj`@sbkMxcDRMqu@Pk5z1f23H#rk4fdg7I&*qjZ4|58N5Vz(9NdLO#|6*g$ z$loBB7Y=B)TF;s8U4_1<$6s45==opCTer2;d-@G$2TZ7)<+~BidgR*TLF6rByd<@= zWhvt8l=Z9G2jpqTd=^eWXA$a6zczQm%!`* literal 0 HcmV?d00001 diff --git a/tests/LionelV1.vms b/tests/LionelV1.vms new file mode 100644 index 0000000000000000000000000000000000000000..616dee67cbc257169811d3ae18388aa9a45ff79d GIT binary patch literal 6144 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 literal 0 HcmV?d00001 diff --git a/tests/LionelV2.dec b/tests/LionelV2.dec new file mode 100755 index 0000000000000000000000000000000000000000..48cee3c60077ba5326a36b302a0769ababd4e83b GIT binary patch literal 4402 zcmWNTc|4Q}1IOnAGv+epc>C-3{d|6(-|z3QM;CxV1pmBJ6Sh$!(dz*Nlpf&^ zbGa}Zt*5Y=bhJN}Imdu$2$g;%7QK(o=L{Vk<#Et7_f9Yc%9N9PsiI^VOh)UuOpqH7 zqw%pk#KYHgRsW}vvwjT#Tp5=%s+(>In>p$hb!(y8QFlx1 z05}?ZskW)23{;wlhckFB7y#TiQ713$UA=V&fa+}oS+Wm&ABv3e@P3fltm{tQd{aKEtRfG1^FI6H8}yeV5kHS-Yxn z?NAd?uC#Ee{Cp%R%-!lD$76NniRv%s_c}Jqp6pgS!a7Bl9MwfC-Js zvov+{xY?h^%~xNyX~48D4X{SLo7QJO-dDc;TS=P|w3nM))0t|Nk)Dt6OC|%mRKUa> z@-SJ0>ONeqvoKOu%K{7p%4q-8hNs3La~Z6w77kGgUy6u#qsa1M3sSRm#3;% zrT-P!I*1qvh81D)bz8q`8C&#RG=%2zSyW*xL<5r&2As022jMAt5j+Vu4X))gdC|SP zaVDGZgouuqm$Ttmcz;q)dQVl|tL{n)EKEU@A%0SS+)ic{!LwQn7G3H57N6MNusuLf zfwzUX><~~8_k|aySWaN;Y7Pw3$58hnGkN^r`8JUF)HwxWpf4S5JLpemrlnP0-^axE zqA|nwDETkRKX-5LB(d*`L_G>9HqrP!9&yV!t+>S4;e2rdlavg3zM4OWh6P{x&lYuK zx}BGC@;=uCyOry8GhR5H2jYs{7!BoY~d>o zC^CacOWa(rF(w(N(D>2Hnv8$RM^Zy%Y^x{^%g1Q9lAjiLEI89U6>vFc(!hwNx=j_d z-&5XP;<3P^O5}b;Uk07tV=ZmxHkd6?(>jKR^C20B_K_MFUrSw0he6usU?|00v1lSq z1<6z^2^Vgwk`~{n2%;FAWS?qm*)X3`52nn}$bn`u5}cBol8^s+2$ag%Ejt??&vTrR zy$E}k?Mhh24oh-!YU-|41~iK6?7%g=4N)Iy%-|7_ zpv+mA{@KfJOD)*`holiJhaR!{JlzU;#>8L+t^6Gl^g1z}fDg;?lUh&B)z1G0M5Vno zbpl;|u?xsKMo@ViTiVtU?l2nDzaSD1+qvmX?Su%_e*0hZm3VcNa@RsgI4;yN?4}mf z&S(C{IKcs8xs|Hz2@@a-s&V&MW6>mDd~wTs!7Sr-Xr=_(Io?3clJDC0l_^kgJq*T~ zWur8n>4aU=SR1&xTBz~f`jv**<~SAKJU=4!6!ejdpE>DK^}$cdAP($5%BwyM=8ihq z4G7O?F$&^X5I;rfB?H+ns?anM5l5m)GcuPOJ?I?i-$5M?>y*@_}I9Z62BWNJCxnCq*;Wb9RH`goY zn)SAPr}H=_BV$Rt=`%2x{EoK+BGKRjvq$7;u-t*22$3wEl9^BE`%RKmY zj~-Mg)aS$_3Uo?5^9>jaJ#S+=l@2dR6roH@HfGFw&}#+#A{7#V>r+q^la$bqonVA>(eRwdn45C=232kR zGjWhKh2`Hag(x`*3l>S$-Ygb7uR|WkF}*9q-PufcH5_grboL6tjsEdsl=|bO9Hdh@ zn>g&r!5z6`HkY&KGkFrONP4l*!-lmRYi6|=48s24*@p`+=Kj57E_Yq*uyq2THj-=5 zf3|##i~ynl>sHss>i=?}#2Yhj?2iGkcDqZf8$c!3Sv6w7BObYpPN8!AC6@^>1upO*#>aSdAouiXyK^naB z6UA3lGoAC9eOOjE#N^5$(WkYYc$g2?&Xsh>cu;sW42X9qs~F;sn7^19tm?fSj2T9~ zGT87mqcnP;wZFT8T}cK$`9%Od1gkeIvL>P@yTK$GR4^QFFxEfV(Ir+sd@A}KeR?b$ zw8-XsglZEz27S-Y(9hGGzRuJ{*Fv{PT3)t}-8F zDME8uusAvKOW1wnccq%ZVYh-tY&s%m-_N!V|Lo$;PYx1llGIZOCfc=U%IE*{-M;xXph_fg9eeM7; z@-PZz)LWBho@$(9;kY5o7vY$3W!OcvZTQSyM9&sqaA1HqQGklT`)2Y29T3@#3uE{0oP!|6yl)uprp{}~W}=h;Tqokxk#l@09g0ND zy$WZyO365!D+}8!cpQ2t10Nm`InS&VqJw->72f=ZgAed@;JLDnQ5?VvZFvJRQx)iV zoMArRQrmM%mNk8Q_Xu&NE+%z~urFSxLpKOf%*Da}q3u-*c<(8k0PFTrMApSAdLo(O zXkP;J(yt#*A6JA{{}1;wQ3(YyQ&ZWdN}LB+m7omee;@=-iq~uy=shg#E;W{|w%4v~ zpTOTiYj;+IALqgYeb9^J@facK9mJ$vZ-hmhcPuR1lv}lKt$HxX->ZpIh?}n~>|%2Jj!Ege zJ_hnH2EG&oW!$EU%KJXx{Q9`hljb3_bWo(Ab_PF*EDpy)Wp}@L$KzI!GtNII3$0)O z5T0eveV*(Ra+tZw)04duNc`WClpMB z)dDh+>D^^!)6z04kHr!vIIK4~tlzX4iJ8CE2?Zm1oO<}oaIxs88}?0oTi~tJQ}Akf zFpeF1npd#^VJO6~+EW*^PIQH($2jX&U#xoNrUM7rR4F}8XIAo3b5v*guq#Rw&fCy?A;(I$=Glm3 z#L?!!Ymi2jU18#%P}|YnyP_T zFU8i@Ut6^|O#Mv#O#?8d&mBWXaPh8=YB%kw<|mk4)do6!Fs~m|d;3t5Uwz-9+iKM3 zA1>yHil075ys#nf?S=5lbE`dPFMAY4-ZT#=(JL>ztmp8V)83L zYY}k`Jcj`}mF`i6N4VKebfKlix!sj@9VbXjLl7UdGt4+|Hv#N84!ZVV)x7R6h%1D7 zrcqPVbiXdiF_bQ4>)*i3^yehyWuJpvzf>j>0mp|cTm0*#-2jce?w_TKl#-x3*RPfo zRa^;YK-Z3+O}tY+z~(W$AFoNe04-)LSCXl!vT@8mv5|r(^GlXWpDXkt(u+dy{mF#R z`(MwPz2JV`{I?z3k)u8dhSSw2BhRF#H5|)7wP6IrrCiBLecVANWoAX3HQZQqHMpdK zW(2*bT@TT9s}QJ_hfw-}@H|Bxq9ic+p0Z54@|<+f1Fh|b+>sW2MX3C&O(O_$9TeFBv`CWFx)^pKuAES+Cds~@w;r#hBO_Eq+v2K8Wab4O% zDZOaMiVhr6uL{WNEFO9Iv_jLhEPkWlEq8=}Law>AJQ=aL$?@58Yh>?j9p=W`XJ=}w zf-l(I)~&xVeBmciN=gb618D)t3DO}U-K8|hD1k}7 zo67I~zTe~b&wK8;w&%RB&vo9<{Tw^?$Fy`bbp?18H1#ypH18`gGHU5)@~T-seQNE& zXyf7P%&2DX>SFE0_#XlOB{TpUa%F;Cj`&}VzZPSk@<91W?9l(j_-N?d;b+`&1p;<< zaeZ`+xW2vy?1TQV7?o`PA^Y@H7VrO+Cm77f@d~N30i-%#K_C!qrF5jSP<|#oSwTVh zHy?oV-e9Eu@UM{eOE?mTX#M8X%TTxiQong+Z@+;7PcSn64_}`4YW@qva01Emq4%180fi;xow zvtSV>Vqz2@Jr@pXo`XP2^Z)Rfu*T%fMukima>4_}!(hmcI1E<-VvCVHj9BvKChQqhOfpDZp@^E;v0vxWO1c!Sgc~9i} zIyi8J)CInR;*p1Rfv*W6SGS0f-V6B`${rv1wlM(Lc<6L7ou@;DPyEFfV2MwVRK@R+l#X%V52Y3D+2cO-YfUE?p z^}DmHlFtm>gU@nKh{G#EDH(tRCL1q2UQd`S9=?IaR8^DSNOPC!kl?a>s0MYR*f4LN zy?uL27xypD9)Kw=4*n%URWto|KlfP`%Lbjh(1cwGd9Es^_tYZmbYo7>9IuRW7`ZOS zuX^muqy)dAu$CkuKlvK%uKkD{h0hclD_TN2lVpqZ3yvZap|jFy+_<9qR8TkLyY9gR zBj<&_wo#I2Jgt6x#&HoW2W-226X9K{+G+sQFj-mwm zm@sVYT>Vmw#n3;Ta`Je@5AQJJrd&XK$`DFhfs2F9aGJiR(C+YK- zK}Om$vPafwGBQ4AD|d_y8|_#|$et^$Y&GW;=jqE2?N1XU-dF=i9*&gooO?dkdjAzP zxuDNO^4V;nLR?tEWm*XH+3-oPqUM@AR9DQT;TyWSZm_RPb=>JLF6B@fEk@MQ6_ftx zfZFQlo2zO+-@K@>T2*wO4@6gMmuuR{-zly6pe6^QBs82O{Wzu&J)zWwun42VjKZiw z+49f^_{iGzSbTM)F#9Eq!4*z!vZYjPA|Q1Qq*vMvQAPkTad*UY^EM|4Wg4>`=m+ucaoC95`pFUgzOBMq!y_{H$bc5o zB^KAvoF^VX7t8p7_hc>iLiFCul$DYcx_h|;FQsEnaKw>myL&oK~7*c{5iBD-Aa z#~t_(ELUMX`J^kUmxPmW{B5hyHz8XAEj#wtce~ijfFkS&nr91k$wxLL57wUCT_qsE zpiDj|-^?Pq-9o2RO5*;s@%8bzpi#r@ee-hekY|wrET4euQ-PV|{LoiPD`$JpPkKgO{ z@x9ZB*n8I(V#Te7z1|R92e~7noI%9Vf&sD2mU%*E72?+^YKZ zN9ERCMgap))@^3r6xs3(VY_uus$_M^DYI@&h5h!q-*=lDfBKbkg0=p*p+2? z`#ndAr15(gwgD#&kG13;$<4nQfqzNRea?YCq;ZA(I~Hq)=0ueV|xvQ1ou7YX$j zM_zFTku<)dyH9Hd7`)$oJ;!65w&(fQu>Y9LLbLOpWthB*akYk*WUb-pw)*(N;(X%V z$J`g2xNBeEA;|nA>g%~>qWk!-?xT}9zEj1U(z9HeGW9kw1?JAeE>f*an>Z;8162oP zgEu*e{KQ=vKubsyP5N@^peGk30Q?Be}VekhJXC6C$8lIuwpu-G_Yv+tIMU*}@ z#f9qo{H*`VU=8mV@6-H=yO}Vz8n`&PXIy3CPI@&LElcrf|MO%U#qE%~vdE5RNMsLi zK(4syG$*sCNvg+!TD?>ZU|z{$`){p=onwC0Y4TO5^Y-^;%s5cryV%fF{N9i!&dK;`B== z2%*Itnzj{8=EbF2=SX|EX8v6BRqoC-l7d!jDRlJUFY|sz%MCxE?83TYMdo*>NSZ!3 zL7gfu09TWDZ~4W+-cdZZB{aJVN}LpVo-L^v3ZQ_xJ;GjV+^$ybtkb@FU8XiCxh!)5 z1+C(D^`m8kCly1t*~DVxlmr`CTzP|?gdjmUt$JTh!*{OVzw3!d!-kREx=*%rrik$} z&TCAwuZeHTwc*M}*k;UOM%`2zAuZ{-ZnYk@wtp7PoylFEmOen5fS*b+Wt9OM4kkU+ zXcmRgLM+AIV$|-wQDlsw^~mA<9GQv;u3XFSf=ZVNl8olUqJP0WxzCf>D4blNvZA0R zaK6*fysdgj374zAh(=|=sdtg|PKdmDxxvpYQqp9+~0xAL=V3Fmx8?w@Cj((X>omzWAQ(r5SKX#61WRB%^drT|_RD`5dW?l|6Z$>YoE z=JRpweWgX(?HQ(`%vF4zNWQc#8;!-!q3RgJDuIT-(1ZP>pjJ@4DDoHXcOj__gdAdY zO$*OR)whasZF@ZypB{JXY`0ntkRaAPac7lIGh!gX)2xN)d-3Y_quavfFKt;;c)+w;jN{Wiy(B(T z=w*?9VeLLySpu^SFQ4*}sJTa(m``)TuoAq6=R)ylVyIZDrXX{Z3~PStV7y}kY1QJ3 z@sj@5ITnbZ4fmu10Iyg8Gq)K|S}$}ow(eO0f#2KJ3SD4!l6oFbS7nh1?I&gXK#$jX z*itMQuo@m2%6d5aDM~4GV#gUD7GTt*PP`)`{OkGh>?W5uNN@f?kmNx5>v7EiNex!f zt%x4*;LHB6KO@XyNq5#dzI1z`HFpOFDIhXnbKh2x--+6 z(Uw}t9Poj-I(&gSFZ`yX4&Gp`PLU4E1B%^y@>33tVn=2GiFq!43&Epx8>x_#3CG6_ z!Aox`0CK=|j?#yvnHFF74lM@CkB4*jrj;8uqibUcex=+xFa=R@WG`=El^_PhRw1vu z%j9dA>tIZ>=%4O>TPC(!b7RJ$MmKxnDPLu*#92Z_??#I_(8E;1Nlnz|BgTl$D6yrK znw#enJL6U*dO}h+)DtQ8-BVV)yM5ZAi%{)AhH$!b6<6ux9rf7}6G+W7|3a|0oR#>I zj6k^~e{s{*)sFb*#DRRMx)-@0euc-*bcH$7`yL8;p)<%EIA8H4Vi853Jr|m(=Rngc5Pp78AYs zhUw4`KHuv_Zn)ytTbc~F=P04zV`YtnI3b2oNit5hKT0((`) z75u(cnkN<;7u$4b%$}W5pzWcf3|$X5w6r6WJ+O9Rd|$r59|$>t%s8IuTx@a`8=+0$ zJ+f~V+#48o3Z4cl#spB_mYK~G8;Ehxp+7c7+iZRdWl53x(468!J?iY=karkQ)J+(F>ZL5n6r&7GCaq7{49k?Qt4IG>f6~Ne8SsgfkWnrmFT!Oj z&55+VSoOIr!+|kq+)dn1tY45aw&+ymO-)mLc<-Z}!5Uy|VL>N7v^BEkOdvKm$^z5DKX=JcQXY=E9tyqTVe#5_F=`Di5*qJ9)5E>ptgG0-Bg$0h|#+9V~r#EdN zd#7uXXdi4g`edk?SHl;!Lg}_W%ouVeZf*hMnPM6+Ce3W3{s?IC_8tyDsS|rvZ9xk0 zkV)eX=qeDR#A<0<>u^ui)QSo<;;a z%I@hh>@8=0{Klbnc9!pW(Max=rsSq1y^Yqkb9Gs^%2p`p<#1?f^(hety=Qpg%!YSm z!%TdCa=Ea(IYY%NOrLkK=V-KMI7_L=IuLS|Eef=Z)O!7vB{y)|{+S1Qw%e1yK}!vs zTCYk{i2}Q7syzUS5V(+Q^Ex$49`HgKXGDm61N>s60O9!y_b^Q$CD-ok#KH4ncbi-d zg@Dnvo~|BtOjO6+)!1QJ{Tj0kV!O+xHaO6VMxT+_ATm|@F%U$+F(u|y)zxI2i7Vmd z9M~PIO{DQ+W7aX>mkRJ`R-KE`&3dcG&WPJZ={D(o=o+&Sf|x)()gHS{hf{KJb-&A( zKbSWG{m9`ovoof%r9i_f^@*Dpe|I2uqW1ow5*>m=Pz_@z#_Dh|cA<&5M5LpF3iIb= z>Bc?dODMe3onUE{;94U{^E^7VQ`*Ue35YmT#aAJK(O$W79x++JJ-A(+pQLv8qj!wO zr-YTo;#{hmmxlR=;x)$%E{}wPN&qpT=HfhdH%?DL&fX|S36uS&&jxb`R$mc zJzcj0<&+J#B$$_VaFiDmBHFwdK+3fW#wb4+{6<|COxRt<4ahR2Y_*t&m(l!y)?is!gW1FMwDs$7Vo<{2A$pnWeHa5xt$u#DJr5p}W}M zs6q=Rk^?NLdD1JX`!san)S3*F!xLv#&(f+6y80ER_H|4jz5DDGTtzoko2l7o-Awm# zF}}qy#e6wxcH~W#`T8*re6?J#ZD$9l&Xghg8KWJdmn;Ke5EEY@`Bldn)zVyZ*wQ<9 z+6B~k6^unniQQ0f(&c<864D+y7=-7&fp6wMy zP2%36kaIW+FubGF@+~tfmtn%Hl*f13%dlFFf~aFSFlB&$+)d|I#pO*_k)HOEW(MG``yaCn(dyrMT{wt02*?X^Wspxtw&Eh% zOa|kH0ZxMK@vM>D;=trx4DG5rpQwU6-gQg)H=PyAUxqDJWQNhOjVI{fxmb8U`S(96 z|3BY~#2JvUSmY-ZS=E!sH>7Ae7GwPG0RFR%>KCCEq1|xnS-&xW!aq1v4^<3E^5*&` z&*?9R+5=T_f4Liflb8ILL-h;(a*P1R-#p6SRgQ7vvZsuq_?x`(zZ|Nc_m=|!K)-pEzsbA!%l!{oq4D1U literal 0 HcmV?d00001