Otclient  14/8/2020
crypt.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 #include "crypt.h"
24 #include <framework/stdext/math.h>
25 #include <framework/core/logger.h>
29 
30 #include <boost/uuid/uuid_generators.hpp>
31 #include <boost/uuid/uuid_io.hpp>
32 
33 #include <boost/functional/hash.hpp>
34 
35 #ifndef USE_GMP
36 #include <openssl/rsa.h>
37 #include <openssl/bn.h>
38 #include <openssl/err.h>
39 #endif
40 
41 static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
42 static inline bool is_base64(unsigned char c) { return (isalnum(c) || (c == '+') || (c == '/')); }
43 
45 
47 {
48 #ifdef USE_GMP
49  mpz_init(m_p);
50  mpz_init(m_q);
51  mpz_init(m_d);
52  mpz_init(m_e);
53  mpz_init(m_n);
54 #else
55  m_rsa = RSA_new();
56 #endif
57 }
58 
60 {
61 #ifdef USE_GMP
62  mpz_clear(m_p);
63  mpz_clear(m_q);
64  mpz_clear(m_n);
65  mpz_clear(m_d);
66  mpz_clear(m_e);
67 #else
68  RSA_free(m_rsa);
69 #endif
70 }
71 
72 std::string Crypt::base64Encode(const std::string& decoded_string)
73 {
74  std::string ret;
75  int i = 0;
76  int j = 0;
77  uint8 char_array_3[3];
78  uint8 char_array_4[4];
79  int pos = 0;
80  int len = decoded_string.size();
81 
82  while(len--) {
83  char_array_3[i++] = decoded_string[pos++];
84  if(i == 3) {
85  char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
86  char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
87  char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
88  char_array_4[3] = char_array_3[2] & 0x3f;
89 
90  for(i = 0; (i <4) ; i++)
91  ret += base64_chars[char_array_4[i]];
92  i = 0;
93  }
94  }
95 
96  if(i) {
97  for(j = i; j < 3; j++)
98  char_array_3[j] = '\0';
99 
100  char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
101  char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
102  char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
103  char_array_4[3] = char_array_3[2] & 0x3f;
104 
105  for(j = 0; (j < i + 1); j++)
106  ret += base64_chars[char_array_4[j]];
107 
108  while((i++ < 3))
109  ret += '=';
110  }
111 
112  return ret;
113 }
114 
115 std::string Crypt::base64Decode(const std::string& encoded_string)
116 {
117  int len = encoded_string.size();
118  int i = 0;
119  int j = 0;
120  int in_ = 0;
121  uint8 char_array_4[4], char_array_3[3];
122  std::string ret;
123 
124  while(len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
125  char_array_4[i++] = encoded_string[in_]; in_++;
126  if(i ==4) {
127  for(i = 0; i <4; i++)
128  char_array_4[i] = base64_chars.find(char_array_4[i]);
129 
130  char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
131  char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
132  char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
133 
134  for(i = 0; (i < 3); i++)
135  ret += char_array_3[i];
136  i = 0;
137  }
138  }
139 
140  if(i) {
141  for(j = i; j <4; j++)
142  char_array_4[j] = 0;
143 
144  for(j = 0; j <4; j++)
145  char_array_4[j] = base64_chars.find(char_array_4[j]);
146 
147  char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
148  char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
149  char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
150 
151  for(j = 0; (j < i - 1); j++)
152  ret += char_array_3[j];
153  }
154 
155  return ret;
156 }
157 
158 std::string Crypt::xorCrypt(const std::string& buffer, const std::string& key)
159 {
160  std::string out;
161  out.resize(buffer.size());
162  size_t i, j=0;
163  for(i=0;i<buffer.size();++i) {
164  out[i] = buffer[i] ^ key[j++];
165  if(j >= key.size())
166  j = 0;
167  }
168  return out;
169 }
170 
171 std::string Crypt::genUUID()
172 {
173  boost::uuids::random_generator gen;
174  boost::uuids::uuid u = gen();
175  return boost::uuids::to_string(u);
176 }
177 
178 bool Crypt::setMachineUUID(std::string uuidstr)
179 {
180  if(uuidstr.empty())
181  return false;
182  uuidstr = _decrypt(uuidstr, false);
183  if(uuidstr.length() != 16)
184  return false;
185  std::copy(uuidstr.begin(), uuidstr.end(), m_machineUUID.begin());
186  return true;
187 }
188 
190 {
191  if(m_machineUUID.is_nil()) {
192  boost::uuids::random_generator gen;
193  m_machineUUID = gen();
194  }
195  return _encrypt(std::string(m_machineUUID.begin(), m_machineUUID.end()), false);
196 }
197 
198 std::string Crypt::getCryptKey(bool useMachineUUID)
199 {
200  boost::hash<boost::uuids::uuid> uuid_hasher;
201  boost::uuids::uuid uuid;
202  if(useMachineUUID) {
203  uuid = m_machineUUID;
204  } else {
205  boost::uuids::nil_generator nilgen;
206  uuid = nilgen();
207  }
208  boost::uuids::name_generator namegen(uuid);
209  boost::uuids::uuid u = namegen(g_app.getCompactName() + g_platform.getCPUName() + g_platform.getOSName() + g_resources.getUserDir());
210  std::size_t hash = uuid_hasher(u);
211  std::string key;
212  key.assign((const char *)&hash, sizeof(hash));
213  return key;
214 }
215 
216 std::string Crypt::_encrypt(const std::string& decrypted_string, bool useMachineUUID)
217 {
218  std::string tmp = "0000" + decrypted_string;
219  uint32 sum = stdext::adler32((const uint8*)decrypted_string.c_str(), decrypted_string.size());
220  stdext::writeULE32((uint8*)&tmp[0], sum);
221  std::string encrypted = base64Encode(xorCrypt(tmp, getCryptKey(useMachineUUID)));
222  return encrypted;
223 }
224 
225 std::string Crypt::_decrypt(const std::string& encrypted_string, bool useMachineUUID)
226 {
227  std::string decoded = base64Decode(encrypted_string);
228  std::string tmp = xorCrypt(decoded, getCryptKey(useMachineUUID));
229  if(tmp.length() >= 4) {
230  uint32 readsum = stdext::readULE32((const uint8*)tmp.c_str());
231  std::string decrypted_string = tmp.substr(4);
232  uint32 sum = stdext::adler32((const uint8*)decrypted_string.c_str(), decrypted_string.size());
233  if(readsum == sum)
234  return decrypted_string;
235  }
236  return std::string();
237 }
238 
239 void Crypt::rsaSetPublicKey(const std::string& n, const std::string& e)
240 {
241 #ifdef USE_GMP
242  mpz_set_str(m_n, n.c_str(), 10);
243  mpz_set_str(m_e, e.c_str(), 10);
244 #else
245 #if OPENSSL_VERSION_NUMBER < 0x10100005L
246  BN_dec2bn(&m_rsa->n, n.c_str());
247  BN_dec2bn(&m_rsa->e, e.c_str());
248  // clear rsa cache
249  if(m_rsa->_method_mod_n) {
250  BN_MONT_CTX_free(m_rsa->_method_mod_n);
251  m_rsa->_method_mod_n = nullptr;
252  }
253 #else
254  BIGNUM *bn = nullptr, *be = nullptr;
255  BN_dec2bn(&bn, n.c_str());
256  BN_dec2bn(&be, e.c_str());
257  RSA_set0_key(m_rsa, bn, be, nullptr);
258 #endif
259 #endif
260 }
261 
262 void Crypt::rsaSetPrivateKey(const std::string& p, const std::string& q, const std::string& d)
263 {
264 #ifdef USE_GMP
265  mpz_set_str(m_p, p.c_str(), 10);
266  mpz_set_str(m_q, q.c_str(), 10);
267  mpz_set_str(m_d, d.c_str(), 10);
268 
269  // n = p * q
270  mpz_mul(n, p, q);
271 #else
272 #if OPENSSL_VERSION_NUMBER < 0x10100005L
273  BN_dec2bn(&m_rsa->p, p.c_str());
274  BN_dec2bn(&m_rsa->q, q.c_str());
275  BN_dec2bn(&m_rsa->d, d.c_str());
276  // clear rsa cache
277  if(m_rsa->_method_mod_p) {
278  BN_MONT_CTX_free(m_rsa->_method_mod_p);
279  m_rsa->_method_mod_p = nullptr;
280  }
281  if(m_rsa->_method_mod_q) {
282  BN_MONT_CTX_free(m_rsa->_method_mod_q);
283  m_rsa->_method_mod_q = nullptr;
284  }
285 #else
286  BIGNUM *bp = nullptr, *bq = nullptr, *bd = nullptr;
287  BN_dec2bn(&bp, p.c_str());
288  BN_dec2bn(&bq, q.c_str());
289  BN_dec2bn(&bd, d.c_str());
290  RSA_set0_key(m_rsa, nullptr, nullptr, bd);
291  RSA_set0_factors(m_rsa, bp, bq);
292 #endif
293 #endif
294 }
295 
296 bool Crypt::rsaEncrypt(unsigned char *msg, int size)
297 {
298  if(size != rsaGetSize())
299  return false;
300 
301 #ifdef USE_GMP
302  mpz_t c, m;
303  mpz_init(c);
304  mpz_init(m);
305  mpz_import(m, size, 1, 1, 0, 0, msg);
306 
307  // c = m^e mod n
308  mpz_powm(c, m, m_e, m_n);
309 
310  size_t count = (mpz_sizeinbase(m, 2) + 7) / 8;
311  memset((char*)msg, 0, size - count);
312  mpz_export((char*)msg + (size - count), nullptr, 1, 1, 0, 0, c);
313 
314  mpz_clear(c);
315  mpz_clear(m);
316 
317  return true;
318 #else
319  return RSA_public_encrypt(size, msg, msg, m_rsa, RSA_NO_PADDING) != -1;
320 #endif
321 }
322 
323 bool Crypt::rsaDecrypt(unsigned char *msg, int size)
324 {
325  if(size != rsaGetSize())
326  return false;
327 
328 #ifdef USE_GMP
329  mpz_t c, m;
330  mpz_init(c);
331  mpz_init(m);
332  mpz_import(c, size, 1, 1, 0, 0, msg);
333 
334  // m = c^d mod n
335  mpz_powm(m, c, m_d, m_n);
336 
337  size_t count = (mpz_sizeinbase(m, 2) + 7) / 8;
338  memset((char*)msg, 0, size - count);
339  mpz_export((char*)msg + (size - count), nullptr, 1, 1, 0, 0, m);
340 
341  mpz_clear(c);
342  mpz_clear(m);
343 
344  return true;
345 #else
346  return RSA_private_decrypt(size, msg, msg, m_rsa, RSA_NO_PADDING) != -1;
347 #endif
348 }
349 
351 {
352 #ifdef USE_GMP
353  size_t count = (mpz_sizeinbase(m_n, 2) + 7) / 8;
354  return ((int)count / 128) * 128;
355 #else
356  return RSA_size(m_rsa);
357 #endif
358 }
Platform::getCPUName
std::string getCPUName()
Definition: unixplatform.cpp:127
Crypt::rsaSetPrivateKey
void rsaSetPrivateKey(const std::string &p, const std::string &q, const std::string &d)
Definition: crypt.cpp:262
logger.h
Crypt::rsaEncrypt
bool rsaEncrypt(unsigned char *msg, int size)
Definition: crypt.cpp:296
Application::getCompactName
const std::string & getCompactName()
Definition: application.h:52
g_crypt
Crypt g_crypt
Definition: crypt.cpp:44
uint32
uint32_t uint32
Definition: types.h:35
Crypt::base64Decode
std::string base64Decode(const std::string &encoded_string)
Definition: crypt.cpp:115
Platform::getOSName
std::string getOSName()
Definition: unixplatform.cpp:159
Crypt::rsaGetSize
int rsaGetSize()
Definition: crypt.cpp:350
resourcemanager.h
Crypt::Crypt
Crypt()
Definition: crypt.cpp:46
Crypt::xorCrypt
std::string xorCrypt(const std::string &buffer, const std::string &key)
Definition: crypt.cpp:158
Crypt::rsaSetPublicKey
void rsaSetPublicKey(const std::string &n, const std::string &e)
Definition: crypt.cpp:239
Crypt::getMachineUUID
std::string getMachineUUID()
Definition: crypt.cpp:189
crypt.h
math.h
g_resources
ResourceManager g_resources
Definition: resourcemanager.cpp:32
stdext::writeULE32
void writeULE32(uchar *addr, uint32_t value)
Definition: math.h:39
Crypt::setMachineUUID
bool setMachineUUID(std::string uuidstr)
Definition: crypt.cpp:178
Crypt::~Crypt
~Crypt()
Definition: crypt.cpp:59
platform.h
stdext::adler32
uint32_t adler32(const uint8_t *buffer, size_t size)
Definition: math.cpp:32
g_app
ConsoleApplication g_app
Definition: consoleapplication.cpp:32
stdext::to_string
std::string to_string(const T &t)
Definition: string.h:35
Crypt::rsaDecrypt
bool rsaDecrypt(unsigned char *msg, int size)
Definition: crypt.cpp:323
Crypt::base64Encode
std::string base64Encode(const std::string &decoded_string)
Definition: crypt.cpp:72
Crypt
Definition: crypt.h:36
Crypt::genUUID
std::string genUUID()
Definition: crypt.cpp:171
stdext::readULE32
uint32_t readULE32(const uchar *addr)
Definition: math.h:35
uint8
uint8_t uint8
Definition: types.h:37
ResourceManager::getUserDir
std::string getUserDir()
Definition: resourcemanager.cpp:347
application.h
g_platform
Platform g_platform
Definition: platform.cpp:25