Moved mtproto/mtpPublicRSA.h to mtproto/rsa_public_key module,

rewritten and refactored, removed openssl headers from stdafx.h

Xcode project file does not contain mtproto/rsa_public_key.cpp yet
This commit is contained in:
John Preston 2016-03-23 21:12:07 +03:00
parent 034adfab2b
commit 68ed885568
17 changed files with 437 additions and 371 deletions

View File

@ -20,9 +20,16 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "autoupdater.h"
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include "application.h"
#include "pspecific.h"
#include "autoupdater.h"
#ifndef TDESKTOP_DISABLE_AUTOUPDATE

View File

@ -200,7 +200,7 @@ inline const char *cGUIDStr() {
return gGuidStr;
}
inline const char **cPublicRSAKeys(uint32 &cnt) {
inline const char **cPublicRSAKeys(int &keysCount) {
static const char *(keys[]) = {"\
-----BEGIN RSA PUBLIC KEY-----\n\
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n\
@ -210,7 +210,7 @@ Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n\
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n\
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n\
-----END RSA PUBLIC KEY-----"};
cnt = sizeof(keys) / sizeof(const char*);
keysCount = arraysize(keys);
return keys;
}

View File

@ -19,8 +19,11 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "localstorage.h"
#include <openssl/evp.h>
#include "mainwidget.h"
#include "window.h"
#include "lang.h"

View File

@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include <openssl/aes.h>
void aesEncrypt(const void *src, void *dst, uint32 len, void *key, void *iv) {
uchar aes_key[32], aes_iv[32];
memcpy(aes_key, key, 32);

View File

@ -20,261 +20,272 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "mtproto/mtpConnection.h"
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
#include <openssl/rand.h>
namespace {
bool parsePQ(const std::string &pqStr, std::string &pStr, std::string &qStr) {
if (pqStr.length() > 8) return false; // more than 64 bit pq
#include "mtproto/rsa_public_key.h"
uint64 pq = 0, p, q;
const uchar *pqChars = (const uchar*)&pqStr[0];
for (uint32 i = 0, l = pqStr.length(); i < l; ++i) {
pq <<= 8;
pq |= (uint64)pqChars[i];
}
uint64 pqSqrt = (uint64)sqrtl((long double)pq), ySqr, y;
while (pqSqrt * pqSqrt > pq) --pqSqrt;
while (pqSqrt * pqSqrt < pq) ++pqSqrt;
for (ySqr = pqSqrt * pqSqrt - pq; ; ++pqSqrt, ySqr = pqSqrt * pqSqrt - pq) {
y = (uint64)sqrtl((long double)ySqr);
while (y * y > ySqr) --y;
while (y * y < ySqr) ++y;
if (!ySqr || y + pqSqrt >= pq) return false;
if (y * y == ySqr) {
p = pqSqrt + y;
q = (pqSqrt > y) ? (pqSqrt - y) : (y - pqSqrt);
break;
}
}
if (p > q) swap(p, q);
using std::string;
pStr.resize(4);
uchar *pChars = (uchar*)&pStr[0];
for (uint32 i = 0; i < 4; ++i) {
*(pChars + 3 - i) = (uchar)(p & 0xFF);
p >>= 8;
namespace MTP {
namespace internal {
bool parsePQ(const string &pqStr, string &pStr, string &qStr) {
if (pqStr.length() > 8) return false; // more than 64 bit pq
uint64 pq = 0, p, q;
const uchar *pqChars = (const uchar*)&pqStr[0];
for (uint32 i = 0, l = pqStr.length(); i < l; ++i) {
pq <<= 8;
pq |= (uint64)pqChars[i];
}
uint64 pqSqrt = (uint64)sqrtl((long double)pq), ySqr, y;
while (pqSqrt * pqSqrt > pq) --pqSqrt;
while (pqSqrt * pqSqrt < pq) ++pqSqrt;
for (ySqr = pqSqrt * pqSqrt - pq; ; ++pqSqrt, ySqr = pqSqrt * pqSqrt - pq) {
y = (uint64)sqrtl((long double)ySqr);
while (y * y > ySqr) --y;
while (y * y < ySqr) ++y;
if (!ySqr || y + pqSqrt >= pq) return false;
if (y * y == ySqr) {
p = pqSqrt + y;
q = (pqSqrt > y) ? (pqSqrt - y) : (y - pqSqrt);
break;
}
}
if (p > q) swap(p, q);
pStr.resize(4);
uchar *pChars = (uchar*)&pStr[0];
for (uint32 i = 0; i < 4; ++i) {
*(pChars + 3 - i) = (uchar)(p & 0xFF);
p >>= 8;
}
qStr.resize(4);
uchar *qChars = (uchar*)&qStr[0];
for (uint32 i = 0; i < 4; ++i) {
*(qChars + 3 - i) = (uchar)(q & 0xFF);
q >>= 8;
}
return true;
}
class BigNumCounter {
public:
bool count(const void *power, const void *modul, uint32 g, void *gResult, const void *g_a, void *g_aResult) {
DEBUG_LOG(("BigNum Info: counting g_b = g ^ b % dh_prime and auth_key = g_a ^ b % dh_prime"));
uint32 g_be = qToBigEndian(g);
if (
!BN_bin2bn((const uchar*)power, 64 * sizeof(uint32), &bnPower) ||
!BN_bin2bn((const uchar*)modul, 64 * sizeof(uint32), &bnModul) ||
!BN_bin2bn((const uchar*)&g_be, sizeof(uint32), &bn_g) ||
!BN_bin2bn((const uchar*)g_a, 64 * sizeof(uint32), &bn_g_a)
) {
ERR_load_crypto_strings();
LOG(("BigNum Error: BN_bin2bn failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0)));
DEBUG_LOG(("BigNum Error: base %1, power %2, modul %3").arg(Logs::mb(&g_be, sizeof(uint32)).str()).arg(Logs::mb(power, 64 * sizeof(uint32)).str()).arg(Logs::mb(modul, 64 * sizeof(uint32)).str()));
return false;
}
qStr.resize(4);
uchar *qChars = (uchar*)&qStr[0];
for (uint32 i = 0; i < 4; ++i) {
*(qChars + 3 - i) = (uchar)(q & 0xFF);
q >>= 8;
if (!BN_mod_exp(&bnResult, &bn_g, &bnPower, &bnModul, ctx)) {
ERR_load_crypto_strings();
LOG(("BigNum Error: BN_mod_exp failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0)));
DEBUG_LOG(("BigNum Error: base %1, power %2, modul %3").arg(Logs::mb(&g_be, sizeof(uint32)).str()).arg(Logs::mb(power, 64 * sizeof(uint32)).str()).arg(Logs::mb(modul, 64 * sizeof(uint32)).str()));
return false;
}
uint32 resultLen = BN_num_bytes(&bnResult);
if (resultLen != 64 * sizeof(uint32)) {
DEBUG_LOG(("BigNum Error: bad gResult len (%1)").arg(resultLen));
return false;
}
resultLen = BN_bn2bin(&bnResult, (uchar*)gResult);
if (resultLen != 64 * sizeof(uint32)) {
DEBUG_LOG(("BigNum Error: bad gResult export len (%1)").arg(resultLen));
return false;
}
BN_add_word(&bnResult, 1); // check g_b < dh_prime - 1
if (BN_cmp(&bnResult, &bnModul) >= 0) {
DEBUG_LOG(("BigNum Error: bad g_b >= dh_prime - 1"));
return false;
}
if (!BN_mod_exp(&bnResult, &bn_g_a, &bnPower, &bnModul, ctx)) {
ERR_load_crypto_strings();
LOG(("BigNum Error: BN_mod_exp failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0)));
DEBUG_LOG(("BigNum Error: base %1, power %2, modul %3").arg(Logs::mb(&g_be, sizeof(uint32)).str()).arg(Logs::mb(power, 64 * sizeof(uint32)).str()).arg(Logs::mb(modul, 64 * sizeof(uint32)).str()));
return false;
}
resultLen = BN_num_bytes(&bnResult);
if (resultLen != 64 * sizeof(uint32)) {
DEBUG_LOG(("BigNum Error: bad g_aResult len (%1)").arg(resultLen));
return false;
}
resultLen = BN_bn2bin(&bnResult, (uchar*)g_aResult);
if (resultLen != 64 * sizeof(uint32)) {
DEBUG_LOG(("BigNum Error: bad g_aResult export len (%1)").arg(resultLen));
return false;
}
BN_add_word(&bn_g_a, 1); // check g_a < dh_prime - 1
if (BN_cmp(&bn_g_a, &bnModul) >= 0) {
DEBUG_LOG(("BigNum Error: bad g_a >= dh_prime - 1"));
return false;
}
return true;
}
class _BigNumCounter {
public:
bool count(const void *power, const void *modul, uint32 g, void *gResult, const void *g_a, void *g_aResult) {
DEBUG_LOG(("BigNum Info: counting g_b = g ^ b % dh_prime and auth_key = g_a ^ b % dh_prime"));
uint32 g_be = qToBigEndian(g);
if (
!BN_bin2bn((const uchar*)power, 64 * sizeof(uint32), &bnPower) ||
!BN_bin2bn((const uchar*)modul, 64 * sizeof(uint32), &bnModul) ||
!BN_bin2bn((const uchar*)&g_be, sizeof(uint32), &bn_g) ||
!BN_bin2bn((const uchar*)g_a, 64 * sizeof(uint32), &bn_g_a)
) {
ERR_load_crypto_strings();
LOG(("BigNum Error: BN_bin2bn failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0)));
DEBUG_LOG(("BigNum Error: base %1, power %2, modul %3").arg(Logs::mb(&g_be, sizeof(uint32)).str()).arg(Logs::mb(power, 64 * sizeof(uint32)).str()).arg(Logs::mb(modul, 64 * sizeof(uint32)).str()));
return false;
}
if (!BN_mod_exp(&bnResult, &bn_g, &bnPower, &bnModul, ctx)) {
ERR_load_crypto_strings();
LOG(("BigNum Error: BN_mod_exp failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0)));
DEBUG_LOG(("BigNum Error: base %1, power %2, modul %3").arg(Logs::mb(&g_be, sizeof(uint32)).str()).arg(Logs::mb(power, 64 * sizeof(uint32)).str()).arg(Logs::mb(modul, 64 * sizeof(uint32)).str()));
return false;
}
uint32 resultLen = BN_num_bytes(&bnResult);
if (resultLen != 64 * sizeof(uint32)) {
DEBUG_LOG(("BigNum Error: bad gResult len (%1)").arg(resultLen));
return false;
}
resultLen = BN_bn2bin(&bnResult, (uchar*)gResult);
if (resultLen != 64 * sizeof(uint32)) {
DEBUG_LOG(("BigNum Error: bad gResult export len (%1)").arg(resultLen));
return false;
}
BN_add_word(&bnResult, 1); // check g_b < dh_prime - 1
if (BN_cmp(&bnResult, &bnModul) >= 0) {
DEBUG_LOG(("BigNum Error: bad g_b >= dh_prime - 1"));
return false;
}
if (!BN_mod_exp(&bnResult, &bn_g_a, &bnPower, &bnModul, ctx)) {
ERR_load_crypto_strings();
LOG(("BigNum Error: BN_mod_exp failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0)));
DEBUG_LOG(("BigNum Error: base %1, power %2, modul %3").arg(Logs::mb(&g_be, sizeof(uint32)).str()).arg(Logs::mb(power, 64 * sizeof(uint32)).str()).arg(Logs::mb(modul, 64 * sizeof(uint32)).str()));
return false;
}
resultLen = BN_num_bytes(&bnResult);
if (resultLen != 64 * sizeof(uint32)) {
DEBUG_LOG(("BigNum Error: bad g_aResult len (%1)").arg(resultLen));
return false;
}
resultLen = BN_bn2bin(&bnResult, (uchar*)g_aResult);
if (resultLen != 64 * sizeof(uint32)) {
DEBUG_LOG(("BigNum Error: bad g_aResult export len (%1)").arg(resultLen));
return false;
}
BN_add_word(&bn_g_a, 1); // check g_a < dh_prime - 1
if (BN_cmp(&bn_g_a, &bnModul) >= 0) {
DEBUG_LOG(("BigNum Error: bad g_a >= dh_prime - 1"));
return false;
}
return true;
}
_BigNumCounter() : ctx(BN_CTX_new()) {
BN_init(&bnPower);
BN_init(&bnModul);
BN_init(&bn_g);
BN_init(&bn_g_a);
BN_init(&bnResult);
}
~_BigNumCounter() {
BN_CTX_free(ctx);
BN_clear_free(&bnPower);
BN_clear_free(&bnModul);
BN_clear_free(&bn_g);
BN_clear_free(&bn_g_a);
BN_clear_free(&bnResult);
}
private:
BIGNUM bnPower, bnModul, bn_g, bn_g_a, bnResult;
BN_CTX *ctx;
};
// Miller-Rabin primality test
class _BigNumPrimeTest {
public:
bool isPrimeAndGood(const void *pData, uint32 iterCount, int32 g) {
if (!memcmp(pData, "\xC7\x1C\xAE\xB9\xC6\xB1\xC9\x04\x8E\x6C\x52\x2F\x70\xF1\x3F\x73\x98\x0D\x40\x23\x8E\x3E\x21\xC1\x49\x34\xD0\x37\x56\x3D\x93\x0F\x48\x19\x8A\x0A\xA7\xC1\x40\x58\x22\x94\x93\xD2\x25\x30\xF4\xDB\xFA\x33\x6F\x6E\x0A\xC9\x25\x13\x95\x43\xAE\xD4\x4C\xCE\x7C\x37\x20\xFD\x51\xF6\x94\x58\x70\x5A\xC6\x8C\xD4\xFE\x6B\x6B\x13\xAB\xDC\x97\x46\x51\x29\x69\x32\x84\x54\xF1\x8F\xAF\x8C\x59\x5F\x64\x24\x77\xFE\x96\xBB\x2A\x94\x1D\x5B\xCD\x1D\x4A\xC8\xCC\x49\x88\x07\x08\xFA\x9B\x37\x8E\x3C\x4F\x3A\x90\x60\xBE\xE6\x7C\xF9\xA4\xA4\xA6\x95\x81\x10\x51\x90\x7E\x16\x27\x53\xB5\x6B\x0F\x6B\x41\x0D\xBA\x74\xD8\xA8\x4B\x2A\x14\xB3\x14\x4E\x0E\xF1\x28\x47\x54\xFD\x17\xED\x95\x0D\x59\x65\xB4\xB9\xDD\x46\x58\x2D\xB1\x17\x8D\x16\x9C\x6B\xC4\x65\xB0\xD6\xFF\x9C\xA3\x92\x8F\xEF\x5B\x9A\xE4\xE4\x18\xFC\x15\xE8\x3E\xBE\xA0\xF8\x7F\xA9\xFF\x5E\xED\x70\x05\x0D\xED\x28\x49\xF4\x7B\xF9\x59\xD9\x56\x85\x0C\xE9\x29\x85\x1F\x0D\x81\x15\xF6\x35\xB1\x05\xEE\x2E\x4E\x15\xD0\x4B\x24\x54\xBF\x6F\x4F\xAD\xF0\x34\xB1\x04\x03\x11\x9C\xD8\xE3\xB9\x2F\xCC\x5B", 256)) {
if (g == 3 || g == 4 || g == 5 || g == 7) {
return true;
}
}
if (
!BN_bin2bn((const uchar*)pData, 64 * sizeof(uint32), &bnPrime)
) {
ERR_load_crypto_strings();
LOG(("BigNum PT Error: BN_bin2bn failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0)));
DEBUG_LOG(("BigNum PT Error: prime %1").arg(Logs::mb(pData, 64 * sizeof(uint32)).str()));
return false;
}
int32 numBits = BN_num_bits(&bnPrime);
if (numBits != 2048) {
LOG(("BigNum PT Error: BN_bin2bn failed, bad dh_prime num bits: %1").arg(numBits));
return false;
}
if (BN_is_prime_ex(&bnPrime, MTPMillerRabinIterCount, ctx, NULL) == 0) {
return false;
}
switch (g) {
case 2: {
int32 mod8 = BN_mod_word(&bnPrime, 8);
if (mod8 != 7) {
LOG(("BigNum PT Error: bad g value: %1, mod8: %2").arg(g).arg(mod8));
return false;
}
} break;
case 3: {
int32 mod3 = BN_mod_word(&bnPrime, 3);
if (mod3 != 2) {
LOG(("BigNum PT Error: bad g value: %1, mod3: %2").arg(g).arg(mod3));
return false;
}
} break;
case 4: break;
case 5: {
int32 mod5 = BN_mod_word(&bnPrime, 5);
if (mod5 != 1 && mod5 != 4) {
LOG(("BigNum PT Error: bad g value: %1, mod5: %2").arg(g).arg(mod5));
return false;
}
} break;
case 6: {
int32 mod24 = BN_mod_word(&bnPrime, 24);
if (mod24 != 19 && mod24 != 23) {
LOG(("BigNum PT Error: bad g value: %1, mod24: %2").arg(g).arg(mod24));
return false;
}
} break;
case 7: {
int32 mod7 = BN_mod_word(&bnPrime, 7);
if (mod7 != 3 && mod7 != 5 && mod7 != 6) {
LOG(("BigNum PT Error: bad g value: %1, mod7: %2").arg(g).arg(mod7));
return false;
}
} break;
default:
LOG(("BigNum PT Error: bad g value: %1").arg(g));
return false;
break;
}
BN_sub_word(&bnPrime, 1); // (p - 1) / 2
BN_div_word(&bnPrime, 2);
if (BN_is_prime_ex(&bnPrime, MTPMillerRabinIterCount, ctx, NULL) == 0) {
return false;
}
return true;
}
_BigNumPrimeTest() : ctx(BN_CTX_new()) {
BN_init(&bnPrime);
}
~_BigNumPrimeTest() {
BN_CTX_free(ctx);
BN_clear_free(&bnPrime);
}
private:
BIGNUM bnPrime;
BN_CTX *ctx;
};
typedef QMap<uint64, mtpPublicRSA> PublicRSAKeys;
PublicRSAKeys gPublicRSA;
bool gConfigInited = false;
void initRSAConfig() {
if (gConfigInited) return;
gConfigInited = true;
DEBUG_LOG(("MTP Info: MTP config init"));
// read all public keys
uint32 keysCnt;
const char **keys = cPublicRSAKeys(keysCnt);
for (uint32 i = 0; i < keysCnt; ++i) {
mtpPublicRSA key(keys[i]);
if (key.key()) {
gPublicRSA.insert(key.fingerPrint(), key);
} else {
LOG(("MTP Error: could not read this public RSA key:"));
LOG((keys[i]));
}
}
DEBUG_LOG(("MTP Info: read %1 public RSA keys").arg(gPublicRSA.size()));
BigNumCounter() : ctx(BN_CTX_new()) {
BN_init(&bnPower);
BN_init(&bnModul);
BN_init(&bn_g);
BN_init(&bn_g_a);
BN_init(&bnResult);
}
~BigNumCounter() {
BN_CTX_free(ctx);
BN_clear_free(&bnPower);
BN_clear_free(&bnModul);
BN_clear_free(&bn_g);
BN_clear_free(&bn_g_a);
BN_clear_free(&bnResult);
}
private:
BIGNUM bnPower, bnModul, bn_g, bn_g_a, bnResult;
BN_CTX *ctx;
};
// Miller-Rabin primality test
class BigNumPrimeTest {
public:
bool isPrimeAndGood(const void *pData, uint32 iterCount, int32 g) {
if (!memcmp(pData, "\xC7\x1C\xAE\xB9\xC6\xB1\xC9\x04\x8E\x6C\x52\x2F\x70\xF1\x3F\x73\x98\x0D\x40\x23\x8E\x3E\x21\xC1\x49\x34\xD0\x37\x56\x3D\x93\x0F\x48\x19\x8A\x0A\xA7\xC1\x40\x58\x22\x94\x93\xD2\x25\x30\xF4\xDB\xFA\x33\x6F\x6E\x0A\xC9\x25\x13\x95\x43\xAE\xD4\x4C\xCE\x7C\x37\x20\xFD\x51\xF6\x94\x58\x70\x5A\xC6\x8C\xD4\xFE\x6B\x6B\x13\xAB\xDC\x97\x46\x51\x29\x69\x32\x84\x54\xF1\x8F\xAF\x8C\x59\x5F\x64\x24\x77\xFE\x96\xBB\x2A\x94\x1D\x5B\xCD\x1D\x4A\xC8\xCC\x49\x88\x07\x08\xFA\x9B\x37\x8E\x3C\x4F\x3A\x90\x60\xBE\xE6\x7C\xF9\xA4\xA4\xA6\x95\x81\x10\x51\x90\x7E\x16\x27\x53\xB5\x6B\x0F\x6B\x41\x0D\xBA\x74\xD8\xA8\x4B\x2A\x14\xB3\x14\x4E\x0E\xF1\x28\x47\x54\xFD\x17\xED\x95\x0D\x59\x65\xB4\xB9\xDD\x46\x58\x2D\xB1\x17\x8D\x16\x9C\x6B\xC4\x65\xB0\xD6\xFF\x9C\xA3\x92\x8F\xEF\x5B\x9A\xE4\xE4\x18\xFC\x15\xE8\x3E\xBE\xA0\xF8\x7F\xA9\xFF\x5E\xED\x70\x05\x0D\xED\x28\x49\xF4\x7B\xF9\x59\xD9\x56\x85\x0C\xE9\x29\x85\x1F\x0D\x81\x15\xF6\x35\xB1\x05\xEE\x2E\x4E\x15\xD0\x4B\x24\x54\xBF\x6F\x4F\xAD\xF0\x34\xB1\x04\x03\x11\x9C\xD8\xE3\xB9\x2F\xCC\x5B", 256)) {
if (g == 3 || g == 4 || g == 5 || g == 7) {
return true;
}
}
if (
!BN_bin2bn((const uchar*)pData, 64 * sizeof(uint32), &bnPrime)
) {
ERR_load_crypto_strings();
LOG(("BigNum PT Error: BN_bin2bn failed, error: %1").arg(ERR_error_string(ERR_get_error(), 0)));
DEBUG_LOG(("BigNum PT Error: prime %1").arg(Logs::mb(pData, 64 * sizeof(uint32)).str()));
return false;
}
int32 numBits = BN_num_bits(&bnPrime);
if (numBits != 2048) {
LOG(("BigNum PT Error: BN_bin2bn failed, bad dh_prime num bits: %1").arg(numBits));
return false;
}
if (BN_is_prime_ex(&bnPrime, MTPMillerRabinIterCount, ctx, NULL) == 0) {
return false;
}
switch (g) {
case 2: {
int32 mod8 = BN_mod_word(&bnPrime, 8);
if (mod8 != 7) {
LOG(("BigNum PT Error: bad g value: %1, mod8: %2").arg(g).arg(mod8));
return false;
}
} break;
case 3: {
int32 mod3 = BN_mod_word(&bnPrime, 3);
if (mod3 != 2) {
LOG(("BigNum PT Error: bad g value: %1, mod3: %2").arg(g).arg(mod3));
return false;
}
} break;
case 4: break;
case 5: {
int32 mod5 = BN_mod_word(&bnPrime, 5);
if (mod5 != 1 && mod5 != 4) {
LOG(("BigNum PT Error: bad g value: %1, mod5: %2").arg(g).arg(mod5));
return false;
}
} break;
case 6: {
int32 mod24 = BN_mod_word(&bnPrime, 24);
if (mod24 != 19 && mod24 != 23) {
LOG(("BigNum PT Error: bad g value: %1, mod24: %2").arg(g).arg(mod24));
return false;
}
} break;
case 7: {
int32 mod7 = BN_mod_word(&bnPrime, 7);
if (mod7 != 3 && mod7 != 5 && mod7 != 6) {
LOG(("BigNum PT Error: bad g value: %1, mod7: %2").arg(g).arg(mod7));
return false;
}
} break;
default:
LOG(("BigNum PT Error: bad g value: %1").arg(g));
return false;
break;
}
BN_sub_word(&bnPrime, 1); // (p - 1) / 2
BN_div_word(&bnPrime, 2);
if (BN_is_prime_ex(&bnPrime, MTPMillerRabinIterCount, ctx, NULL) == 0) {
return false;
}
return true;
}
BigNumPrimeTest() : ctx(BN_CTX_new()) {
BN_init(&bnPrime);
}
~BigNumPrimeTest() {
BN_CTX_free(ctx);
BN_clear_free(&bnPrime);
}
private:
BIGNUM bnPrime;
BN_CTX *ctx;
};
typedef QMap<uint64, MTP::internal::RSAPublicKey> RSAPublicKeys;
RSAPublicKeys InitRSAPublicKeys() {
DEBUG_LOG(("MTP Info: RSA public keys list creation"));
RSAPublicKeys result;
int keysCount;
const char **keys = cPublicRSAKeys(keysCount);
for (int i = 0; i < keysCount; ++i) {
RSAPublicKey key(keys[i]);
if (key.isValid()) {
result.insert(key.getFingerPrint(), key);
} else {
LOG(("MTP Error: could not read this public RSA key:"));
LOG((keys[i]));
}
}
DEBUG_LOG(("MTP Info: read %1 public RSA keys").arg(result.size()));
return result;
}
} // namespace internal
} // namespace MTP
uint32 MTPThreadIdIncrement = 0;
MTPThread::MTPThread() : QThread(0)
@ -294,8 +305,6 @@ MTProtoConnection::MTProtoConnection() : thread(nullptr), data(nullptr) {
int32 MTProtoConnection::start(MTPSessionData *sessionData, int32 dc) {
t_assert(thread == nullptr && data == nullptr);
initRSAConfig();
thread = new MTPThread();
data = new MTProtoConnectionPrivate(thread, this, sessionData, dc);
@ -3330,22 +3339,22 @@ void MTProtoConnectionPrivate::pqAnswered() {
return restart();
}
mtpPublicRSA *rsaKey = 0;
static MTP::internal::RSAPublicKeys RSAKeys = MTP::internal::InitRSAPublicKeys();
const MTP::internal::RSAPublicKey *rsaKey = nullptr;
const QVector<MTPlong> &fingerPrints(res_pq.c_resPQ().vserver_public_key_fingerprints.c_vector().v);
for (uint32 i = 0, l = fingerPrints.size(); i < l; ++i) {
uint64 print(fingerPrints[i].v);
PublicRSAKeys::iterator rsaIndex = gPublicRSA.find(print);
if (rsaIndex != gPublicRSA.end()) {
rsaKey = &rsaIndex.value();
for (const MTPlong &fingerPrint : fingerPrints) {
auto it = RSAKeys.constFind(fingerPrint.v);
if (it != RSAKeys.cend()) {
rsaKey = &it.value();
break;
}
}
if (!rsaKey) {
QStringList suggested, my;
for (uint32 i = 0, l = fingerPrints.size(); i < l; ++i) {
suggested.push_back(QString("%1").arg(fingerPrints[i].v));
for (const MTPlong &fingerPrint : fingerPrints) {
suggested.push_back(QString("%1").arg(fingerPrint.v));
}
for (PublicRSAKeys::const_iterator i = gPublicRSA.cbegin(), e = gPublicRSA.cend(); i != e; ++i) {
for (auto i = RSAKeys.cbegin(), e = RSAKeys.cend(); i != e; ++i) {
my.push_back(QString("%1").arg(i.key()));
}
LOG(("AuthKey Error: could not choose public RSA key, suggested fingerprints: %1, my fingerprints: %2").arg(suggested.join(", ")).arg(my.join(", ")));
@ -3363,7 +3372,7 @@ void MTProtoConnectionPrivate::pqAnswered() {
const string &pq(res_pq_data.vpq.c_string().v);
string &p(p_q_inner_data.vp._string().v), &q(p_q_inner_data.vq._string().v);
if (!parsePQ(pq, p, q)) {
if (!MTP::internal::parsePQ(pq, p, q)) {
LOG(("AuthKey Error: could not factor pq!"));
DEBUG_LOG(("AuthKey Error: problematic pq: %1").arg(Logs::mb(&pq[0], pq.length()).str()));
return restart();
@ -3375,7 +3384,7 @@ void MTProtoConnectionPrivate::pqAnswered() {
MTPReq_DH_params req_DH_params;
req_DH_params.vnonce = authKeyData->nonce;
req_DH_params.vserver_nonce = authKeyData->server_nonce;
req_DH_params.vpublic_key_fingerprint = MTP_long(rsaKey->fingerPrint());
req_DH_params.vpublic_key_fingerprint = MTP_long(rsaKey->getFingerPrint());
req_DH_params.vp = p_q_inner_data.vp;
req_DH_params.vq = p_q_inner_data.vq;
@ -3403,14 +3412,9 @@ void MTProtoConnectionPrivate::pqAnswered() {
memset_rand(&encBuffer[encSize], (65 - encSize) * sizeof(mtpPrime));
}
dhEncString.resize(256);
int32 res = RSA_public_encrypt(256, ((const uchar*)&encBuffer[0]) + 3, (uchar*)&dhEncString[0], rsaKey->key(), RSA_NO_PADDING);
if (res != 256) {
ERR_load_crypto_strings();
LOG(("RSA Error: RSA_public_encrypt failed, key fp: %1, result: %2, error: %3").arg(rsaKey->fingerPrint()).arg(res).arg(ERR_error_string(ERR_get_error(), 0)));
if (!rsaKey->encrypt(reinterpret_cast<const char*>(&encBuffer[0]) + 3, dhEncString)) {
return restart();
}
connect(_conn, SIGNAL(receivedData()), this, SLOT(dhParamsAnswered()));
DEBUG_LOG(("AuthKey Info: sending Req_DH_params.."));
@ -3498,7 +3502,7 @@ void MTProtoConnectionPrivate::dhParamsAnswered() {
}
// check that dhPrime and (dhPrime - 1) / 2 are really prime using openssl BIGNUM methods
_BigNumPrimeTest bnPrimeTest;
MTP::internal::BigNumPrimeTest bnPrimeTest;
if (!bnPrimeTest.isPrimeAndGood(&dhPrime[0], MTPMillerRabinIterCount, dh_inner_data.vg.v)) {
LOG(("AuthKey Error: bad dh_prime primality!").arg(dhPrime.length()).arg(g_a.length()));
DEBUG_LOG(("AuthKey Error: dh_prime %1").arg(Logs::mb(&dhPrime[0], dhPrime.length()).str()));
@ -3556,7 +3560,7 @@ void MTProtoConnectionPrivate::dhClientParamsSend() {
memset_rand(b, sizeof(b));
// count g_b and auth_key using openssl BIGNUM methods
_BigNumCounter bnCounter;
MTP::internal::BigNumCounter bnCounter;
if (!bnCounter.count(b, authKeyStrings->dh_prime.constData(), authKeyData->g, g_b, authKeyStrings->g_a.constData(), authKeyData->auth_key)) {
return dhClientParamsSend();
}

View File

@ -21,7 +21,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#include "mtproto/mtpCoreTypes.h"
#include "mtproto/mtpPublicRSA.h"
#include "mtproto/mtpAuthKey.h"
inline bool mtpRequestData::isSentContainer(const mtpRequest &request) { // "request-like" wrap for msgIds vector

View File

@ -1,85 +0,0 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
class mtpPublicRSA {
public:
mtpPublicRSA(const char *key) : data(new mtpPublicRSAInner(PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(key), -1), 0, 0, 0), 0)) {
if (!data->prsa) return;
int32 nBytes = BN_num_bytes(data->prsa->n);
int32 eBytes = BN_num_bytes(data->prsa->e);
string nStr(nBytes, 0), eStr(eBytes, 0);
BN_bn2bin(data->prsa->n, (uchar*)&nStr[0]);
BN_bn2bin(data->prsa->e, (uchar*)&eStr[0]);
mtpBuffer tmp;
MTP_string(nStr).write(tmp);
MTP_string(eStr).write(tmp);
uchar sha1Buffer[20];
data->fp = *(uint64*)(hashSha1(&tmp[0], tmp.size() * sizeof(mtpPrime), sha1Buffer) + 3);
}
mtpPublicRSA(const mtpPublicRSA &v) : data(v.data) {
++data->cnt;
}
mtpPublicRSA &operator=(const mtpPublicRSA &v) {
if (data != v.data) {
destroy();
data = v.data;
++data->cnt;
}
return *this;
}
uint64 fingerPrint() const {
return data->fp;
}
RSA *key() {
return data->prsa;
}
~mtpPublicRSA() {
destroy();
}
private:
void destroy() {
if (!--data->cnt) {
delete data;
}
}
struct mtpPublicRSAInner {
mtpPublicRSAInner(RSA *_prsa, uint64 _fp) : prsa(_prsa), cnt(1), fp(_fp) {
}
~mtpPublicRSAInner() {
RSA_free(prsa);
}
RSA *prsa;
uint32 cnt;
uint64 fp;
};
mtpPublicRSAInner *data;
};

View File

@ -0,0 +1,84 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "mtproto/rsa_public_key.h"
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/err.h>
using std::string;
namespace MTP {
namespace internal {
struct RSAPublicKey::Impl {
Impl(const char *key) : rsa(PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(key), -1), 0, 0, 0)) {
}
~Impl() {
RSA_free(rsa);
}
RSA *rsa;
uint64 fp = 0;
};
RSAPublicKey::RSAPublicKey(const char *key) : impl_(new Impl(key)) {
if (!impl_->rsa) return;
int nBytes = BN_num_bytes(impl_->rsa->n);
int eBytes = BN_num_bytes(impl_->rsa->e);
string nStr(nBytes, 0), eStr(eBytes, 0);
BN_bn2bin(impl_->rsa->n, (uchar*)&nStr[0]);
BN_bn2bin(impl_->rsa->e, (uchar*)&eStr[0]);
mtpBuffer tmp;
MTP_string(nStr).write(tmp);
MTP_string(eStr).write(tmp);
uchar sha1Buffer[20];
impl_->fp = *(uint64*)(hashSha1(&tmp[0], tmp.size() * sizeof(mtpPrime), sha1Buffer) + 3);
}
uint64 RSAPublicKey::getFingerPrint() const {
return impl_->fp;
}
bool RSAPublicKey::isValid() const {
return impl_->rsa != nullptr;
}
bool RSAPublicKey::encrypt(const void *data, string &result) const {
t_assert(isValid());
result.resize(256);
int res = RSA_public_encrypt(256, reinterpret_cast<const unsigned char*>(data), reinterpret_cast<uchar*>(&result[0]), impl_->rsa, RSA_NO_PADDING);
if (res != 256) {
ERR_load_crypto_strings();
LOG(("RSA Error: RSA_public_encrypt failed, key fp: %1, result: %2, error: %3").arg(getFingerPrint()).arg(res).arg(ERR_error_string(ERR_get_error(), 0)));
return false;
}
return true;
}
} // namespace internal
} // namespace MTP

View File

@ -0,0 +1,48 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
namespace MTP {
namespace internal {
// this class holds an RSA public key and can encrypt fixed-size messages with it
class RSAPublicKey final {
public:
// key in RSAPublicKey "-----BEGIN RSA PUBLIC KEY----- ..." format
RSAPublicKey(const char *key);
bool isValid() const;
uint64 getFingerPrint() const;
// data has exactly 256 chars to be encrypted
bool encrypt(const void *data, string &result) const;
private:
struct Impl;
typedef QSharedPointer<Impl> ImplPtr;
ImplPtr impl_;
};
} // namespace internal
} // namespace MTP

View File

@ -36,16 +36,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include <numeric>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
#include <QtCore/QtCore>
#include <QtWidgets/QtWidgets>
#include <QtNetwork/QtNetwork>

View File

@ -20,6 +20,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "types.h"
#include <openssl/crypto.h>
#include <openssl/sha.h>
#include "application.h"
uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };

View File

@ -46,6 +46,10 @@ public:
};
// thanks Chromium see https://blogs.msdn.microsoft.com/the1/2004/05/07/how-would-you-get-the-count-of-an-array-in-c-2/
template <typename T, size_t N> char(&ArraySizeHelper(T(&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
#define qsl(s) QStringLiteral(s)
#define qstr(s) QLatin1String(s, sizeof(s) - 1)

View File

@ -120,6 +120,7 @@ SOURCES += \
./SourceFiles/mtproto/mtpCoreTypes.cpp \
./SourceFiles/mtproto/mtpDC.cpp \
./SourceFiles/mtproto/mtpFileLoader.cpp \
./SourceFiles/mtproto/rsa_public_key.cpp \
./SourceFiles/mtproto/mtpRPC.cpp \
./SourceFiles/mtproto/mtpScheme.cpp \
./SourceFiles/mtproto/mtpSession.cpp \
@ -212,7 +213,7 @@ HEADERS += \
./SourceFiles/mtproto/mtpCoreTypes.h \
./SourceFiles/mtproto/mtpDC.h \
./SourceFiles/mtproto/mtpFileLoader.h \
./SourceFiles/mtproto/mtpPublicRSA.h \
./SourceFiles/mtproto/rsa_public_key.h \
./SourceFiles/mtproto/mtpRPC.h \
./SourceFiles/mtproto/mtpScheme.h \
./SourceFiles/mtproto/mtpSession.h \

View File

@ -1043,6 +1043,7 @@
<ClCompile Include="SourceFiles\mtproto\mtpRPC.cpp" />
<ClCompile Include="SourceFiles\mtproto\mtpScheme.cpp" />
<ClCompile Include="SourceFiles\mtproto\mtpSession.cpp" />
<ClCompile Include="SourceFiles\mtproto\rsa_public_key.cpp" />
<ClCompile Include="SourceFiles\overviewwidget.cpp" />
<ClCompile Include="SourceFiles\passcodewidget.cpp" />
<ClCompile Include="SourceFiles\playerwidget.cpp" />
@ -1924,7 +1925,7 @@
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
</CustomBuild>
<ClInclude Include="SourceFiles\mtproto\mtpPublicRSA.h" />
<ClInclude Include="SourceFiles\mtproto\rsa_public_key.h" />
<ClInclude Include="SourceFiles\mtproto\mtpScheme.h" />
<CustomBuild Include="SourceFiles\mtproto\mtpSession.h">
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing mtpSession.h...</Message>

View File

@ -921,6 +921,9 @@
<ClCompile Include="GeneratedFiles\Release\moc_pspecific_winrt.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\mtproto\rsa_public_key.cpp">
<Filter>mtproto</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SourceFiles\stdafx.h">
@ -938,9 +941,6 @@
<ClInclude Include="SourceFiles\logs.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\mtproto\mtpPublicRSA.h">
<Filter>mtproto</Filter>
</ClInclude>
<ClInclude Include="GeneratedFiles\style_auto.h">
<Filter>Generated Files</Filter>
</ClInclude>
@ -1022,6 +1022,9 @@
<ClInclude Include="SourceFiles\intro\introstart.h">
<Filter>intro</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\mtproto\rsa_public_key.h">
<Filter>mtproto</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="SourceFiles\mtproto\mtpConnection.h">

View File

@ -577,7 +577,7 @@
A022AF919D1977534CA66BB8 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_widgets.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_widgets.pri"; sourceTree = "<absolute>"; };
A1479F94376F9732B57C69DB /* moc_animation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_animation.cpp; path = GeneratedFiles/Debug/moc_animation.cpp; sourceTree = "<absolute>"; };
A1A67BEAA744704B29168D39 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
A3622760CEC6D6827A25E710 /* mtpPublicRSA.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mtpPublicRSA.h; path = SourceFiles/mtproto/mtpPublicRSA.h; sourceTree = "<absolute>"; };
A3622760CEC6D6827A25E710 /* rsa_public_key.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = rsa_public_key.h; path = SourceFiles/mtproto/rsa_public_key.h; sourceTree = "<absolute>"; };
A37C7E516201B0264A4CDA38 /* moc_introwidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_introwidget.cpp; path = GeneratedFiles/Debug/moc_introwidget.cpp; sourceTree = "<absolute>"; };
A4D8AC60897F435C1C3B9D02 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensors_generic.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensors_generic.pri"; sourceTree = "<absolute>"; };
A59F74CD76FDC2B4B9910E18 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_scripttools_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_scripttools_private.pri"; sourceTree = "<absolute>"; };
@ -830,7 +830,7 @@
27E7471A4EC90E84353AA16F /* mtpCoreTypes.h */,
B3D42654F18B1FE49512C404 /* mtpDC.h */,
96ACDDE3DCB798B97F9EA2F4 /* mtpFileLoader.h */,
A3622760CEC6D6827A25E710 /* mtpPublicRSA.h */,
A3622760CEC6D6827A25E710 /* rsa_public_key.h */,
FB61F72601D91BF3AC730D20 /* mtpRPC.h */,
7DBFC0B5EAF874BA10E3D603 /* mtpScheme.h */,
4D1099F2D3696E8A0E17D37D /* mtpSession.h */,

View File

@ -299,7 +299,7 @@ GeneratedFiles/Debug/moc_mtp.cpp: SourceFiles/mtproto/mtpSession.h \
../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \
SourceFiles/logs.h \
SourceFiles/mtproto/mtpScheme.h \
SourceFiles/mtproto/mtpPublicRSA.h \
SourceFiles/mtproto/rsa_public_key.h \
SourceFiles/mtproto/mtpAuthKey.h \
SourceFiles/mtproto/mtpDC.h \
SourceFiles/mtproto/mtpRPC.h \
@ -313,7 +313,7 @@ GeneratedFiles/Debug/moc_mtpConnection.cpp: SourceFiles/mtproto/mtpCoreTypes.h \
../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \
SourceFiles/logs.h \
SourceFiles/mtproto/mtpScheme.h \
SourceFiles/mtproto/mtpPublicRSA.h \
SourceFiles/mtproto/rsa_public_key.h \
SourceFiles/mtproto/mtpAuthKey.h \
SourceFiles/mtproto/mtpConnection.h
/usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/mtproto/mtpConnection.h -o GeneratedFiles/Debug/moc_mtpConnection.cpp
@ -330,7 +330,7 @@ GeneratedFiles/Debug/moc_mtpSession.cpp: SourceFiles/mtproto/mtpConnection.h \
../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \
SourceFiles/logs.h \
SourceFiles/mtproto/mtpScheme.h \
SourceFiles/mtproto/mtpPublicRSA.h \
SourceFiles/mtproto/rsa_public_key.h \
SourceFiles/mtproto/mtpAuthKey.h \
SourceFiles/mtproto/mtpDC.h \
SourceFiles/mtproto/mtpRPC.h \