1 /*
2 * Copyright 2013 Vitaly Valtman
3 * Copyright 2014 Canonical Ltd.
4 * Authors:
5 * Roberto Mier
6 * Tiago Herrmann
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 3.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "utils.h"
23 #include <openssl/rand.h>
24 #include <openssl/pem.h>
25 #include <openssl/err.h>
26 #include <zlib.h>
27 #if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
28 #include <sys/utsname.h>
29 #endif
30
31 #include <QDebug>
32 #include <QEventLoop>
33 #include <QtMultimedia/QMediaPlayer>
34 #include <QtMultimedia/QMediaContent>
35 #include <QtMultimedia/QMediaResource>
36 #include <QProcess>
37 #include <QStringList>
38 #include <QtCore>
39
40
41 Q_LOGGING_CATEGORY(TG_UTIL_UTILS, "tg.util.utils")
42
43 #if defined(Q_OS_MAC)
44 #include <sys/time.h>
45 //clock_gettime is not implemented on OSX
clock_gettime(int,struct timespec * t)46 int clock_gettime(int /*clk_id*/, struct timespec* t) {
47 struct timeval now;
48 int rv = gettimeofday(&now, NULL);
49 if (rv) return rv;
50 t->tv_sec = now.tv_sec;
51 t->tv_nsec = now.tv_usec * 1000;
52 return 0;
53 }
54 #elif defined(Q_OS_WIN)
55 //clock_gettime is not implemented on Win
56 // took from https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows
57
58 #ifdef Q_CC_MSVC
59 struct timespec {
60 long int tv_sec; /* Seconds. */
61 long int tv_nsec; /* Nanoseconds. */
62 };
63 #endif
64
65 LARGE_INTEGER getFILETIMEoffset()
66 {
67 SYSTEMTIME s;
68 FILETIME f;
69 LARGE_INTEGER t;
70
71 s.wYear = 1970;
72 s.wMonth = 1;
73 s.wDay = 1;
74 s.wHour = 0;
75 s.wMinute = 0;
76 s.wSecond = 0;
77 s.wMilliseconds = 0;
78 SystemTimeToFileTime(&s, &f);
79 t.QuadPart = f.dwHighDateTime;
80 t.QuadPart <<= 32;
81 t.QuadPart |= f.dwLowDateTime;
82 return (t);
83 }
84
85 int clock_gettime(int /*X*/, struct timespec *ts)
86 {
87 LARGE_INTEGER t;
88 FILETIME f;
89 double nanoseconds;
90 static LARGE_INTEGER offset;
91 static double frequencyToNanoseconds;
92 static int initialized = 0;
93 static BOOL usePerformanceCounter = 0;
94
95 if (!initialized) {
96 LARGE_INTEGER performanceFrequency;
97 initialized = 1;
98 usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
99 if (usePerformanceCounter) {
100 QueryPerformanceCounter(&offset);
101 frequencyToNanoseconds = (double)performanceFrequency.QuadPart / 1000.;
102 } else {
103 offset = getFILETIMEoffset();
104 frequencyToNanoseconds = 0.010;
105 }
106 }
107 if (usePerformanceCounter) {
108 QueryPerformanceCounter(&t);
109 }
110 else {
111 GetSystemTimeAsFileTime(&f);
112 t.QuadPart = f.dwHighDateTime;
113 t.QuadPart <<= 32;
114 t.QuadPart |= f.dwLowDateTime;
115 }
116
117 t.QuadPart -= offset.QuadPart;
118 nanoseconds = (double)t.QuadPart / frequencyToNanoseconds;
119 t.QuadPart = nanoseconds;
120 ts->tv_sec = t.QuadPart / 1000000000;
121 ts->tv_nsec = t.QuadPart % 1000000000;
122
123 return (0);
124 }
125 #endif
126
Utils(QObject * parent)127 Utils::Utils(QObject *parent) :
128 QObject(parent)
129 {
130 }
131
randomBytes(void * buffer,qint32 count)132 qint32 Utils::randomBytes(void *buffer, qint32 count) {
133 qint32 returnValue = RAND_bytes ((uchar *)buffer, count);
134 if (returnValue < 0) {
135 returnValue = RAND_pseudo_bytes ((uchar *)buffer, count);
136 }
137 return returnValue;
138 }
139
serializeBignum(const BIGNUM * b,char * buffer,qint32 maxlen)140 qint32 Utils::serializeBignum(const BIGNUM *b, char *buffer, qint32 maxlen) {
141 qint32 itslen = BN_num_bytes (b);
142 qint32 reqlen;
143 if (itslen < 254) {
144 reqlen = itslen + 1;
145 } else {
146 reqlen = itslen + 4;
147 }
148 qint32 newlen = (reqlen + 3) & -4;
149 qint32 pad = newlen - reqlen;
150 reqlen = newlen;
151 if (reqlen > maxlen) {
152 return -reqlen;
153 }
154 if (itslen < 254) {
155 *buffer++ = itslen;
156 } else {
157 *(qint32 *)buffer = (itslen << 8) + 0xfe;
158 buffer += 4;
159 }
160 qint32 l = BN_bn2bin (b, (uchar *)buffer);
161 Q_ASSERT (l == itslen);
162 buffer += l;
163 while (pad --> 0) {
164 *buffer++ = 0;
165 }
166 return reqlen;
167 }
168
getUTime(qint32 clockId)169 double Utils::getUTime(qint32 clockId) {
170 struct timespec T;
171 qint32 success = clock_gettime(clockId, &T);
172 Q_UNUSED(success);
173 Q_ASSERT(success == 0);
174 double res = T.tv_sec + (double) T.tv_nsec * 1e-9;
175 return res;
176 }
177
gcd(quint64 a,quint64 b)178 quint64 Utils::gcd(quint64 a, quint64 b) {
179 return b ? gcd (b, a % b) : a;
180 }
181
check_g(uchar p[256],BIGNUM * g)182 qint32 Utils::check_g (uchar p[256], BIGNUM *g) {
183 static uchar s[256];
184 memset (s, 0, 256);
185 Q_ASSERT(BN_num_bytes (g) <= 256);
186 BN_bn2bin (g, s);
187 qint32 ok = 0;
188 qint32 i;
189 for (i = 0; i < 64; i++) {
190 if (s[i]) {
191 ok = 1;
192 break;
193 }
194 }
195 if (!ok) { return -1; }
196 ok = 0;
197 for (i = 0; i < 64; i++) {
198 if (s[255 - i]) {
199 ok = 1;
200 break;
201 }
202 }
203 if (!ok) { return -1; }
204 ok = 0;
205 for (i = 0; i < 64; i++) {
206 if (s[i] < p[i]) {
207 ok = 1;
208 break;
209 } else if (s[i] > p[i]) {
210 qDebug() << i << "=" << (qint32)s[i] << (qint32)p[i];
211 return -1;
212 }
213 }
214 if (!ok) { return -1; }
215 return 0;
216 }
217
check_g_bn(BIGNUM * p,BIGNUM * g)218 qint32 Utils::check_g_bn (BIGNUM *p, BIGNUM *g) {
219 static uchar s[256];
220 memset (s, 0, 256);
221 Q_ASSERT(BN_num_bytes (p) <= 256);
222 BN_bn2bin (p, s);
223 return check_g (s, g);
224 }
225
ensurePtr(void * p)226 void Utils::ensurePtr(void *p) {
227 if (p == NULL) {
228 qFatal("Out of memory");
229 exit (1);
230 }
231 }
232
ensure(qint32 r)233 void Utils::ensure (qint32 r) {
234 if (!r) {
235 ERR_print_errors_fp (stderr);
236 Q_ASSERT(0);
237 }
238 }
239
freeSecure(void * ptr,qint32 size)240 void Utils::freeSecure(void *ptr, qint32 size) {
241 if (!ptr) return;
242 memset (ptr, 0, size);
243 free (ptr);
244 }
245
secureZeroMemory(void * dst,int val,size_t count)246 void Utils::secureZeroMemory(void *dst, int val, size_t count) {
247 #if defined(Q_OS_WIN)
248 Q_UNUSED(val);
249 RtlSecureZeroMemory(dst, count);
250 #else
251 // TODO: maybe we should use memset_s ?
252
253 volatile unsigned char *p = (unsigned char *)dst;
254 while (count--)
255 *p++ = val;
256
257 #endif
258 }
259
rsaLoadPublicKey(const QString & publicKeyName)260 RSA *Utils::rsaLoadPublicKey(const QString &publicKeyName) {
261 RSA *pubKey = NULL;
262 FILE *f = fopen (publicKeyName.toLocal8Bit().data(), "r");
263 if (f == NULL) {
264 qCWarning(TG_UTIL_UTILS) << "Couldn't open public key file" << publicKeyName;
265 return NULL;
266 }
267 pubKey = PEM_read_RSAPublicKey (f, NULL, NULL, NULL);
268 fclose (f);
269 if (pubKey == NULL) {
270 qCWarning(TG_UTIL_UTILS) << "PEM_read_RSAPublicKey returns NULL";
271 return NULL;
272 }
273 qCDebug(TG_UTIL_UTILS) << "public key" << publicKeyName << "loaded successfully";
274 return pubKey;
275 }
276
computeRSAFingerprint(RSA * key)277 qint64 Utils::computeRSAFingerprint(RSA *key) {
278 static char tempbuff[4096];
279 static uchar sha[20];
280 #if OPENSSL_VERSION_NUMBER < 0x10100000L
281 Q_ASSERT(key->n && key->e);
282 qint32 l1 = serializeBignum (key->n, tempbuff, 4096);
283 Q_ASSERT(l1 > 0);
284 qint32 l2 = serializeBignum (key->e, tempbuff + l1, 4096 - l1);
285 #else
286 const BIGNUM *key_e;
287 const BIGNUM *key_n;
288 RSA_get0_key(key, &key_n, &key_e, NULL);
289 Q_ASSERT(key_n && key_e);
290 qint32 l1 = serializeBignum (key_n, tempbuff, 4096);
291 Q_ASSERT(l1 > 0);
292 qint32 l2 = serializeBignum (key_e, tempbuff + l1, 4096 - l1);
293 #endif
294 Q_ASSERT(l2 > 0 && l1 + l2 <= 4096);
295 SHA1 ((uchar *)tempbuff, l1 + l2, sha);
296 return *(qint64 *)(sha + 12);
297 }
298
talloc(size_t size)299 void *Utils::talloc(size_t size) {
300 #ifdef DEBUG
301 total_allocated_bytes += size;
302 void *p = malloc (size + RES_PRE + RES_AFTER);
303 ensurePtr (p);
304 *(qint32 *)p = size ^ 0xbedabeda;
305 *(qint32 *)(p + 4) = size;
306 *(qint32 *)(p + RES_PRE + size) = size ^ 0x7bed7bed;
307 *(qint32 *)(p + RES_AFTER + 4 + size) = usedBlocks;
308 blocks[usedBlocks ++] = p;
309 return p + 8;
310 #else
311 void *p = malloc (size);
312 ensurePtr (p);
313 return p;
314 #endif
315 }
316
tinflate(void * input,qint32 ilen,void * output,qint32 olen)317 qint32 Utils::tinflate(void *input, qint32 ilen, void *output, qint32 olen) {
318 z_stream strm;
319 memset(&strm, 0, sizeof (strm));
320 qint32 inflateResult = inflateInit2(&strm, 16 + MAX_WBITS);
321 Q_UNUSED(inflateResult);
322 Q_ASSERT(inflateResult == Z_OK);
323 strm.avail_in = ilen;
324 strm.next_in = (Bytef *)input;
325 strm.avail_out = olen ;
326 strm.next_out = (Bytef *)output;
327 qint32 err = inflate (&strm, Z_FINISH), totalOut = 0;
328 if (err == Z_OK || err == Z_STREAM_END) {
329 totalOut = (qint32) strm.total_out;
330 }
331 inflateEnd (&strm);
332 return totalOut;
333 }
334
toHex(qint32 x)335 QString Utils::toHex(qint32 x) {
336 return "0x" + QString::number(static_cast<quint32>(x), 16);
337 }
338
toHex(void * buffer,qint32 size)339 QString Utils::toHex(void *buffer, qint32 size) {
340 QByteArray array((char *)buffer, size);
341 QByteArray hexArray = array.toHex();
342 QString sb;
343 qint32 count = 0;
344 for (qint32 i = 0; i < hexArray.length(); i += 2) {
345 count++;
346 sb.append(QString(hexArray.at(i)).toUpper());
347 sb.append(QString(hexArray.at(i+1)).toUpper());
348 if (count == 8) {
349 sb.append("\n");
350 count = 0;
351 } else if (count == 4) {
352 sb.append("\t");
353 } else {
354 sb.append(" ");
355 }
356 }
357 return sb;
358 }
359
padBytesAndGetBignum(const QByteArray & gAOrB)360 BIGNUM *Utils::padBytesAndGetBignum(const QByteArray &gAOrB) {
361 // padding of B (gAOrB) to have exactly 256 bytes
362 uchar paddedGAOrB[256];
363 qint32 length = gAOrB.length();
364 // check that size of
365 uchar *rawGAOrB = (uchar *)gAOrB.data();
366 if (length < 256) {
367 memcpy (paddedGAOrB + 256 - length, rawGAOrB, length);
368 } else {
369 memcpy (paddedGAOrB, rawGAOrB + (length - 256), 256);
370 }
371
372 BIGNUM *bigNumGAOrB = BN_bin2bn(paddedGAOrB, 256, 0);
373 return bigNumGAOrB;
374 }
375
bytesToBignum(const QByteArray & bytes)376 BIGNUM *Utils::bytesToBignum(const QByteArray &bytes) {
377 uchar *data = (uchar *)bytes.data();
378 qint32 length = bytes.length();
379 BIGNUM *bignum = BN_bin2bn(data, length, 0);
380 return bignum;
381 }
382
bignumToBytes(BIGNUM * bignum)383 QByteArray Utils::bignumToBytes(BIGNUM *bignum) {
384 qint32 length = BN_num_bytes(bignum);
385 QScopedArrayPointer<uchar> data(new uchar[length]);
386 BN_bn2bin(bignum, data.data());
387 return QByteArray((char *)data.data(), length);
388 }
389
getKeyFingerprint(uchar * sharedKey)390 qint64 Utils::getKeyFingerprint(uchar *sharedKey) {
391 uchar shaBuffer[20];
392 SHA1(sharedKey, 256, shaBuffer);
393 qint64 keyFingerprint = *(qint64 *)(shaBuffer + 12);
394 return keyFingerprint;
395 }
396
getDeviceModel()397 QString Utils::getDeviceModel() {
398 #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
399 #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
400 return "Mobile";
401 #else
402 return "PC";
403 #endif
404 #else
405 struct utsname st;
406 uname(&st);
407 return QString(st.machine);
408 #endif
409 }
410
getSystemVersion()411 QString Utils::getSystemVersion() {
412 #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
413 return QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture();
414 #else
415 struct utsname st;
416 uname(&st);
417 return QString(QString(st.sysname) + " " + QString(st.release) + " " + QString(st.version));
418 #endif
419 }
420
getAppVersion()421 QString Utils::getAppVersion() {
422 if(QCoreApplication::applicationVersion().isEmpty())
423 return "1.0";
424 else
425 return QCoreApplication::applicationVersion();
426 }
427
parsePhoneNumberDigits(const QString & phoneNumber)428 QString Utils::parsePhoneNumberDigits(const QString &phoneNumber) {
429 // Only allowing + and [0..9] chars
430 QString filteredChars;
431
432 if (phoneNumber.length() > 0) {
433
434 for (int i = 0; i < phoneNumber.length(); i++) {
435 const QChar c = phoneNumber.at(i);
436 if (c.isDigit() || c == '+') {
437 filteredChars.append(c);
438 }
439 }
440 }
441
442 return filteredChars;
443 }
444
pToBigEndian(quint32 p)445 QByteArray Utils::pToBigEndian(quint32 p) {;
446 qint32 pLength;
447 if (p < (1 << 8)) {
448 pLength = 1;
449 } else if (p < (1 << 16)) {
450 pLength = 2;
451 } else if (p < (1 << 24)) {
452 pLength = 3;
453 } else {
454 pLength = 4;
455 }
456
457 uchar beP[4];
458 qToBigEndian(p, beP);
459
460 return QByteArray((const char *)beP, pLength);
461 }
462
findDivider(qint64 pq)463 qint64 Utils::findDivider(qint64 pq) {
464 qint32 it = 0;
465 quint64 g = 0;
466 for (int i = 0; i < 3 || it < 1000; i++) {
467 qint32 q = ((lrand48() & 15) + 17) % pq;
468 quint64 x = (qint64)lrand48 () % (pq - 1) + 1, y = x;
469 qint32 lim = 1 << (i + 18);
470 qint32 j;
471 for (j = 1; j < lim; j++) {
472 ++it;
473 quint64 a = x, b = x, c = q;
474 while (b) {
475 if (b & 1) {
476 c += a;
477 if ((qint64)c >= pq) {
478 c -= pq;
479 }
480 }
481 a += a;
482 if ((qint64)a >= pq) {
483 a -= pq;
484 }
485 b >>= 1;
486 }
487 x = c;
488 quint64 z = x < y ? pq + x - y : x - y;
489 g = Utils::gcd(z, pq);
490 if (g != 1) {
491 break;
492 }
493 if (!(j & (j - 1))) {
494 y = x;
495 }
496 }
497 if (g > 1 && (qint64)g < pq) break;
498 }
499 qCDebug(TG_UTIL_UTILS) << "got" << g << "divider after" << it << "iterations";
500 return g;
501 }
502
503 #ifdef Q_OS_WIN
lrand48()504 qint64 lrand48()
505 {
506 qint64 result = 0;
507 Utils::randomBytes(&result, 6);
508 return result;
509 }
510 #endif
511