2018-12-31 20:04:05 +01:00
|
|
|
//
|
2022-12-31 22:28:08 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
|
|
|
#include "td/mtproto/Transport.h"
|
|
|
|
|
|
|
|
#include "td/mtproto/AuthKey.h"
|
2019-07-26 23:39:39 +02:00
|
|
|
#include "td/mtproto/KDF.h"
|
2023-09-21 16:52:33 +02:00
|
|
|
#include "td/mtproto/MessageId.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-12-19 22:57:56 +01:00
|
|
|
#include "td/utils/as.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/utils/crypto.h"
|
|
|
|
#include "td/utils/format.h"
|
|
|
|
#include "td/utils/logging.h"
|
|
|
|
#include "td/utils/Random.h"
|
2021-05-17 14:21:11 +02:00
|
|
|
#include "td/utils/SliceBuilder.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/utils/Status.h"
|
|
|
|
|
|
|
|
#include <array>
|
2019-01-31 03:27:21 +01:00
|
|
|
#include <tuple>
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
namespace td {
|
2020-10-05 17:07:23 +02:00
|
|
|
|
|
|
|
int VERBOSITY_NAME(raw_mtproto) = VERBOSITY_NAME(DEBUG) + 10;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
namespace mtproto {
|
2018-12-19 21:35:13 +01:00
|
|
|
|
2019-01-31 03:27:21 +01:00
|
|
|
#pragma pack(push, 4)
|
|
|
|
#if TD_MSVC
|
|
|
|
#pragma warning(push)
|
|
|
|
#pragma warning(disable : 4200)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct CryptoHeader {
|
|
|
|
uint64 auth_key_id;
|
|
|
|
UInt128 message_key;
|
|
|
|
|
|
|
|
// encrypted part
|
|
|
|
uint64 salt;
|
|
|
|
uint64 session_id;
|
|
|
|
|
|
|
|
// It is weird to generate message_id and seq_no while writing a packet.
|
|
|
|
//
|
2023-09-21 16:52:33 +02:00
|
|
|
// uint64 msg_id;
|
2019-01-31 03:27:21 +01:00
|
|
|
// uint32 seq_no;
|
|
|
|
// uint32 message_data_length;
|
|
|
|
uint8 data[0]; // use compiler extension
|
|
|
|
|
|
|
|
static size_t encrypted_header_size() {
|
|
|
|
return sizeof(salt) + sizeof(session_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8 *encrypt_begin() {
|
|
|
|
return reinterpret_cast<uint8 *>(&salt);
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint8 *encrypt_begin() const {
|
|
|
|
return reinterpret_cast<const uint8 *>(&salt);
|
|
|
|
}
|
|
|
|
|
|
|
|
CryptoHeader() = delete;
|
|
|
|
CryptoHeader(const CryptoHeader &) = delete;
|
|
|
|
CryptoHeader(CryptoHeader &&) = delete;
|
|
|
|
CryptoHeader &operator=(const CryptoHeader &) = delete;
|
|
|
|
CryptoHeader &operator=(CryptoHeader &&) = delete;
|
|
|
|
~CryptoHeader() = delete;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct CryptoPrefix {
|
2023-09-21 16:52:33 +02:00
|
|
|
uint64 msg_id;
|
2019-01-31 03:27:21 +01:00
|
|
|
uint32 seq_no;
|
|
|
|
uint32 message_data_length;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct EndToEndHeader {
|
|
|
|
uint64 auth_key_id;
|
|
|
|
UInt128 message_key;
|
|
|
|
|
|
|
|
// encrypted part
|
|
|
|
// uint32 message_data_length;
|
|
|
|
uint8 data[0]; // use compiler extension
|
|
|
|
|
|
|
|
static size_t encrypted_header_size() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8 *encrypt_begin() {
|
|
|
|
return reinterpret_cast<uint8 *>(&data);
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint8 *encrypt_begin() const {
|
|
|
|
return reinterpret_cast<const uint8 *>(&data);
|
|
|
|
}
|
|
|
|
|
|
|
|
EndToEndHeader() = delete;
|
|
|
|
EndToEndHeader(const EndToEndHeader &) = delete;
|
|
|
|
EndToEndHeader(EndToEndHeader &&) = delete;
|
|
|
|
EndToEndHeader &operator=(const EndToEndHeader &) = delete;
|
|
|
|
EndToEndHeader &operator=(EndToEndHeader &&) = delete;
|
|
|
|
~EndToEndHeader() = delete;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct EndToEndPrefix {
|
|
|
|
uint32 message_data_length;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct NoCryptoHeader {
|
|
|
|
uint64 auth_key_id;
|
|
|
|
|
2023-09-21 16:52:33 +02:00
|
|
|
// msg_id is removed from CryptoHeader. Should be removed from here too.
|
2019-01-31 03:27:21 +01:00
|
|
|
//
|
2023-09-21 16:52:33 +02:00
|
|
|
// uint64 msg_id;
|
2019-01-31 03:27:21 +01:00
|
|
|
// uint32 message_data_length;
|
|
|
|
uint8 data[0]; // use compiler extension
|
|
|
|
|
|
|
|
NoCryptoHeader() = delete;
|
|
|
|
NoCryptoHeader(const NoCryptoHeader &) = delete;
|
|
|
|
NoCryptoHeader(NoCryptoHeader &&) = delete;
|
|
|
|
NoCryptoHeader &operator=(const NoCryptoHeader &) = delete;
|
|
|
|
NoCryptoHeader &operator=(NoCryptoHeader &&) = delete;
|
|
|
|
~NoCryptoHeader() = delete;
|
|
|
|
};
|
|
|
|
|
|
|
|
#if TD_MSVC
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
2021-07-02 02:25:09 +02:00
|
|
|
// MTProto v1.0
|
2018-12-31 20:04:05 +01:00
|
|
|
template <class HeaderT>
|
2019-01-31 03:27:21 +01:00
|
|
|
std::pair<uint32, UInt128> Transport::calc_message_ack_and_key(const HeaderT &head, size_t data_size) {
|
2018-12-31 20:04:05 +01:00
|
|
|
Slice part(head.encrypt_begin(), head.data + data_size);
|
|
|
|
UInt<160> message_sha1;
|
|
|
|
sha1(part, message_sha1.raw);
|
2019-01-31 03:27:21 +01:00
|
|
|
return std::make_pair(as<uint32>(message_sha1.raw) | (1u << 31), as<UInt128>(message_sha1.raw + 4));
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class HeaderT>
|
|
|
|
size_t Transport::calc_crypto_size(size_t data_size) {
|
|
|
|
size_t enc_size = HeaderT::encrypted_header_size();
|
|
|
|
size_t raw_size = sizeof(HeaderT) - enc_size;
|
|
|
|
return raw_size + ((enc_size + data_size + 15) & ~15);
|
|
|
|
}
|
|
|
|
|
2021-07-02 02:25:09 +02:00
|
|
|
// MTProto v2.0
|
2019-01-31 03:27:21 +01:00
|
|
|
std::pair<uint32, UInt128> Transport::calc_message_key2(const AuthKey &auth_key, int X, Slice to_encrypt) {
|
2018-12-31 20:04:05 +01:00
|
|
|
// msg_key_large = SHA256 (substr (auth_key, 88+x, 32) + plaintext + random_padding);
|
|
|
|
Sha256State state;
|
2019-07-23 02:20:11 +02:00
|
|
|
state.init();
|
|
|
|
state.feed(Slice(auth_key.key()).substr(88 + X, 32));
|
|
|
|
state.feed(to_encrypt);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
uint8 msg_key_large_raw[32];
|
|
|
|
MutableSlice msg_key_large(msg_key_large_raw, sizeof(msg_key_large_raw));
|
2019-07-23 02:50:03 +02:00
|
|
|
state.extract(msg_key_large, true);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
// msg_key = substr (msg_key_large, 8, 16);
|
2018-11-06 17:00:03 +01:00
|
|
|
UInt128 res;
|
2023-02-02 15:40:47 +01:00
|
|
|
as_mutable_slice(res).copy_from(msg_key_large.substr(8, 16));
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-01-31 03:27:21 +01:00
|
|
|
return std::make_pair(as<uint32>(msg_key_large_raw) | (1u << 31), res);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2019-07-04 12:56:10 +02:00
|
|
|
namespace {
|
|
|
|
size_t do_calc_crypto_size2_basic(size_t data_size, size_t enc_size, size_t raw_size) {
|
2018-12-31 20:04:05 +01:00
|
|
|
size_t encrypted_size = (enc_size + data_size + 12 + 15) & ~15;
|
2019-07-04 12:56:10 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
std::array<size_t, 10> sizes{{64, 128, 192, 256, 384, 512, 768, 1024, 1280}};
|
|
|
|
for (auto size : sizes) {
|
|
|
|
if (encrypted_size <= size) {
|
|
|
|
return raw_size + size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
encrypted_size = (encrypted_size - 1280 + 447) / 448 * 448 + 1280;
|
|
|
|
|
|
|
|
return raw_size + encrypted_size;
|
|
|
|
}
|
|
|
|
|
2019-07-04 12:56:10 +02:00
|
|
|
size_t do_calc_crypto_size2_rand(size_t data_size, size_t enc_size, size_t raw_size) {
|
2019-09-15 05:19:46 +02:00
|
|
|
size_t rand_data_size = Random::secure_uint32() & 0xff;
|
2019-07-04 12:56:10 +02:00
|
|
|
size_t encrypted_size = (enc_size + data_size + rand_data_size + 12 + 15) & ~15;
|
|
|
|
return raw_size + encrypted_size;
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
template <class HeaderT>
|
2023-09-09 23:04:55 +02:00
|
|
|
size_t Transport::calc_crypto_size2(size_t data_size, PacketInfo *packet_info) {
|
2019-07-04 12:56:10 +02:00
|
|
|
size_t enc_size = HeaderT::encrypted_header_size();
|
|
|
|
size_t raw_size = sizeof(HeaderT) - enc_size;
|
2023-09-09 23:04:55 +02:00
|
|
|
if (packet_info->use_random_padding) {
|
2023-09-09 22:51:40 +02:00
|
|
|
return do_calc_crypto_size2_rand(data_size, enc_size, raw_size);
|
2019-07-04 12:56:10 +02:00
|
|
|
} else {
|
2023-09-09 22:51:40 +02:00
|
|
|
return do_calc_crypto_size2_basic(data_size, enc_size, raw_size);
|
2019-07-04 12:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
size_t Transport::calc_no_crypto_size(size_t data_size) {
|
|
|
|
return sizeof(NoCryptoHeader) + data_size;
|
|
|
|
}
|
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
Status Transport::read_no_crypto(MutableSlice message, PacketInfo *packet_info, MutableSlice *data) {
|
2018-12-31 20:04:05 +01:00
|
|
|
if (message.size() < sizeof(NoCryptoHeader)) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: too small [message.size() = " << message.size()
|
2018-12-31 20:04:05 +01:00
|
|
|
<< "] < [sizeof(NoCryptoHeader) = " << sizeof(NoCryptoHeader) << "]");
|
|
|
|
}
|
|
|
|
size_t data_size = message.size() - sizeof(NoCryptoHeader);
|
|
|
|
CHECK(message.size() == calc_no_crypto_size(data_size));
|
2018-12-19 15:49:13 +01:00
|
|
|
*data = MutableSlice(message.begin() + sizeof(NoCryptoHeader), data_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
return Status::OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class HeaderT, class PrefixT>
|
|
|
|
Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &auth_key, HeaderT **header_ptr,
|
2023-09-09 23:04:55 +02:00
|
|
|
PrefixT **prefix_ptr, MutableSlice *data, PacketInfo *packet_info) {
|
2018-12-31 20:04:05 +01:00
|
|
|
if (message.size() < sizeof(HeaderT)) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: too small [message.size() = " << message.size()
|
2018-12-31 20:04:05 +01:00
|
|
|
<< "] < [sizeof(HeaderT) = " << sizeof(HeaderT) << "]");
|
|
|
|
}
|
2018-12-19 15:49:13 +01:00
|
|
|
//FIXME: rewrite without reinterpret cast
|
|
|
|
auto *header = reinterpret_cast<HeaderT *>(message.begin());
|
2018-12-31 20:04:05 +01:00
|
|
|
*header_ptr = header;
|
|
|
|
auto to_decrypt = MutableSlice(header->encrypt_begin(), message.uend());
|
2021-06-02 00:50:00 +02:00
|
|
|
to_decrypt.remove_suffix(to_decrypt.size() & 15);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
if (header->auth_key_id != auth_key.id()) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: auth_key_id mismatch [found = "
|
2018-12-31 20:04:05 +01:00
|
|
|
<< format::as_hex(header->auth_key_id)
|
2019-05-13 18:34:23 +02:00
|
|
|
<< "] [expected = " << format::as_hex(auth_key.id()) << "]");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
UInt256 aes_key;
|
|
|
|
UInt256 aes_iv;
|
2023-09-09 23:04:55 +02:00
|
|
|
if (packet_info->version == 1) {
|
2018-12-31 20:04:05 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-02-02 15:40:47 +01:00
|
|
|
aes_ige_decrypt(as_slice(aes_key), as_mutable_slice(aes_iv), to_decrypt, to_decrypt);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
size_t tail_size = message.end() - reinterpret_cast<char *>(header->data);
|
|
|
|
if (tail_size < sizeof(PrefixT)) {
|
|
|
|
return Status::Error("Too small encrypted part");
|
|
|
|
}
|
2018-12-19 15:49:13 +01:00
|
|
|
//FIXME: rewrite without reinterpret cast
|
|
|
|
auto *prefix = reinterpret_cast<PrefixT *>(header->data);
|
2018-12-31 20:04:05 +01:00
|
|
|
*prefix_ptr = prefix;
|
|
|
|
size_t data_size = prefix->message_data_length + sizeof(PrefixT);
|
2021-07-11 01:13:04 +02:00
|
|
|
bool is_length_bad = false;
|
2018-12-31 20:04:05 +01:00
|
|
|
UInt128 real_message_key;
|
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
if (packet_info->version == 1) {
|
|
|
|
is_length_bad |= packet_info->check_mod4 && prefix->message_data_length % 4 != 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
auto expected_size = calc_crypto_size<HeaderT>(data_size);
|
2021-07-11 01:13:04 +02:00
|
|
|
is_length_bad |= expected_size != message.size();
|
|
|
|
auto check_size = data_size * (1 - is_length_bad) + tail_size * is_length_bad;
|
2023-09-09 23:04:55 +02:00
|
|
|
std::tie(packet_info->message_ack, real_message_key) = calc_message_ack_and_key(*header, check_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
} else {
|
2023-09-09 23:04:55 +02:00
|
|
|
std::tie(packet_info->message_ack, real_message_key) = calc_message_key2(auth_key, X, to_decrypt);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2021-07-11 01:13:04 +02:00
|
|
|
int is_key_bad = false;
|
2018-12-31 20:04:05 +01:00
|
|
|
for (size_t i = 0; i < sizeof(real_message_key.raw); i++) {
|
2021-07-11 01:13:04 +02:00
|
|
|
is_key_bad |= real_message_key.raw[i] ^ header->message_key.raw[i];
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2021-07-11 01:13:04 +02:00
|
|
|
if (is_key_bad != 0) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: message_key mismatch [found = "
|
2018-12-31 20:04:05 +01:00
|
|
|
<< format::as_hex_dump(header->message_key)
|
2019-05-13 18:34:23 +02:00
|
|
|
<< "] [expected = " << format::as_hex_dump(real_message_key) << "]");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2019-01-29 16:16:52 +01:00
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
if (packet_info->version == 2) {
|
|
|
|
if (packet_info->check_mod4 && prefix->message_data_length % 4 != 0) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (not divisible by four)"
|
2019-01-29 16:16:52 +01:00
|
|
|
<< tag("total_size", message.size())
|
|
|
|
<< tag("message_data_length", prefix->message_data_length));
|
|
|
|
}
|
|
|
|
if (tail_size - sizeof(PrefixT) < prefix->message_data_length) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (message_data_length is too big)"
|
2019-01-29 16:16:52 +01:00
|
|
|
<< tag("total_size", message.size())
|
|
|
|
<< tag("message_data_length", prefix->message_data_length));
|
|
|
|
}
|
|
|
|
size_t pad_size = tail_size - data_size;
|
|
|
|
if (pad_size < 12 || pad_size > 1024) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (invalid padding length)"
|
2019-01-29 16:16:52 +01:00
|
|
|
<< tag("padding_size", pad_size) << tag("total_size", message.size())
|
|
|
|
<< tag("message_data_length", prefix->message_data_length));
|
|
|
|
}
|
|
|
|
} else {
|
2021-07-11 01:13:04 +02:00
|
|
|
if (is_length_bad) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: invalid length " << tag("total_size", message.size())
|
2019-01-29 16:16:52 +01:00
|
|
|
<< tag("message_data_length", prefix->message_data_length));
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
*data = MutableSlice(header->data, data_size);
|
|
|
|
return Status::OK();
|
|
|
|
}
|
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
Status Transport::read_crypto(MutableSlice message, const AuthKey &auth_key, PacketInfo *packet_info,
|
|
|
|
MutableSlice *data) {
|
2018-12-31 20:04:05 +01:00
|
|
|
CryptoHeader *header = nullptr;
|
|
|
|
CryptoPrefix *prefix = nullptr;
|
2023-09-09 23:04:55 +02:00
|
|
|
TRY_STATUS(read_crypto_impl(8, message, auth_key, &header, &prefix, data, packet_info));
|
2018-12-31 20:04:05 +01:00
|
|
|
CHECK(header != nullptr);
|
|
|
|
CHECK(prefix != nullptr);
|
2023-09-09 23:04:55 +02:00
|
|
|
CHECK(packet_info != nullptr);
|
|
|
|
packet_info->type = PacketInfo::Common;
|
|
|
|
packet_info->salt = header->salt;
|
|
|
|
packet_info->session_id = header->session_id;
|
2023-09-21 16:52:33 +02:00
|
|
|
packet_info->message_id = MessageId(prefix->msg_id);
|
2023-09-09 23:04:55 +02:00
|
|
|
packet_info->seq_no = prefix->seq_no;
|
2018-12-31 20:04:05 +01:00
|
|
|
return Status::OK();
|
|
|
|
}
|
2023-09-09 23:04:55 +02:00
|
|
|
Status Transport::read_e2e_crypto(MutableSlice message, const AuthKey &auth_key, PacketInfo *packet_info,
|
|
|
|
MutableSlice *data) {
|
2018-12-31 20:04:05 +01:00
|
|
|
EndToEndHeader *header = nullptr;
|
|
|
|
EndToEndPrefix *prefix = nullptr;
|
2023-09-09 23:04:55 +02:00
|
|
|
TRY_STATUS(read_crypto_impl(packet_info->is_creator && packet_info->version != 1 ? 8 : 0, message, auth_key, &header,
|
|
|
|
&prefix, data, packet_info));
|
2018-12-31 20:04:05 +01:00
|
|
|
CHECK(header != nullptr);
|
|
|
|
CHECK(prefix != nullptr);
|
2023-09-09 23:04:55 +02:00
|
|
|
CHECK(packet_info != nullptr);
|
|
|
|
packet_info->type = PacketInfo::EndToEnd;
|
2018-12-31 20:04:05 +01:00
|
|
|
return Status::OK();
|
|
|
|
}
|
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
BufferWriter Transport::write_no_crypto(const Storer &storer, PacketInfo *packet_info, size_t prepend_size,
|
2023-09-09 22:46:56 +02:00
|
|
|
size_t append_size) {
|
2018-12-31 20:04:05 +01:00
|
|
|
size_t size = calc_no_crypto_size(storer.size());
|
2023-09-09 22:46:56 +02:00
|
|
|
auto packet = BufferWriter{size, prepend_size, append_size};
|
|
|
|
|
2018-12-19 15:49:13 +01:00
|
|
|
// NoCryptoHeader
|
2023-09-09 22:46:56 +02:00
|
|
|
auto *begin = packet.as_mutable_slice().ubegin();
|
|
|
|
as<uint64>(begin) = 0;
|
|
|
|
auto real_size = storer.store(begin + sizeof(uint64));
|
2018-07-06 22:33:11 +02:00
|
|
|
CHECK(real_size == storer.size());
|
2023-09-09 22:46:56 +02:00
|
|
|
return packet;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class HeaderT>
|
2023-09-09 23:04:55 +02:00
|
|
|
void Transport::write_crypto_impl(int X, const Storer &storer, const AuthKey &auth_key, PacketInfo *packet_info,
|
2023-09-09 21:22:35 +02:00
|
|
|
HeaderT *header, size_t data_size, size_t padded_size) {
|
2018-07-06 22:33:11 +02:00
|
|
|
auto real_data_size = storer.store(header->data);
|
|
|
|
CHECK(real_data_size == data_size);
|
2023-09-09 21:22:35 +02:00
|
|
|
VLOG(raw_mtproto) << "Send packet of size " << data_size << ':'
|
2018-08-22 03:04:09 +02:00
|
|
|
<< format::as_hex_dump<4>(Slice(header->data, data_size));
|
2023-09-09 21:22:35 +02:00
|
|
|
size_t pad_size = padded_size - (sizeof(HeaderT) + data_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
MutableSlice pad(header->data + data_size, pad_size);
|
|
|
|
Random::secure_bytes(pad.ubegin(), pad.size());
|
|
|
|
MutableSlice to_encrypt = MutableSlice(header->encrypt_begin(), pad.uend());
|
|
|
|
|
|
|
|
UInt256 aes_key;
|
|
|
|
UInt256 aes_iv;
|
2023-09-09 23:04:55 +02:00
|
|
|
if (packet_info->version == 1) {
|
|
|
|
std::tie(packet_info->message_ack, header->message_key) = calc_message_ack_and_key(*header, data_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
KDF(auth_key.key(), header->message_key, X, &aes_key, &aes_iv);
|
|
|
|
} else {
|
2023-09-09 23:04:55 +02:00
|
|
|
std::tie(packet_info->message_ack, header->message_key) = calc_message_key2(auth_key, X, to_encrypt);
|
2018-12-31 20:04:05 +01:00
|
|
|
KDF2(auth_key.key(), header->message_key, X, &aes_key, &aes_iv);
|
|
|
|
}
|
|
|
|
|
2023-02-02 15:40:47 +01:00
|
|
|
aes_ige_encrypt(as_slice(aes_key), as_mutable_slice(aes_iv), to_encrypt, to_encrypt);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
BufferWriter Transport::write_crypto(const Storer &storer, const AuthKey &auth_key, PacketInfo *packet_info,
|
2023-09-09 22:46:56 +02:00
|
|
|
size_t prepend_size, size_t append_size) {
|
2018-12-31 20:04:05 +01:00
|
|
|
size_t data_size = storer.size();
|
2023-09-09 21:22:35 +02:00
|
|
|
size_t padded_size;
|
2023-09-09 23:04:55 +02:00
|
|
|
if (packet_info->version == 1) {
|
2023-09-09 21:22:35 +02:00
|
|
|
padded_size = calc_crypto_size<CryptoHeader>(data_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
} else {
|
2023-09-09 23:04:55 +02:00
|
|
|
padded_size = calc_crypto_size2<CryptoHeader>(data_size, packet_info);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2023-09-09 22:46:56 +02:00
|
|
|
auto packet = BufferWriter{padded_size, prepend_size, append_size};
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-12-19 15:49:13 +01:00
|
|
|
//FIXME: rewrite without reinterpret cast
|
2023-09-09 22:46:56 +02:00
|
|
|
auto &header = *reinterpret_cast<CryptoHeader *>(packet.as_mutable_slice().begin());
|
2018-12-31 20:04:05 +01:00
|
|
|
header.auth_key_id = auth_key.id();
|
2023-09-09 23:04:55 +02:00
|
|
|
header.salt = packet_info->salt;
|
|
|
|
header.session_id = packet_info->session_id;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
write_crypto_impl(0, storer, auth_key, packet_info, &header, data_size, padded_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2023-09-09 22:46:56 +02:00
|
|
|
return packet;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
BufferWriter Transport::write_e2e_crypto(const Storer &storer, const AuthKey &auth_key, PacketInfo *packet_info,
|
2023-09-09 22:46:56 +02:00
|
|
|
size_t prepend_size, size_t append_size) {
|
2018-12-31 20:04:05 +01:00
|
|
|
size_t data_size = storer.size();
|
2023-09-09 21:22:35 +02:00
|
|
|
size_t padded_size;
|
2023-09-09 23:04:55 +02:00
|
|
|
if (packet_info->version == 1) {
|
2023-09-09 21:22:35 +02:00
|
|
|
padded_size = calc_crypto_size<EndToEndHeader>(data_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
} else {
|
2023-09-09 23:04:55 +02:00
|
|
|
padded_size = calc_crypto_size2<EndToEndHeader>(data_size, packet_info);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2023-09-09 22:46:56 +02:00
|
|
|
auto packet = BufferWriter{padded_size, prepend_size, append_size};
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-12-19 15:49:13 +01:00
|
|
|
//FIXME: rewrite without reinterpret cast
|
2023-09-09 22:46:56 +02:00
|
|
|
auto &header = *reinterpret_cast<EndToEndHeader *>(packet.as_mutable_slice().begin());
|
2018-12-31 20:04:05 +01:00
|
|
|
header.auth_key_id = auth_key.id();
|
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
write_crypto_impl(packet_info->is_creator || packet_info->version == 1 ? 0 : 8, storer, auth_key, packet_info,
|
|
|
|
&header, data_size, padded_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2023-09-09 22:46:56 +02:00
|
|
|
return packet;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Result<uint64> Transport::read_auth_key_id(Slice message) {
|
|
|
|
if (message.size() < 8) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: smaller than 8 bytes [size = " << message.size() << "]");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
return as<uint64>(message.begin());
|
|
|
|
}
|
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
Result<Transport::ReadResult> Transport::read(MutableSlice message, const AuthKey &auth_key, PacketInfo *packet_info) {
|
2018-06-25 23:10:53 +02:00
|
|
|
if (message.size() < 12) {
|
2018-06-17 19:52:40 +02:00
|
|
|
if (message.size() < 4) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error(PSLICE() << "Invalid MTProto message: smaller than 4 bytes [size = " << message.size()
|
2019-05-13 18:34:23 +02:00
|
|
|
<< "]");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2018-06-17 19:52:40 +02:00
|
|
|
|
2018-12-19 23:46:55 +01:00
|
|
|
int32 code = as<int32>(message.begin());
|
2018-06-17 19:52:40 +02:00
|
|
|
if (code == 0) {
|
|
|
|
return ReadResult::make_nop();
|
2018-06-25 23:10:53 +02:00
|
|
|
} else if (code == -1 && message.size() >= 8) {
|
|
|
|
return ReadResult::make_quick_ack(as<uint32>(message.begin() + 4));
|
2018-06-17 19:52:40 +02:00
|
|
|
} else {
|
|
|
|
return ReadResult::make_error(code);
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2018-06-17 19:52:40 +02:00
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
packet_info->no_crypto_flag = as<int64>(message.begin()) == 0;
|
2018-06-17 19:52:40 +02:00
|
|
|
MutableSlice data;
|
2023-09-09 23:04:55 +02:00
|
|
|
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));
|
2018-12-31 20:04:05 +01:00
|
|
|
} else {
|
|
|
|
if (auth_key.empty()) {
|
2021-07-02 02:25:09 +02:00
|
|
|
return Status::Error("Failed to decrypt MTProto message: auth key is empty");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2023-09-09 23:04:55 +02:00
|
|
|
TRY_STATUS(read_crypto(message, auth_key, packet_info, &data));
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2018-06-17 19:52:40 +02:00
|
|
|
return ReadResult::make_packet(data);
|
2018-06-17 21:56:21 +02:00
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2023-09-09 23:04:55 +02:00
|
|
|
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);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2023-09-09 23:04:55 +02:00
|
|
|
if (packet_info->no_crypto_flag) {
|
|
|
|
return write_no_crypto(storer, packet_info, prepend_size, append_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
} else {
|
|
|
|
CHECK(!auth_key.empty());
|
2023-09-09 23:04:55 +02:00
|
|
|
return write_crypto(storer, auth_key, packet_info, prepend_size, append_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
}
|
2018-12-19 21:35:13 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
} // namespace mtproto
|
|
|
|
} // namespace td
|