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 5288KB
stdin
Standard input is empty
stdout
int8_t:
checksum = 
00000000000000000000000001011101 + 
11010101110101010110111110000011 = 
11010101110101010110111111100000
ZtlSecureTear(42) = D5D56FE0
ZtlSecureFuse = 42

checksum = 
00000000000000000000000000111010 + 
10110101110101010110111110000101 = 
10110101110101010110111110111111
ZtlSecureTear(-127) = B5D56FBF
ZtlSecureFuse = -127

ZtlSecureFuse (invalid checksum) = 

int16_t:
checksum = 
00000000000000000000000001000011 + 
10001101110101010110111110000101 = 
10001101110101010110111111001000
checksum = 
00000000000000000000000010110000 + 
00111100011011101010101101111000 = 
00111100011011101010110000101000
ZtlSecureTear(32767) = 3C6EAC28
ZtlSecureFuse = 32767

checksum = 
00000000000000000000000011011011 + 
00000101110101010110111110000001 = 
00000101110101010111000001011100
checksum = 
00000000000000000000000001100001 + 
00010000001011101010101110000110 = 
00010000001011101010101111100111
ZtlSecureTear(-10) = 102EABE7
ZtlSecureFuse = -10

ZtlSecureFuse (invalid checksum) = 

int32_t:
checksum = 
01100110001101000000011110100010 + 
11000011111000010110100000001011 = 
00101010000101010110111110101101
ZtlSecureTear(1337) = 2A156FAD
ZtlSecureFuse = 1337

checksum = 
10000101110010010000011101101110 + 
10111000000111000110100011101111 = 
00111101111001010111000001011101
ZtlSecureTear(42) = 3DE5705D
ZtlSecureFuse = 42

ZtlSecureFuse (invalid checksum) = 

int64_t:
checksum = 
10110111100110010100001111011101 + 
10001110001001101100011001001000 = 
01000101110000000000101000100101
checksum = 
11000010111111011100001011101001 + 
11100000110100111100001010111000 = 
10100011110100011000010110100001
ZtlSecureTear(6666666666) = A3D185A1
ZtlSecureFuse = 6666666666

checksum = 
01110110100100111110100110001000 + 
10001100101000000111010000000101 = 
00000011001101000101110110001101
checksum = 
00010000110011100110010111100011 + 
01111000110101111100011100001111 = 
10001001101001100010110011110010
ZtlSecureTear(4242424242) = 89A62CF2
ZtlSecureFuse = 4242424242

ZtlSecureFuse (invalid checksum) = 

double:
checksum = 
10010111101010011010001010110111 + 
01110010100110011010110101110110 = 
00001010010000110101000000101101
checksum = 
00110001111100010100010011101011 + 
10001000010111001111010101001000 = 
10111010010011100011101000110011
ZtlSecureTear(1.337) = BA4E3A33
ZtlSecureFuse = 1.337

checksum = 
01011110100000111001101111011000 + 
11111110000000111110100100110000 = 
01011100100001111000010100001000
checksum = 
01001010010000100101011110011111 + 
01011010101000011110100110000010 = 
10100100111001000100000100100001
ZtlSecureTear(66666.7) = A4E44121
ZtlSecureFuse = 66666.7

ZtlSecureFuse (invalid checksum) =