document challenge mode time encoding

This commit is contained in:
Martin Michelsen
2023-07-09 21:04:36 -07:00
parent b1531139c0
commit 73a68911e8
4 changed files with 45 additions and 9 deletions
+33
View File
@@ -4,6 +4,7 @@
#include <string.h>
#include <phosg/Encoding.hh>
#include <phosg/Random.hh>
#include <phosg/Strings.hh>
#include <stdexcept>
#include <string>
@@ -886,6 +887,38 @@ void decrypt_trivial_gci_data(void* data, size_t size, uint8_t basis) {
}
}
static uint8_t count_one_bits(uint16_t v) {
uint8_t ret = 0;
while (v) {
v &= (v - 1);
ret++;
}
return ret;
}
uint32_t encrypt_challenge_time(uint16_t value) {
vector<uint8_t> available_bits({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15});
uint16_t mask = 0;
uint8_t num_one_bits = (random_object<uint8_t>() % 9) + 4; // Range [4, 12]
for (; num_one_bits; num_one_bits--) {
uint8_t index = random_object<uint8_t>() % available_bits.size();
auto it = available_bits.begin() + index;
mask |= (1 << *it);
available_bits.erase(it);
}
return (mask << 16) | (value ^ mask);
}
uint16_t decrypt_challenge_time(uint32_t value) {
uint16_t mask = (value >> 0x10);
uint8_t mask_one_bits = count_one_bits(mask);
return ((mask_one_bits < 4) || (mask_one_bits > 12))
? 0xFFFF
: ((mask ^ value) & 0xFFFF);
}
template <typename StringT, bool IsEncrypt>
StringT crypt_challenge_rank_text(const void* src, size_t count) {
if (count == 0) {
+3
View File
@@ -241,6 +241,9 @@ private:
void decrypt_trivial_gci_data(void* data, size_t size, uint8_t basis);
uint32_t encrypt_challenge_time(uint16_t value);
uint16_t decrypt_challenge_time(uint32_t value);
std::string decrypt_challenge_rank_text(const char* data, size_t count);
std::string decrypt_challenge_rank_text(const std::string& data);
std::string encrypt_challenge_rank_text(const char* data, size_t count);
+8 -8
View File
@@ -333,13 +333,13 @@ struct PlayerRecordsDCPC_Challenge {
/* 00 */ le_uint16_t title_color = 0x7FFF;
/* 02 */ parray<uint8_t, 2> unknown_u0;
/* 04 */ ptext<CharT, 0x0C> rank_title; // Encrypted; see decrypt_challenge_rank_text
/* 10 */ parray<le_uint32_t, 9> times_ep1_online; // TODO: This might be offline times
/* 10 */ parray<le_uint32_t, 9> times_ep1_online; // Encrypted; see decrypt_challenge_time. TODO: This might be offline times
/* 34 */ le_uint16_t unknown_g3 = 0;
/* 36 */ le_uint16_t grave_deaths = 0;
/* 38 */ parray<le_uint32_t, 5> grave_coords_time;
/* 4C */ ptext<CharT, 0x14> grave_team;
/* 60 */ ptext<CharT, 0x18> grave_message;
/* 78 */ parray<le_uint32_t, 9> times_ep1_offline; // TODO: This might be online times
/* 78 */ parray<le_uint32_t, 9> times_ep1_offline; // Encrypted; see decrypt_challenge_time. TODO: This might be online times
/* 9C */ parray<uint8_t, 4> unknown_l4;
/* A0 */
} __attribute__((packed));
@@ -359,9 +359,9 @@ struct PlayerRecordsV3_Challenge {
// of save file structure
/* 0000:001C */ U16T title_color = 0x7FFF; // XRGB1555
/* 0002:001E */ parray<uint8_t, 2> unknown_u0;
/* 0004:0020 */ parray<U32T, 9> times_ep1_online;
/* 0028:0044 */ parray<U32T, 5> times_ep2_online;
/* 003C:0058 */ parray<U32T, 9> times_ep1_offline;
/* 0004:0020 */ parray<U32T, 9> times_ep1_online; // Encrypted; see decrypt_challenge_time
/* 0028:0044 */ parray<U32T, 5> times_ep2_online; // Encrypted; see decrypt_challenge_time
/* 003C:0058 */ parray<U32T, 9> times_ep1_offline; // Encrypted; see decrypt_challenge_time
/* 0060:007C */ parray<uint8_t, 4> unknown_g3;
/* 0064:0080 */ U16T grave_deaths = 0;
/* 0066:0082 */ parray<uint8_t, 2> unknown_u4;
@@ -378,9 +378,9 @@ struct PlayerRecordsV3_Challenge {
struct PlayerRecordsBB_Challenge {
/* 0000 */ le_uint16_t title_color = 0x7FFF; // XRGB1555
/* 0002 */ parray<uint8_t, 2> unknown_u0;
/* 0004 */ parray<le_uint32_t, 9> times_ep1_online;
/* 0028 */ parray<le_uint32_t, 5> times_ep2_online;
/* 003C */ parray<le_uint32_t, 9> times_ep1_offline;
/* 0004 */ parray<le_uint32_t, 9> times_ep1_online; // Encrypted; see decrypt_challenge_time
/* 0028 */ parray<le_uint32_t, 5> times_ep2_online; // Encrypted; see decrypt_challenge_time
/* 003C */ parray<le_uint32_t, 9> times_ep1_offline; // Encrypted; see decrypt_challenge_time
/* 0060 */ parray<uint8_t, 4> unknown_g3;
/* 0064 */ le_uint16_t grave_deaths = 0;
/* 0066 */ parray<uint8_t, 2> unknown_u4;
+1 -1
View File
@@ -725,7 +725,7 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
{0xF8B5, "write4", {REG, REG}, {}, V2, V2},
{0xF8B5, "write4", {}, {INT32, REG}, V3, V4},
{0xF8B6, "check_for_hacking", {REG}, {}, V2, V2}, // Returns a bitmask of 5 different types of detectable hacking. But it only works on DCv2 - it crashes on all other versions.
{0xF8B7, nullptr, {REG}, {}, V2, V4}, // TODO (DX) - Challenge mode. Appears to be timing-related; regA is expected to be in [60, 3600]. Encodes the value with some strange masking key, even though it's never sent over the network and is only decoded locally.
{0xF8B7, nullptr, {REG}, {}, V2, V4}, // TODO (DX) - Challenge mode. Appears to be timing-related; regA is expected to be in [60, 3600]. Encodes the value with encrypt_challenge_time even though it's never sent over the network and is only decrypted locally.
{0xF8B8, "disable_retry_menu", {}, {}, V2, V4},
{0xF8B9, "chl_recovery", {}, {}, V2, V4},
{0xF8BA, "load_guild_card_file_creation_time_to_flag_buf", {}, {}, V2, V4},