summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/td/mtproto/Transport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Telegram/tdlib/td/td/mtproto/Transport.cpp')
-rw-r--r--protocols/Telegram/tdlib/td/td/mtproto/Transport.cpp191
1 files changed, 87 insertions, 104 deletions
diff --git a/protocols/Telegram/tdlib/td/td/mtproto/Transport.cpp b/protocols/Telegram/tdlib/td/td/mtproto/Transport.cpp
index ef0440ef6f..1a98182dd8 100644
--- a/protocols/Telegram/tdlib/td/td/mtproto/Transport.cpp
+++ b/protocols/Telegram/tdlib/td/td/mtproto/Transport.cpp
@@ -1,5 +1,5 @@
//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -8,12 +8,12 @@
#include "td/mtproto/AuthKey.h"
#include "td/mtproto/KDF.h"
+#include "td/mtproto/MessageId.h"
#include "td/utils/as.h"
#include "td/utils/crypto.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
-#include "td/utils/misc.h"
#include "td/utils/Random.h"
#include "td/utils/SliceBuilder.h"
#include "td/utils/Status.h"
@@ -43,7 +43,7 @@ struct CryptoHeader {
// It is weird to generate message_id and seq_no while writing a packet.
//
- // uint64 message_id;
+ // uint64 msg_id;
// uint32 seq_no;
// uint32 message_data_length;
uint8 data[0]; // use compiler extension
@@ -69,7 +69,7 @@ struct CryptoHeader {
};
struct CryptoPrefix {
- uint64 message_id;
+ uint64 msg_id;
uint32 seq_no;
uint32 message_data_length;
};
@@ -109,9 +109,9 @@ struct EndToEndPrefix {
struct NoCryptoHeader {
uint64 auth_key_id;
- // message_id is removed from CryptoHeader. Should be removed from here too.
+ // msg_id is removed from CryptoHeader. Should be removed from here too.
//
- // uint64 message_id;
+ // uint64 msg_id;
// uint32 message_data_length;
uint8 data[0]; // use compiler extension
@@ -186,26 +186,21 @@ size_t do_calc_crypto_size2_rand(size_t data_size, size_t enc_size, size_t raw_s
} // namespace
template <class HeaderT>
-size_t Transport::calc_crypto_size2(size_t data_size, PacketInfo *info) {
- if (info->size != 0) {
- return info->size;
- }
-
+size_t Transport::calc_crypto_size2(size_t data_size, PacketInfo *packet_info) {
size_t enc_size = HeaderT::encrypted_header_size();
size_t raw_size = sizeof(HeaderT) - enc_size;
- if (info->use_random_padding) {
- info->size = narrow_cast<uint32>(do_calc_crypto_size2_rand(data_size, enc_size, raw_size));
+ if (packet_info->use_random_padding) {
+ return do_calc_crypto_size2_rand(data_size, enc_size, raw_size);
} else {
- info->size = narrow_cast<uint32>(do_calc_crypto_size2_basic(data_size, enc_size, raw_size));
+ return do_calc_crypto_size2_basic(data_size, enc_size, raw_size);
}
- return info->size;
}
size_t Transport::calc_no_crypto_size(size_t data_size) {
return sizeof(NoCryptoHeader) + data_size;
}
-Status Transport::read_no_crypto(MutableSlice message, PacketInfo *info, MutableSlice *data) {
+Status Transport::read_no_crypto(MutableSlice message, PacketInfo *packet_info, MutableSlice *data) {
if (message.size() < sizeof(NoCryptoHeader)) {
return Status::Error(PSLICE() << "Invalid MTProto message: too small [message.size() = " << message.size()
<< "] < [sizeof(NoCryptoHeader) = " << sizeof(NoCryptoHeader) << "]");
@@ -218,7 +213,7 @@ Status Transport::read_no_crypto(MutableSlice message, PacketInfo *info, Mutable
template <class HeaderT, class PrefixT>
Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &auth_key, HeaderT **header_ptr,
- PrefixT **prefix_ptr, MutableSlice *data, PacketInfo *info) {
+ PrefixT **prefix_ptr, MutableSlice *data, PacketInfo *packet_info) {
if (message.size() < sizeof(HeaderT)) {
return Status::Error(PSLICE() << "Invalid MTProto message: too small [message.size() = " << message.size()
<< "] < [sizeof(HeaderT) = " << sizeof(HeaderT) << "]");
@@ -237,7 +232,7 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
UInt256 aes_key;
UInt256 aes_iv;
- if (info->version == 1) {
+ if (packet_info->version == 1) {
KDF(auth_key.key(), header->message_key, X, &aes_key, &aes_iv);
} else {
KDF2(auth_key.key(), header->message_key, X, &aes_key, &aes_iv);
@@ -256,14 +251,14 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
bool is_length_bad = false;
UInt128 real_message_key;
- if (info->version == 1) {
- is_length_bad |= info->check_mod4 && prefix->message_data_length % 4 != 0;
+ if (packet_info->version == 1) {
+ is_length_bad |= packet_info->check_mod4 && prefix->message_data_length % 4 != 0;
auto expected_size = calc_crypto_size<HeaderT>(data_size);
is_length_bad |= expected_size != message.size();
auto check_size = data_size * (1 - is_length_bad) + tail_size * is_length_bad;
- std::tie(info->message_ack, real_message_key) = calc_message_ack_and_key(*header, check_size);
+ std::tie(packet_info->message_ack, real_message_key) = calc_message_ack_and_key(*header, check_size);
} else {
- std::tie(info->message_ack, real_message_key) = calc_message_key2(auth_key, X, to_decrypt);
+ std::tie(packet_info->message_ack, real_message_key) = calc_message_key2(auth_key, X, to_decrypt);
}
int is_key_bad = false;
@@ -276,8 +271,8 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
<< "] [expected = " << format::as_hex_dump(real_message_key) << "]");
}
- if (info->version == 2) {
- if (info->check_mod4 && prefix->message_data_length % 4 != 0) {
+ if (packet_info->version == 2) {
+ if (packet_info->check_mod4 && prefix->message_data_length % 4 != 0) {
return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (not divisible by four)"
<< tag("total_size", message.size())
<< tag("message_data_length", prefix->message_data_length));
@@ -304,125 +299,113 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
return Status::OK();
}
-Status Transport::read_crypto(MutableSlice message, const AuthKey &auth_key, PacketInfo *info, MutableSlice *data) {
+Status Transport::read_crypto(MutableSlice message, const AuthKey &auth_key, PacketInfo *packet_info,
+ MutableSlice *data) {
CryptoHeader *header = nullptr;
CryptoPrefix *prefix = nullptr;
- TRY_STATUS(read_crypto_impl(8, message, auth_key, &header, &prefix, data, info));
+ TRY_STATUS(read_crypto_impl(8, message, auth_key, &header, &prefix, data, packet_info));
CHECK(header != nullptr);
CHECK(prefix != nullptr);
- CHECK(info != nullptr);
- info->type = PacketInfo::Common;
- info->salt = header->salt;
- info->session_id = header->session_id;
- info->message_id = prefix->message_id;
- info->seq_no = prefix->seq_no;
+ CHECK(packet_info != nullptr);
+ packet_info->type = PacketInfo::Common;
+ packet_info->salt = header->salt;
+ packet_info->session_id = header->session_id;
+ packet_info->message_id = MessageId(prefix->msg_id);
+ packet_info->seq_no = prefix->seq_no;
return Status::OK();
}
-Status Transport::read_e2e_crypto(MutableSlice message, const AuthKey &auth_key, PacketInfo *info, MutableSlice *data) {
+Status Transport::read_e2e_crypto(MutableSlice message, const AuthKey &auth_key, PacketInfo *packet_info,
+ MutableSlice *data) {
EndToEndHeader *header = nullptr;
EndToEndPrefix *prefix = nullptr;
- TRY_STATUS(read_crypto_impl(info->is_creator && info->version != 1 ? 8 : 0, message, auth_key, &header, &prefix, data,
- info));
+ TRY_STATUS(read_crypto_impl(packet_info->is_creator && packet_info->version != 1 ? 8 : 0, message, auth_key, &header,
+ &prefix, data, packet_info));
CHECK(header != nullptr);
CHECK(prefix != nullptr);
- CHECK(info != nullptr);
- info->type = PacketInfo::EndToEnd;
+ CHECK(packet_info != nullptr);
+ packet_info->type = PacketInfo::EndToEnd;
return Status::OK();
}
-size_t Transport::write_no_crypto(const Storer &storer, PacketInfo *info, MutableSlice dest) {
+BufferWriter Transport::write_no_crypto(const Storer &storer, PacketInfo *packet_info, size_t prepend_size,
+ size_t append_size) {
size_t size = calc_no_crypto_size(storer.size());
- if (size > dest.size()) {
- return size;
- }
+ auto packet = BufferWriter{size, prepend_size, append_size};
+
// NoCryptoHeader
- as<uint64>(dest.begin()) = 0;
- auto real_size = storer.store(dest.ubegin() + sizeof(uint64));
+ auto *begin = packet.as_mutable_slice().ubegin();
+ as<uint64>(begin) = 0;
+ auto real_size = storer.store(begin + sizeof(uint64));
CHECK(real_size == storer.size());
- return size;
+ return packet;
}
template <class HeaderT>
-void Transport::write_crypto_impl(int X, const Storer &storer, const AuthKey &auth_key, PacketInfo *info,
- HeaderT *header, size_t data_size) {
+void Transport::write_crypto_impl(int X, const Storer &storer, const AuthKey &auth_key, PacketInfo *packet_info,
+ HeaderT *header, size_t data_size, size_t padded_size) {
auto real_data_size = storer.store(header->data);
CHECK(real_data_size == data_size);
- VLOG(raw_mtproto) << "Send packet of size " << data_size << " to session " << format::as_hex(info->session_id) << ":"
+ VLOG(raw_mtproto) << "Send packet of size " << data_size << ':'
<< format::as_hex_dump<4>(Slice(header->data, data_size));
-
- size_t size = 0;
- if (info->version == 1) {
- size = calc_crypto_size<HeaderT>(data_size);
- } else {
- size = calc_crypto_size2<HeaderT>(data_size, info);
- }
-
- size_t pad_size = size - (sizeof(HeaderT) + data_size);
+ size_t pad_size = padded_size - (sizeof(HeaderT) + data_size);
MutableSlice pad(header->data + data_size, pad_size);
Random::secure_bytes(pad.ubegin(), pad.size());
MutableSlice to_encrypt = MutableSlice(header->encrypt_begin(), pad.uend());
- if (info->version == 1) {
- std::tie(info->message_ack, info->message_key) = calc_message_ack_and_key(*header, data_size);
- } else {
- std::tie(info->message_ack, info->message_key) = calc_message_key2(auth_key, X, to_encrypt);
- }
-
- header->message_key = info->message_key;
-
UInt256 aes_key;
UInt256 aes_iv;
- if (info->version == 1) {
+ if (packet_info->version == 1) {
+ std::tie(packet_info->message_ack, header->message_key) = calc_message_ack_and_key(*header, data_size);
KDF(auth_key.key(), header->message_key, X, &aes_key, &aes_iv);
} else {
+ std::tie(packet_info->message_ack, header->message_key) = calc_message_key2(auth_key, X, to_encrypt);
KDF2(auth_key.key(), header->message_key, X, &aes_key, &aes_iv);
}
aes_ige_encrypt(as_slice(aes_key), as_mutable_slice(aes_iv), to_encrypt, to_encrypt);
}
-size_t Transport::write_crypto(const Storer &storer, const AuthKey &auth_key, PacketInfo *info, MutableSlice dest) {
+BufferWriter Transport::write_crypto(const Storer &storer, const AuthKey &auth_key, PacketInfo *packet_info,
+ size_t prepend_size, size_t append_size) {
size_t data_size = storer.size();
- size_t size;
- if (info->version == 1) {
- size = calc_crypto_size<CryptoHeader>(data_size);
+ size_t padded_size;
+ if (packet_info->version == 1) {
+ padded_size = calc_crypto_size<CryptoHeader>(data_size);
} else {
- size = calc_crypto_size2<CryptoHeader>(data_size, info);
- }
- if (size > dest.size()) {
- return size;
+ padded_size = calc_crypto_size2<CryptoHeader>(data_size, packet_info);
}
+ auto packet = BufferWriter{padded_size, prepend_size, append_size};
//FIXME: rewrite without reinterpret cast
- auto &header = *reinterpret_cast<CryptoHeader *>(dest.begin());
+ auto &header = *reinterpret_cast<CryptoHeader *>(packet.as_mutable_slice().begin());
header.auth_key_id = auth_key.id();
- header.salt = info->salt;
- header.session_id = info->session_id;
+ header.salt = packet_info->salt;
+ header.session_id = packet_info->session_id;
- write_crypto_impl(0, storer, auth_key, info, &header, data_size);
+ write_crypto_impl(0, storer, auth_key, packet_info, &header, data_size, padded_size);
- return size;
+ return packet;
}
-size_t Transport::write_e2e_crypto(const Storer &storer, const AuthKey &auth_key, PacketInfo *info, MutableSlice dest) {
+BufferWriter Transport::write_e2e_crypto(const Storer &storer, const AuthKey &auth_key, PacketInfo *packet_info,
+ size_t prepend_size, size_t append_size) {
size_t data_size = storer.size();
- size_t size;
- if (info->version == 1) {
- size = calc_crypto_size<EndToEndHeader>(data_size);
+ size_t padded_size;
+ if (packet_info->version == 1) {
+ padded_size = calc_crypto_size<EndToEndHeader>(data_size);
} else {
- size = calc_crypto_size2<EndToEndHeader>(data_size, info);
- }
- if (size > dest.size()) {
- return size;
+ padded_size = calc_crypto_size2<EndToEndHeader>(data_size, packet_info);
}
+ auto packet = BufferWriter{padded_size, prepend_size, append_size};
//FIXME: rewrite without reinterpret cast
- auto &header = *reinterpret_cast<EndToEndHeader *>(dest.begin());
+ auto &header = *reinterpret_cast<EndToEndHeader *>(packet.as_mutable_slice().begin());
header.auth_key_id = auth_key.id();
- write_crypto_impl(info->is_creator || info->version == 1 ? 0 : 8, storer, auth_key, info, &header, data_size);
+ write_crypto_impl(packet_info->is_creator || packet_info->version == 1 ? 0 : 8, storer, auth_key, packet_info,
+ &header, data_size, padded_size);
- return size;
+ return packet;
}
Result<uint64> Transport::read_auth_key_id(Slice message) {
@@ -432,8 +415,8 @@ Result<uint64> Transport::read_auth_key_id(Slice message) {
return as<uint64>(message.begin());
}
-Result<Transport::ReadResult> Transport::read(MutableSlice message, const AuthKey &auth_key, PacketInfo *info) {
- if (message.size() < 12) {
+Result<Transport::ReadResult> Transport::read(MutableSlice message, const AuthKey &auth_key, PacketInfo *packet_info) {
+ if (message.size() < 16) {
if (message.size() < 4) {
return Status::Error(PSLICE() << "Invalid MTProto message: smaller than 4 bytes [size = " << message.size()
<< "]");
@@ -449,31 +432,31 @@ Result<Transport::ReadResult> Transport::read(MutableSlice message, const AuthKe
}
}
- info->auth_key_id = as<int64>(message.begin());
- info->no_crypto_flag = info->auth_key_id == 0;
+ packet_info->no_crypto_flag = as<int64>(message.begin()) == 0;
MutableSlice data;
- if (info->type == PacketInfo::EndToEnd) {
- TRY_STATUS(read_e2e_crypto(message, auth_key, info, &data));
- } else if (info->no_crypto_flag) {
- TRY_STATUS(read_no_crypto(message, info, &data));
+ if (packet_info->type == PacketInfo::EndToEnd) {
+ TRY_STATUS(read_e2e_crypto(message, auth_key, packet_info, &data));
+ } else if (packet_info->no_crypto_flag) {
+ TRY_STATUS(read_no_crypto(message, packet_info, &data));
} else {
if (auth_key.empty()) {
return Status::Error("Failed to decrypt MTProto message: auth key is empty");
}
- TRY_STATUS(read_crypto(message, auth_key, info, &data));
+ TRY_STATUS(read_crypto(message, auth_key, packet_info, &data));
}
return ReadResult::make_packet(data);
}
-size_t Transport::write(const Storer &storer, const AuthKey &auth_key, PacketInfo *info, MutableSlice dest) {
- if (info->type == PacketInfo::EndToEnd) {
- return write_e2e_crypto(storer, auth_key, info, dest);
+BufferWriter Transport::write(const Storer &storer, const AuthKey &auth_key, PacketInfo *packet_info,
+ size_t prepend_size, size_t append_size) {
+ if (packet_info->type == PacketInfo::EndToEnd) {
+ return write_e2e_crypto(storer, auth_key, packet_info, prepend_size, append_size);
}
- if (info->no_crypto_flag) {
- return write_no_crypto(storer, info, dest);
+ if (packet_info->no_crypto_flag) {
+ return write_no_crypto(storer, packet_info, prepend_size, append_size);
} else {
CHECK(!auth_key.empty());
- return write_crypto(storer, auth_key, info, dest);
+ return write_crypto(storer, auth_key, packet_info, prepend_size, append_size);
}
}