mtproto_dc_key_binder.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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/details/mtproto_dc_key_binder.h"
  8. #include "mtproto/details/mtproto_serialized_request.h"
  9. #include "mtproto/mtp_instance.h"
  10. #include "base/unixtime.h"
  11. #include "base/openssl_help.h"
  12. #include "base/random.h"
  13. #include "scheme.h"
  14. #include <QtCore/QPointer>
  15. namespace MTP::details {
  16. namespace {
  17. [[nodiscard]] QByteArray EncryptBindAuthKeyInner(
  18. const AuthKeyPtr &persistentKey,
  19. mtpMsgId realMsgId,
  20. const MTPBindAuthKeyInner &data) {
  21. auto serialized = SerializedRequest::Serialize(data);
  22. serialized.setMsgId(realMsgId);
  23. serialized.setSeqNo(0);
  24. serialized.addPadding(true);
  25. constexpr auto kMsgIdPosition = SerializedRequest::kMessageIdPosition;
  26. constexpr auto kMinMessageSize = 5;
  27. const auto sizeInPrimes = serialized->size();
  28. const auto messageSize = serialized.messageSize();
  29. Assert(messageSize >= kMinMessageSize);
  30. Assert(sizeInPrimes >= kMsgIdPosition + messageSize);
  31. const auto sizeInBytes = sizeInPrimes * sizeof(mtpPrime);
  32. const auto padding = sizeInBytes
  33. - (kMsgIdPosition + messageSize) * sizeof(mtpPrime);
  34. // session_id, salt - just random here.
  35. bytes::set_random(bytes::make_span(*serialized).subspan(
  36. 0,
  37. kMsgIdPosition * sizeof(mtpPrime)));
  38. const auto hash = openssl::Sha1(bytes::make_span(*serialized).subspan(
  39. 0,
  40. sizeInBytes - padding));
  41. auto msgKey = MTPint128();
  42. bytes::copy(
  43. bytes::object_as_span(&msgKey),
  44. bytes::make_span(hash).subspan(4));
  45. constexpr auto kAuthKeyIdBytes = 2 * sizeof(mtpPrime);
  46. constexpr auto kMessageKeyPosition = kAuthKeyIdBytes;
  47. constexpr auto kMessageKeyBytes = 4 * sizeof(mtpPrime);
  48. constexpr auto kPrefix = (kAuthKeyIdBytes + kMessageKeyBytes);
  49. auto encrypted = QByteArray(kPrefix + sizeInBytes, Qt::Uninitialized);
  50. *reinterpret_cast<uint64*>(encrypted.data()) = persistentKey->keyId();
  51. *reinterpret_cast<MTPint128*>(encrypted.data() + kMessageKeyPosition)
  52. = msgKey;
  53. aesIgeEncrypt_oldmtp(
  54. serialized->constData(),
  55. encrypted.data() + kPrefix,
  56. sizeInBytes,
  57. persistentKey,
  58. msgKey);
  59. return encrypted;
  60. }
  61. } // namespace
  62. DcKeyBinder::DcKeyBinder(AuthKeyPtr &&persistentKey)
  63. : _persistentKey(std::move(persistentKey)) {
  64. Expects(_persistentKey != nullptr);
  65. }
  66. SerializedRequest DcKeyBinder::prepareRequest(
  67. const AuthKeyPtr &temporaryKey,
  68. uint64 sessionId) {
  69. Expects(temporaryKey != nullptr);
  70. Expects(temporaryKey->expiresAt() != 0);
  71. const auto nonce = base::RandomValue<uint64>();
  72. const auto msgId = base::unixtime::mtproto_msg_id();
  73. auto result = SerializedRequest::Serialize(MTPauth_BindTempAuthKey(
  74. MTP_long(_persistentKey->keyId()),
  75. MTP_long(nonce),
  76. MTP_int(temporaryKey->expiresAt()),
  77. MTP_bytes(EncryptBindAuthKeyInner(
  78. _persistentKey,
  79. msgId,
  80. MTP_bind_auth_key_inner(
  81. MTP_long(nonce),
  82. MTP_long(temporaryKey->keyId()),
  83. MTP_long(_persistentKey->keyId()),
  84. MTP_long(sessionId),
  85. MTP_int(temporaryKey->expiresAt()))))));
  86. result.setMsgId(msgId);
  87. return result;
  88. }
  89. DcKeyBindState DcKeyBinder::handleResponse(const mtpBuffer &response) {
  90. Expects(!response.isEmpty());
  91. auto from = response.data();
  92. const auto end = from + response.size();
  93. auto error = MTPRpcError();
  94. if (response[0] == mtpc_boolTrue) {
  95. return DcKeyBindState::Success;
  96. } else if (response[0] == mtpc_rpc_error && error.read(from, end)) {
  97. const auto destroyed = error.match([&](const MTPDrpc_error &data) {
  98. return (data.verror_code().v == 400)
  99. && (data.verror_message().v == "ENCRYPTED_MESSAGE_INVALID");
  100. });
  101. return destroyed
  102. ? DcKeyBindState::DefinitelyDestroyed
  103. : DcKeyBindState::Failed;
  104. } else {
  105. return DcKeyBindState::Failed;
  106. }
  107. }
  108. AuthKeyPtr DcKeyBinder::persistentKey() const {
  109. return _persistentKey;
  110. }
  111. } // namespace MTP::details