#include <iostream>
#include <sstream>
#include <cstdint>
#include <random>
#include <string>
#include <iomanip>
#include <bitset>
using namespace std;
template<class T>
T __ROL__(T value, uint32_t count) {
const uint32_t nbits = sizeof(T)* 8;
count %= nbits;
T high = value >> (nbits - count);
value <<= count;
value |= high;
return value;
}
template<class T>
T __ROR__(T value, uint32_t count) {
const uint32_t nbits = sizeof(T)* 8;
count %= nbits;
T low = value << (nbits - count);
value >>= count;
value |= low;
return value;
}
class CRand32 {
public:
uint32_t Random() {
return dist(mt);
}
protected:
random_device rd;
mt19937 mt{ rd() };
uniform_int_distribution<uint32_t> dist;
};
CRand32 rnd;
class maple_exception : public exception {
protected:
int code;
public:
maple_exception(int code) : code(code) {};
~maple_exception() {};
const char *what() const throw() {
stringstream ss;
// TODO: get actual exception descriptions used by maplestory
ss << "MapleStory error " << code;
return ss.str().c_str();
};
};
template <class T, bool shortorbyte>
struct ZtlSecureImpl {
uint8_t key[sizeof(T)];
uint8_t encrypted_data[sizeof(T)];
} __attribute__((packed));
template <class T>
struct ZtlSecureImpl<T, false> {
uint32_t key[sizeof(T) / sizeof(uint32_t)];
uint32_t encrypted_data[sizeof(T) / sizeof(uint32_t)];
} __attribute__((packed));
template <class T>
struct ZtlSecure : ZtlSecureImpl<T, sizeof(T) <= 2> { } __attribute__((packed));
// set encrypted data
template <class T, bool shortorbyte>
struct ZtlSecureTearImpl {
static uint32_t call(T value, ZtlSecure<T> *p) {
auto pvalue = (uint8_t *)&value;
uint32_t checksum = 0xBAADF00D;
for (size_t i = 0; i < sizeof(T); i++) {
p->key[i] = (uint8_t)rnd.Random();
p->encrypted_data[i] = pvalue[i] ^ p->key[i];
bitset<32> a(p->encrypted_data[i]);
bitset<32> b(__ROR__(p->key[i] ^ checksum, 5));
checksum = p->encrypted_data[i] + __ROR__(p->key[i] ^ checksum, 5);
bitset<32> c(checksum);
cout << "checksum = " << endl << a << " + " << endl << b << " = " << endl << c << endl;
}
return checksum;
}
};
template <class T>
struct ZtlSecureTearImpl<T, false> {
static uint32_t call(T value, ZtlSecure<T> *p) {
auto pvalue = (uint32_t *)&value;
uint32_t checksum = 0xBAADF00D;
for (size_t i = 0; i < sizeof(T) / sizeof(uint32_t); i++) {
p->key[i] = rnd.Random();
p->encrypted_data[i] = __ROR__(pvalue[i] ^ p->key[i], 5);
bitset<32> a(p->encrypted_data[i]);
bitset<32> b(__ROR__(p->key[i] ^ checksum, 5));
checksum = p->encrypted_data[i] + __ROR__(p->key[i] ^ checksum, 5);
bitset<32> c(checksum);
cout << "checksum = " << endl << a << " + " << endl << b << " = " << endl << c << endl;
}
return checksum;
}
};
template <class T>
uint32_t ZtlSecureTear(T value, ZtlSecure<T> *p) {
return ZtlSecureTearImpl<T, sizeof(T) <= sizeof(uint16_t)>::call(value, p);
}
// get encrypted data and check validity
template <class T, bool shortorbyte>
struct ZtlSecureFuseImpl {
static T call(ZtlSecure<T> *p, uint32_t expected_checksum) {
uint32_t checksum = 0xBAADF00D;
uint8_t value[sizeof(T)] = { 0 };
for (size_t i = 0; i < sizeof(T); i++) {
value[i] = p->key[i] ^ p->encrypted_data[i];
checksum = p->encrypted_data[i] + __ROR__(p->key[i] ^ checksum, 5);
}
if (expected_checksum != checksum) {
throw maple_exception(5);
}
return *(T *)&value[0];
}
};
template <class T>
struct ZtlSecureFuseImpl<T, false> {
static T call(ZtlSecure<T> *p, uint32_t expected_checksum) {
uint32_t checksum = 0xBAADF00D;
uint32_t value[sizeof(T) / sizeof(uint32_t)] = { 0 };
for (size_t i = 0; i < sizeof(T) / sizeof(uint32_t); i++) {
value[i] = p->key[i] ^ __ROL__(p->encrypted_data[i], 5);
checksum = p->encrypted_data[i] + __ROR__(p->key[i] ^ checksum, 5);
}
if (expected_checksum != checksum) {
throw maple_exception(5);
}
return *(T *)&value[0];
}
};
template <class T>
T ZtlSecureFuse(ZtlSecure<T> *p, uint32_t expected_checksum) {
return ZtlSecureFuseImpl<T, sizeof(T) <= sizeof(uint16_t)>::call(p, expected_checksum);
}
string fmthex(uint32_t value, int width = 8) {
stringstream sshex;
sshex << hex << uppercase << setw(width) << setfill('0') << value;
return sshex.str();
}
template<class T>
void runtest(const char *tname, T a, T b) {
try {
cout << tname << ":" << endl;
ZtlSecure<T> sec;
uint32_t check = ZtlSecureTear<T>(a, &sec);
uint32_t oldcheck = check;
cout << "ZtlSecureTear(" << +a << ") = " << fmthex(check) << endl;
cout << "ZtlSecureFuse = " << +ZtlSecureFuse<T>(&sec, check) << endl;
cout << endl;
check = ZtlSecureTear<T>(b, &sec);
cout << "ZtlSecureTear(" << +b << ") = " << fmthex(check) << endl;
cout << "ZtlSecureFuse = " << +ZtlSecureFuse<T>(&sec, check) << endl;
cout << endl;
cout << "ZtlSecureFuse (invalid checksum) = ";
cout << +ZtlSecureFuse<T>(&sec, oldcheck) << endl;
}
catch (const std::exception &e) {
cout << e.what() << endl;
}
cout << endl;
}
int main() {
runtest<int8_t>("int8_t", 42, -127);
runtest<int16_t>("int16_t", 32767, -10);
runtest<int32_t>("int32_t", 1337, 42);
runtest<int64_t>("int64_t", 6666666666, 4242424242);
runtest<double>("double", 1.337, 66666.66666);
return 0;
}