add decrypt/encrypt for simple DCv2 executable encryption

This commit is contained in:
Martin Michelsen
2024-04-20 10:08:45 -07:00
parent d40c260d18
commit c95b158e4e
3 changed files with 68 additions and 12 deletions
+32
View File
@@ -1425,3 +1425,35 @@ EncryptedDCv2Executables encrypt_dp_address_jpn(const string& executable, const
ret.indexes.at(fixup_steps_offset) = 0;
return ret;
}
std::string crypt_dp_address_jpn_simple(const std::string& data, int64_t mask_key) {
if (data.size() & 3) {
throw runtime_error("size is not a multiple of 4");
}
StringReader r(data);
if (mask_key < 0) {
unordered_map<uint32_t, size_t> key_freq;
while (!r.eof()) {
key_freq[r.get_u32l()] += 1;
}
size_t max_v = 0;
for (const auto& it : key_freq) {
if (it.second > max_v) {
max_v = it.second;
mask_key = it.first;
}
}
if (mask_key < 0) {
throw runtime_error("cannot determine mask key");
}
log_info("Determined %08" PRIX64 " to be the most likely mask key", mask_key);
r.go(0);
}
StringWriter w;
while (!r.eof()) {
w.put_u32l(r.get_u32l() ^ mask_key);
}
return std::move(w.str());
}
+2
View File
@@ -32,3 +32,5 @@ std::string decrypt_dp_address_jpn(
const std::string& iwashi_sea_data,
const std::string& katsuo_sea_data);
EncryptedDCv2Executables encrypt_dp_address_jpn(const std::string& executable, const std::string& indexes);
std::string crypt_dp_address_jpn_simple(const std::string& data, int64_t seed = -1);
+34 -12
View File
@@ -757,35 +757,57 @@ Action a_encrypt_save_data("encrypt-save-data", nullptr, a_encrypt_decrypt_save_
Action a_decrypt_dcv2_executable(
"decrypt-dcv2-executable", "\
decrypt-dcv2-executable --executable=EXEC --indexes=INDEXES --values=VALUES\n\
decrypt-dcv2-executable --executable=EXEC --simple [--seed=SEED]\n\
Decrypt a PSO DC v2 executable file. EXEC should be the path to the\n\
executable (DP_ADDRESS.JPN), INDEXES should be the path to the index fixup\n\
table (KATSUO.SEA), and VALUES should be the path to the value fixup table\n\
(IWASHI.SEA). The output is written to EXEC.dec.\n",
(IWASHI.SEA). The output is written to EXEC.dec.\n\
If --simple is given, uses the simpler encryption method used in some\n\
community modifications of the game. In this case, --seed is not required;\n\
if not given, finds the seed automatically, and prints it to stderr so you\n\
will be able to use it when re-encrypting.",
+[](Arguments& args) {
string executable_filename = args.get<string>("executable", true);
string values_filename = args.get<string>("values", true);
string indexes_filename = args.get<string>("indexes", true);
string executable_data = load_file(executable_filename);
string values_data = load_file(values_filename);
string indexes_data = load_file(indexes_filename);
string decrypted = decrypt_dp_address_jpn(executable_data, values_data, indexes_data);
string decrypted;
if (args.get<bool>("simple")) {
string seed_str = args.get<string>("seed");
int64_t seed = seed_str.empty() ? -1 : stoull(seed_str, nullptr, 16);
decrypted = crypt_dp_address_jpn_simple(executable_data, seed);
} else {
string values_filename = args.get<string>("values", true);
string indexes_filename = args.get<string>("indexes", true);
string values_data = load_file(values_filename);
string indexes_data = load_file(indexes_filename);
decrypted = decrypt_dp_address_jpn(executable_data, values_data, indexes_data);
}
save_file(executable_filename + ".dec", decrypted);
});
Action a_encrypt_dcv2_executable(
"encrypt-dcv2-executable", "\
decrypt-dcv2-executable --executable=EXEC --indexes=INDEXES\n\
decrypt-dcv2-executable --executable=EXEC --simple --seed=SEED\n\
Encrypt a PSO DC v2 executable file. EXEC should be the path to the\n\
executable (DP_ADDRESS.JPN) and INDEXES should be the path to the index\n\
fixup table (KATSUO.SEA). The output is written to EXEC.enc and\n\
INDEXES.enc.",
INDEXES.enc.\n\
If --simple is given, uses the simpler encryption method used in some\n\
community modifications of the game. In this case, --seed is required.",
+[](Arguments& args) {
string executable_filename = args.get<string>("executable", true);
string indexes_filename = args.get<string>("indexes", true);
string executable_data = load_file(executable_filename);
string indexes_data = load_file(indexes_filename);
auto encrypted = encrypt_dp_address_jpn(executable_data, indexes_data);
save_file(executable_filename + ".enc", encrypted.executable);
save_file(indexes_filename + ".enc", encrypted.indexes);
string encrypted_executable;
if (args.get<bool>("simple")) {
int64_t seed = stoull(args.get<string>("seed", true), nullptr, 16);
encrypted_executable = crypt_dp_address_jpn_simple(executable_data, seed);
} else {
string indexes_filename = args.get<string>("indexes", true);
string indexes_data = load_file(indexes_filename);
auto encrypted = encrypt_dp_address_jpn(executable_data, indexes_data);
save_file(indexes_filename + ".enc", encrypted.indexes);
encrypted_executable = std::move(encrypted.executable);
}
save_file(executable_filename + ".enc", encrypted_executable);
});
Action a_decode_gci_snapshot(