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