fork download
  1. #include <iostream>
  2. #include <sstream>
  3. #include <cstdint>
  4. #include <random>
  5. #include <string>
  6. #include <iomanip>
  7. #include <bitset>
  8. using namespace std;
  9.  
  10. template<class T>
  11. T __ROL__(T value, uint32_t count) {
  12. const uint32_t nbits = sizeof(T)* 8;
  13. count %= nbits;
  14.  
  15. T high = value >> (nbits - count);
  16. value <<= count;
  17. value |= high;
  18. return value;
  19. }
  20.  
  21. template<class T>
  22. T __ROR__(T value, uint32_t count) {
  23. const uint32_t nbits = sizeof(T)* 8;
  24. count %= nbits;
  25.  
  26. T low = value << (nbits - count);
  27. value >>= count;
  28. value |= low;
  29. return value;
  30. }
  31.  
  32. class CRand32 {
  33. public:
  34. uint32_t Random() {
  35. return dist(mt);
  36. }
  37.  
  38. protected:
  39. random_device rd;
  40. mt19937 mt{ rd() };
  41. uniform_int_distribution<uint32_t> dist;
  42. };
  43.  
  44. CRand32 rnd;
  45.  
  46. class maple_exception : public exception {
  47. protected:
  48. int code;
  49.  
  50. public:
  51. maple_exception(int code) : code(code) {};
  52. ~maple_exception() {};
  53. const char *what() const throw() {
  54. stringstream ss;
  55. // TODO: get actual exception descriptions used by maplestory
  56. ss << "MapleStory error " << code;
  57. return ss.str().c_str();
  58. };
  59. };
  60.  
  61. template <class T, bool shortorbyte>
  62. struct ZtlSecureImpl {
  63. uint8_t key[sizeof(T)];
  64. uint8_t encrypted_data[sizeof(T)];
  65. } __attribute__((packed));
  66.  
  67. template <class T>
  68. struct ZtlSecureImpl<T, false> {
  69. uint32_t key[sizeof(T) / sizeof(uint32_t)];
  70. uint32_t encrypted_data[sizeof(T) / sizeof(uint32_t)];
  71. } __attribute__((packed));
  72.  
  73. template <class T>
  74. struct ZtlSecure : ZtlSecureImpl<T, sizeof(T) <= 2> { } __attribute__((packed));
  75.  
  76. // set encrypted data
  77. template <class T, bool shortorbyte>
  78. struct ZtlSecureTearImpl {
  79. static uint32_t call(T value, ZtlSecure<T> *p) {
  80. auto pvalue = (uint8_t *)&value;
  81. uint32_t checksum = 0xBAADF00D;
  82. for (size_t i = 0; i < sizeof(T); i++) {
  83. p->key[i] = (uint8_t)rnd.Random();
  84. p->encrypted_data[i] = pvalue[i] ^ p->key[i];
  85. bitset<32> a(p->encrypted_data[i]);
  86. bitset<32> b(__ROR__(p->key[i] ^ checksum, 5));
  87. checksum = p->encrypted_data[i] + __ROR__(p->key[i] ^ checksum, 5);
  88. bitset<32> c(checksum);
  89. cout << "checksum = " << endl << a << " + " << endl << b << " = " << endl << c << endl;
  90. }
  91. return checksum;
  92. }
  93. };
  94.  
  95. template <class T>
  96. struct ZtlSecureTearImpl<T, false> {
  97. static uint32_t call(T value, ZtlSecure<T> *p) {
  98. auto pvalue = (uint32_t *)&value;
  99. uint32_t checksum = 0xBAADF00D;
  100. for (size_t i = 0; i < sizeof(T) / sizeof(uint32_t); i++) {
  101. p->key[i] = rnd.Random();
  102. p->encrypted_data[i] = __ROR__(pvalue[i] ^ p->key[i], 5);
  103. bitset<32> a(p->encrypted_data[i]);
  104. bitset<32> b(__ROR__(p->key[i] ^ checksum, 5));
  105. checksum = p->encrypted_data[i] + __ROR__(p->key[i] ^ checksum, 5);
  106. bitset<32> c(checksum);
  107. cout << "checksum = " << endl << a << " + " << endl << b << " = " << endl << c << endl;
  108. }
  109. return checksum;
  110. }
  111. };
  112.  
  113. template <class T>
  114. uint32_t ZtlSecureTear(T value, ZtlSecure<T> *p) {
  115. return ZtlSecureTearImpl<T, sizeof(T) <= sizeof(uint16_t)>::call(value, p);
  116. }
  117.  
  118. // get encrypted data and check validity
  119. template <class T, bool shortorbyte>
  120. struct ZtlSecureFuseImpl {
  121. static T call(ZtlSecure<T> *p, uint32_t expected_checksum) {
  122. uint32_t checksum = 0xBAADF00D;
  123. uint8_t value[sizeof(T)] = { 0 };
  124. for (size_t i = 0; i < sizeof(T); i++) {
  125. value[i] = p->key[i] ^ p->encrypted_data[i];
  126. checksum = p->encrypted_data[i] + __ROR__(p->key[i] ^ checksum, 5);
  127. }
  128. if (expected_checksum != checksum) {
  129. throw maple_exception(5);
  130. }
  131. return *(T *)&value[0];
  132. }
  133. };
  134.  
  135. template <class T>
  136. struct ZtlSecureFuseImpl<T, false> {
  137. static T call(ZtlSecure<T> *p, uint32_t expected_checksum) {
  138. uint32_t checksum = 0xBAADF00D;
  139. uint32_t value[sizeof(T) / sizeof(uint32_t)] = { 0 };
  140. for (size_t i = 0; i < sizeof(T) / sizeof(uint32_t); i++) {
  141. value[i] = p->key[i] ^ __ROL__(p->encrypted_data[i], 5);
  142. checksum = p->encrypted_data[i] + __ROR__(p->key[i] ^ checksum, 5);
  143. }
  144. if (expected_checksum != checksum) {
  145. throw maple_exception(5);
  146. }
  147. return *(T *)&value[0];
  148. }
  149. };
  150.  
  151. template <class T>
  152. T ZtlSecureFuse(ZtlSecure<T> *p, uint32_t expected_checksum) {
  153. return ZtlSecureFuseImpl<T, sizeof(T) <= sizeof(uint16_t)>::call(p, expected_checksum);
  154. }
  155.  
  156. string fmthex(uint32_t value, int width = 8) {
  157. stringstream sshex;
  158. sshex << hex << uppercase << setw(width) << setfill('0') << value;
  159. return sshex.str();
  160. }
  161.  
  162. template<class T>
  163. void runtest(const char *tname, T a, T b) {
  164. try {
  165. cout << tname << ":" << endl;
  166.  
  167. ZtlSecure<T> sec;
  168. uint32_t check = ZtlSecureTear<T>(a, &sec);
  169. uint32_t oldcheck = check;
  170. cout << "ZtlSecureTear(" << +a << ") = " << fmthex(check) << endl;
  171. cout << "ZtlSecureFuse = " << +ZtlSecureFuse<T>(&sec, check) << endl;
  172. cout << endl;
  173.  
  174. check = ZtlSecureTear<T>(b, &sec);
  175. cout << "ZtlSecureTear(" << +b << ") = " << fmthex(check) << endl;
  176. cout << "ZtlSecureFuse = " << +ZtlSecureFuse<T>(&sec, check) << endl;
  177. cout << endl;
  178.  
  179. cout << "ZtlSecureFuse (invalid checksum) = ";
  180. cout << +ZtlSecureFuse<T>(&sec, oldcheck) << endl;
  181. }
  182. catch (const std::exception &e) {
  183. cout << e.what() << endl;
  184. }
  185.  
  186. cout << endl;
  187. }
  188.  
  189. int main() {
  190. runtest<int8_t>("int8_t", 42, -127);
  191. runtest<int16_t>("int16_t", 32767, -10);
  192. runtest<int32_t>("int32_t", 1337, 42);
  193. runtest<int64_t>("int64_t", 6666666666, 4242424242);
  194. runtest<double>("double", 1.337, 66666.66666);
  195. return 0;
  196. }
