describe DC save file formats; add decrypt/encrypt actions

This commit is contained in:
Martin Michelsen
2024-11-03 21:24:48 -08:00
parent ac20d0c7d4
commit 0522b539c4
22 changed files with 544 additions and 214 deletions
+81 -48
View File
@@ -2,6 +2,7 @@
#include <stdint.h>
#include <mutex>
#include <phosg/Random.hh>
#include <phosg/Strings.hh>
#include <phosg/Time.hh>
@@ -24,6 +25,7 @@ static const uint32_t primes1[] = {
0x313, 0x31D, 0x329, 0x32B, 0x335, 0x337, 0x33B, 0x33D, 0x347, 0x355, 0x359,
0x35B, 0x35F, 0x36D, 0x371, 0x373, 0x377, 0x38B, 0x38F, 0x397, 0x3A1, 0x3A9,
0x3AD, 0x3B3, 0x3B9, 0x3C7, 0x3CB, 0x3D1, 0x3D7, 0x3DF, 0x3E5};
static const uint32_t primes2[] = {
0x3F1, 0x3F5, 0x3FB, 0x3FD, 0x407, 0x409, 0x40F, 0x419, 0x41B, 0x425, 0x427,
0x42D, 0x43F, 0x443, 0x445, 0x449, 0x44F, 0x455, 0x45D, 0x463, 0x469, 0x47F,
@@ -135,6 +137,8 @@ static const uint32_t primes2[] = {
0x2627, 0x2629, 0x2635, 0x263B, 0x263F, 0x264B, 0x2653, 0x2659, 0x2665,
0x2669, 0x266F, 0x267B, 0x2681, 0x2683, 0x268F, 0x269B, 0x269F, 0x26AD,
0x26B3, 0x26C3, 0x26C9, 0x26CB, 0x26D5, 0x26DD, 0x26EF, 0x26F5};
static constexpr size_t num_primes2 = sizeof(primes2) / sizeof(primes2[0]);
static const uint32_t primes3[] = {
0x2717, 0x2719, 0x2735, 0x2737, 0x274D, 0x2753, 0x2755, 0x275F, 0x276B,
0x276D, 0x2773, 0x2777, 0x277F, 0x2795, 0x279B, 0x279D, 0x27A7, 0x27AF,
@@ -1107,15 +1111,19 @@ static const uint32_t primes3[] = {
0x18569, 0x1857B, 0x1857D, 0x18581, 0x18587, 0x18589, 0x18595, 0x185B1,
0x185B7, 0x185CB, 0x185D1, 0x185E1, 0x185E9, 0x185EF, 0x185F5, 0x185F9,
0x185FF, 0x18613, 0x1861F};
static constexpr size_t num_primes3 = sizeof(primes3) / sizeof(primes3[0]);
static bool check_prime3(uint64_t prime3) {
static vector<bool> primes3_set;
static mutex primes3_init_mutex;
if (primes3_set.empty()) {
size_t num_primes3 = sizeof(primes3) / sizeof(primes3[0]);
size_t primes3_set_size = primes3[num_primes3 - 1] - primes3[0] + 1;
primes3_set.resize(primes3_set_size, false);
for (size_t z = 0; z < num_primes3; z++) {
primes3_set[primes3[z] - primes3[0]] = true;
lock_guard g(primes3_init_mutex);
if (primes3_set.empty()) {
size_t primes3_set_size = primes3[num_primes3 - 1] - primes3[0] + 1;
primes3_set.resize(primes3_set_size, false);
for (size_t z = 0; z < num_primes3; z++) {
primes3_set[primes3[z] - primes3[0]] = true;
}
}
}
uint64_t offset = prime3 - primes3[0];
@@ -1227,8 +1235,8 @@ bool dc_serial_number_is_valid_slow(const string& s, uint8_t domain, uint8_t sub
}
for (; offset1 < limit1; offset1++) {
for (size_t offset2 = 0; offset2 < sizeof(primes2) / sizeof(primes2[0]); offset2++) {
for (size_t offset3 = 0; offset3 < sizeof(primes3) / sizeof(primes3[0]); offset3++) {
for (size_t offset2 = 0; offset2 < num_primes2; offset2++) {
for (size_t offset3 = 0; offset3 < num_primes3; offset3++) {
if (primes1[offset1] * primes2[offset2] * primes3[offset3] == serial_number) {
return true;
}
@@ -1251,7 +1259,7 @@ bool decoded_dc_serial_number_is_valid_fast(uint32_t serial_number, uint8_t doma
continue;
}
uint64_t sub1 = sub0 / primes1[offset1];
for (size_t offset2 = 0; offset2 < sizeof(primes2) / sizeof(primes2[0]); offset2++) {
for (size_t offset2 = 0; offset2 < num_primes2; offset2++) {
if (sub1 % primes2[offset2]) {
continue;
}
@@ -1293,8 +1301,8 @@ string generate_dc_serial_number(uint8_t domain, uint8_t subdomain) {
size_t det1 = (subdomain == 0xFF) ? phosg::random_object<uint32_t>() : subdomain;
size_t index1 = offset1 + (det1 % (limit1 - offset1));
size_t index2 = phosg::random_object<uint32_t>() % (sizeof(primes2) / sizeof(primes2[0]));
size_t index3 = phosg::random_object<uint32_t>() % (sizeof(primes3) / sizeof(primes3[0]));
size_t index2 = phosg::random_object<uint32_t>() % num_primes2;
size_t index3 = phosg::random_object<uint32_t>() % num_primes3;
uint32_t value = primes1[index1] * primes2[index2] * primes3[index3];
string s = phosg::string_printf("%08X", value);
@@ -1306,54 +1314,79 @@ string generate_dc_serial_number(uint8_t domain, uint8_t subdomain) {
}
unordered_map<uint32_t, string> generate_all_dc_serial_numbers(uint8_t domain, uint8_t subdomain) {
vector<uint8_t> domains;
if (domain == 0xFF) {
domains.emplace_back(0x00);
domains.emplace_back(0x01);
domains.emplace_back(0x02);
} else {
domains.emplace_back(domain);
DCSerialNumberIterator iter;
if (domain < 3) {
iter.domain = domain;
iter.end_domain = domain + 1;
} else if (domain != 0xFF) {
throw runtime_error("invalid domain");
}
vector<uint8_t> subdomains;
if (subdomain == 0xFF) {
subdomains.emplace_back(0x00);
subdomains.emplace_back(0x01);
subdomains.emplace_back(0x02);
} else {
subdomains.emplace_back(subdomain);
if (subdomain < 3) {
iter.subdomain = subdomain;
iter.start_subdomain = subdomain;
iter.end_subdomain = subdomain + 1;
} else if (subdomain != 0xFF) {
throw runtime_error("invalid subdomain");
}
uint32_t serial_number;
unordered_map<uint32_t, string> ret;
for (uint8_t domain : domains) {
size_t offset1, limit1;
if (domain == 0) {
offset1 = 0x00;
limit1 = 0x03;
} else if (domain == 1) {
offset1 = 0x1E;
limit1 = 0x21;
} else if (domain == 2) {
offset1 = 0x3C;
limit1 = 0x3F;
} else {
throw runtime_error("invalid domain");
}
for (uint8_t subdomain : subdomains) {
size_t index1 = offset1 + (subdomain % (limit1 - offset1));
for (size_t index2 = 0; index2 < sizeof(primes2) / sizeof(primes2[0]); index2++) {
for (size_t index3 = 0; index3 < sizeof(primes3) / sizeof(primes3[0]); index3++) {
uint32_t value = primes1[index1] * primes2[index2] * primes3[index3];
ret[encode_dc_serial_number_int(value)].push_back(((domain << 2) & 3) | (subdomain & 3));
}
fprintf(stderr, "... domain=%hhu subdomain=%hhu index2=%zu results=%zu (0x%zX)\n", domain, subdomain, index2, ret.size(), ret.size());
}
while ((serial_number = iter.next()) != 0) {
ret[serial_number].push_back(((iter.domain << 2) & 3) | (iter.subdomain & 3));
if (iter.index3 == 0) {
fprintf(stderr, "... (it) domain=%hhu subdomain=%hhu index2=%hu results=%zu (0x%zX)\n", iter.domain, iter.subdomain, iter.index2, ret.size(), ret.size());
}
}
return ret;
}
uint32_t DCSerialNumberIterator::next() {
if (!this->started) {
this->started = true;
} else if (!this->complete) {
this->index3++;
if (this->index3 >= num_primes3) {
this->index3 = 0;
this->index2++;
if (this->index2 >= num_primes2) {
this->index2 = 0;
this->subdomain++;
if (this->subdomain >= this->end_subdomain) {
this->subdomain = this->start_subdomain;
this->domain++;
if (this->domain >= this->end_domain) {
this->serial_number = 0;
this->complete = true;
}
}
}
}
}
if (!this->complete) {
size_t index1 = (30 * this->domain) + (this->subdomain % 3);
return encode_dc_serial_number_int(primes1[index1] * primes2[this->index2] * primes3[this->index3]);
} else {
return 0;
}
}
size_t DCSerialNumberIterator::total_count() const {
return (this->end_domain - this->start_domain) * (this->end_subdomain - this->start_subdomain) * num_primes2 * num_primes3;
}
size_t DCSerialNumberIterator::progress() const {
size_t domains_done = this->domain - this->start_domain;
size_t subdomains_per_domain = this->end_subdomain - this->start_subdomain;
size_t subdomains_done = this->subdomain - this->start_subdomain;
return (
(domains_done * subdomains_per_domain * num_primes2 * num_primes3) +
(subdomains_done * num_primes2 * num_primes3) +
(this->index2 * num_primes3) +
this->index3);
}
void dc_serial_number_speed_test(uint64_t seed) {
uint32_t effective_seed = (seed & 0xFFFFFFFF00000000) ? phosg::random_object<uint32_t>() : seed;
fprintf(stderr, "Product speed test with seed=%08" PRIX32 "\n", effective_seed);