mtproto_dh_utils.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "mtproto/mtproto_dh_utils.h"
  8. #include "base/openssl_help.h"
  9. namespace MTP {
  10. namespace {
  11. constexpr auto kMaxModExpSize = 256;
  12. bool IsPrimeAndGoodCheck(const openssl::BigNum &prime, int g) {
  13. constexpr auto kGoodPrimeBitsCount = 2048;
  14. if (prime.failed()
  15. || prime.isNegative()
  16. || prime.bitsSize() != kGoodPrimeBitsCount) {
  17. LOG(("MTP Error: Bad prime bits count %1, expected %2."
  18. ).arg(prime.bitsSize()
  19. ).arg(kGoodPrimeBitsCount));
  20. return false;
  21. }
  22. const auto context = openssl::Context();
  23. if (!prime.isPrime(context)) {
  24. LOG(("MTP Error: Bad prime."));
  25. return false;
  26. }
  27. switch (g) {
  28. case 2: {
  29. const auto mod8 = prime.countModWord(8);
  30. if (mod8 != 7) {
  31. LOG(("BigNum PT Error: bad g value: %1, mod8: %2").arg(g).arg(mod8));
  32. return false;
  33. }
  34. } break;
  35. case 3: {
  36. const auto mod3 = prime.countModWord(3);
  37. if (mod3 != 2) {
  38. LOG(("BigNum PT Error: bad g value: %1, mod3: %2").arg(g).arg(mod3));
  39. return false;
  40. }
  41. } break;
  42. case 4: break;
  43. case 5: {
  44. const auto mod5 = prime.countModWord(5);
  45. if (mod5 != 1 && mod5 != 4) {
  46. LOG(("BigNum PT Error: bad g value: %1, mod5: %2").arg(g).arg(mod5));
  47. return false;
  48. }
  49. } break;
  50. case 6: {
  51. const auto mod24 = prime.countModWord(24);
  52. if (mod24 != 19 && mod24 != 23) {
  53. LOG(("BigNum PT Error: bad g value: %1, mod24: %2").arg(g).arg(mod24));
  54. return false;
  55. }
  56. } break;
  57. case 7: {
  58. const auto mod7 = prime.countModWord(7);
  59. if (mod7 != 3 && mod7 != 5 && mod7 != 6) {
  60. LOG(("BigNum PT Error: bad g value: %1, mod7: %2").arg(g).arg(mod7));
  61. return false;
  62. }
  63. } break;
  64. default: {
  65. LOG(("BigNum PT Error: bad g value: %1").arg(g));
  66. return false;
  67. } break;
  68. }
  69. if (!openssl::BigNum(prime).subWord(1).divWord(2).isPrime(context)) {
  70. LOG(("MTP Error: Bad (prime - 1) / 2."));
  71. return false;
  72. }
  73. return true;
  74. }
  75. } // namespace
  76. bool IsGoodModExpFirst(
  77. const openssl::BigNum &modexp,
  78. const openssl::BigNum &prime) {
  79. const auto diff = openssl::BigNum::Sub(prime, modexp);
  80. if (modexp.failed() || prime.failed() || diff.failed()) {
  81. return false;
  82. }
  83. constexpr auto kMinDiffBitsCount = 2048 - 64;
  84. if (diff.isNegative()
  85. || diff.bitsSize() < kMinDiffBitsCount
  86. || modexp.bitsSize() < kMinDiffBitsCount
  87. || modexp.bytesSize() > kMaxModExpSize) {
  88. return false;
  89. }
  90. return true;
  91. }
  92. bool IsPrimeAndGood(bytes::const_span primeBytes, int g) {
  93. static constexpr unsigned char GoodPrime[] = {
  94. 0xC7, 0x1C, 0xAE, 0xB9, 0xC6, 0xB1, 0xC9, 0x04, 0x8E, 0x6C, 0x52, 0x2F, 0x70, 0xF1, 0x3F, 0x73,
  95. 0x98, 0x0D, 0x40, 0x23, 0x8E, 0x3E, 0x21, 0xC1, 0x49, 0x34, 0xD0, 0x37, 0x56, 0x3D, 0x93, 0x0F,
  96. 0x48, 0x19, 0x8A, 0x0A, 0xA7, 0xC1, 0x40, 0x58, 0x22, 0x94, 0x93, 0xD2, 0x25, 0x30, 0xF4, 0xDB,
  97. 0xFA, 0x33, 0x6F, 0x6E, 0x0A, 0xC9, 0x25, 0x13, 0x95, 0x43, 0xAE, 0xD4, 0x4C, 0xCE, 0x7C, 0x37,
  98. 0x20, 0xFD, 0x51, 0xF6, 0x94, 0x58, 0x70, 0x5A, 0xC6, 0x8C, 0xD4, 0xFE, 0x6B, 0x6B, 0x13, 0xAB,
  99. 0xDC, 0x97, 0x46, 0x51, 0x29, 0x69, 0x32, 0x84, 0x54, 0xF1, 0x8F, 0xAF, 0x8C, 0x59, 0x5F, 0x64,
  100. 0x24, 0x77, 0xFE, 0x96, 0xBB, 0x2A, 0x94, 0x1D, 0x5B, 0xCD, 0x1D, 0x4A, 0xC8, 0xCC, 0x49, 0x88,
  101. 0x07, 0x08, 0xFA, 0x9B, 0x37, 0x8E, 0x3C, 0x4F, 0x3A, 0x90, 0x60, 0xBE, 0xE6, 0x7C, 0xF9, 0xA4,
  102. 0xA4, 0xA6, 0x95, 0x81, 0x10, 0x51, 0x90, 0x7E, 0x16, 0x27, 0x53, 0xB5, 0x6B, 0x0F, 0x6B, 0x41,
  103. 0x0D, 0xBA, 0x74, 0xD8, 0xA8, 0x4B, 0x2A, 0x14, 0xB3, 0x14, 0x4E, 0x0E, 0xF1, 0x28, 0x47, 0x54,
  104. 0xFD, 0x17, 0xED, 0x95, 0x0D, 0x59, 0x65, 0xB4, 0xB9, 0xDD, 0x46, 0x58, 0x2D, 0xB1, 0x17, 0x8D,
  105. 0x16, 0x9C, 0x6B, 0xC4, 0x65, 0xB0, 0xD6, 0xFF, 0x9C, 0xA3, 0x92, 0x8F, 0xEF, 0x5B, 0x9A, 0xE4,
  106. 0xE4, 0x18, 0xFC, 0x15, 0xE8, 0x3E, 0xBE, 0xA0, 0xF8, 0x7F, 0xA9, 0xFF, 0x5E, 0xED, 0x70, 0x05,
  107. 0x0D, 0xED, 0x28, 0x49, 0xF4, 0x7B, 0xF9, 0x59, 0xD9, 0x56, 0x85, 0x0C, 0xE9, 0x29, 0x85, 0x1F,
  108. 0x0D, 0x81, 0x15, 0xF6, 0x35, 0xB1, 0x05, 0xEE, 0x2E, 0x4E, 0x15, 0xD0, 0x4B, 0x24, 0x54, 0xBF,
  109. 0x6F, 0x4F, 0xAD, 0xF0, 0x34, 0xB1, 0x04, 0x03, 0x11, 0x9C, 0xD8, 0xE3, 0xB9, 0x2F, 0xCC, 0x5B };
  110. if (!bytes::compare(bytes::make_span(GoodPrime), primeBytes)) {
  111. if (g == 3 || g == 4 || g == 5 || g == 7) {
  112. return true;
  113. }
  114. }
  115. return IsPrimeAndGoodCheck(openssl::BigNum(primeBytes), g);
  116. }
  117. ModExpFirst CreateModExp(
  118. int g,
  119. bytes::const_span primeBytes,
  120. bytes::const_span randomSeed) {
  121. Expects(randomSeed.size() == ModExpFirst::kRandomPowerSize);
  122. using namespace openssl;
  123. BigNum prime(primeBytes);
  124. auto result = ModExpFirst();
  125. result.randomPower.resize(ModExpFirst::kRandomPowerSize);
  126. while (true) {
  127. bytes::set_random(result.randomPower);
  128. for (auto i = 0; i != ModExpFirst::kRandomPowerSize; ++i) {
  129. result.randomPower[i] ^= randomSeed[i];
  130. }
  131. const auto modexp = BigNum::ModExp(
  132. BigNum(g),
  133. BigNum(result.randomPower),
  134. prime);
  135. if (IsGoodModExpFirst(modexp, prime)) {
  136. result.modexp = modexp.getBytes();
  137. return result;
  138. }
  139. }
  140. }
  141. bytes::vector CreateAuthKey(
  142. bytes::const_span firstBytes,
  143. bytes::const_span randomBytes,
  144. bytes::const_span primeBytes) {
  145. using openssl::BigNum;
  146. const auto first = BigNum(firstBytes);
  147. const auto prime = BigNum(primeBytes);
  148. if (!IsGoodModExpFirst(first, prime)) {
  149. LOG(("AuthKey Error: Bad first prime in CreateAuthKey()."));
  150. return {};
  151. }
  152. return BigNum::ModExp(first, BigNum(randomBytes), prime).getBytes();
  153. }
  154. } // namespace MTP