Success #stdin #stdout 0.01s 5272KB
stdin
Standard input is empty
stdout
int8_t:
checksum = 
00000000000000000000000011111110 + 
11001101110101010110111110000110 = 
11001101110101010111000010000100
ZtlSecureTear(42) = CDD57084
ZtlSecureFuse = 42

checksum = 
00000000000000000000000000000000 + 
01100101110101010110111110000100 = 
01100101110101010110111110000100
ZtlSecureTear(-127) = 65D56F84
ZtlSecureFuse = -127

ZtlSecureFuse (invalid checksum) = 

int16_t:
checksum = 
00000000000000000000000011010100 + 
00110101110101010110111110000001 = 
00110101110101010111000001010101
checksum = 
00000000000000000000000000101000 + 
00010001101011101010101110000000 = 
00010001101011101010101110101000
ZtlSecureTear(32767) = 11AEABA8
ZtlSecureFuse = 32767

checksum = 
00000000000000000000000010010110 + 
01101101110101010110111110000011 = 
01101101110101010111000000011001
checksum = 
00000000000000000000000010000011 + 
00101011011011101010101110000011 = 
00101011011011101010110000000110
ZtlSecureTear(-10) = 2B6EAC06
ZtlSecureFuse = -10

ZtlSecureFuse (invalid checksum) = 

int32_t:
checksum = 
01010110101010101010110011100110 + 
11110011011111111100001101001111 = 
01001010001010100111000000110101
ZtlSecureTear(1337) = 4A2A7035
ZtlSecureFuse = 1337

checksum = 
01001001001101001000101100010001 + 
01110100111000011110010010010000 = 
10111110000101100110111110100001
ZtlSecureTear(42) = BE166FA1
ZtlSecureFuse = 42

ZtlSecureFuse (invalid checksum) = 

int64_t:
checksum = 
01100100011111010111100010100000 + 
01011101110000101111110100110101 = 
11000010010000000111010111010101
checksum = 
10101100100001111011011101100001 + 
00001010100101011011010011001111 = 
10110111000111010110110000110000
ZtlSecureTear(6666666666) = B71D6C30
ZtlSecureFuse = 6666666666

checksum = 
10011111001110011111100011011000 + 
01100101000010100110010101010101 = 
00000100010001000101111000101101
checksum = 
00110001100101011110011000101010 + 
01011001101101111100010011011011 = 
10001011010011011010101100000101
ZtlSecureTear(4242424242) = 8B4DAB05
ZtlSecureFuse = 4242424242

ZtlSecureFuse (invalid checksum) = 

double:
checksum = 
01001100100110110101010110111110 + 
10101001101010110101101001111111 = 
11110110010001101011000000111101
checksum = 
10010011111111010000000101101011 + 
10101101101100001001111111001000 = 
01000001101011011010000100110011
ZtlSecureTear(1.337) = 41ADA133
ZtlSecureFuse = 1.337

checksum = 
01111001010011010100110000011110 + 
11011001110011010011111011110110 = 
01010011000110101000101100010100
checksum = 
11001100000000001100101000000101 + 
00111100100111111001110001101000 = 
00001000101000000110011001101101
ZtlSecureTear(66666.7) = 08A0666D
ZtlSecureFuse = 66666.7

ZtlSecureFuse (invalid checksum) =