188 lines
5.5 KiB
C
188 lines
5.5 KiB
C
|
//
|
||
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2017
|
||
|
//
|
||
|
// 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)
|
||
|
//
|
||
|
#pragma once
|
||
|
#include "td/mtproto/utils.h"
|
||
|
|
||
|
#include "td/utils/common.h"
|
||
|
#include "td/utils/int_types.h"
|
||
|
#include "td/utils/Slice.h"
|
||
|
#include "td/utils/Status.h"
|
||
|
|
||
|
#include <tuple>
|
||
|
|
||
|
namespace td {
|
||
|
namespace mtproto {
|
||
|
class AuthKey;
|
||
|
|
||
|
#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.
|
||
|
//
|
||
|
// uint64 message_id;
|
||
|
// 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 {
|
||
|
uint64 message_id;
|
||
|
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;
|
||
|
|
||
|
// message_id is removed from CryptoHeader. Should be removed from here too.
|
||
|
//
|
||
|
// int64 message_id;
|
||
|
// 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)
|
||
|
|
||
|
struct PacketInfo {
|
||
|
enum { Common, EndToEnd } type = Common;
|
||
|
uint64 auth_key_id;
|
||
|
uint32 message_ack;
|
||
|
UInt128 message_key;
|
||
|
|
||
|
uint64 salt;
|
||
|
uint64 session_id;
|
||
|
|
||
|
uint64 message_id;
|
||
|
int32 seq_no;
|
||
|
int32 version = 1;
|
||
|
bool no_crypto_flag;
|
||
|
bool is_creator = false;
|
||
|
};
|
||
|
|
||
|
class Transport {
|
||
|
public:
|
||
|
static Result<uint64> read_auth_key_id(Slice message);
|
||
|
|
||
|
// Reads mtproto packet from [message] and saves into [data].
|
||
|
// If message is encrypted, [auth_key] is used.
|
||
|
// Decryption and unpacking is made inplace, so [data] will be subslice of [message].
|
||
|
// Returns size of mtproto packet.
|
||
|
// If dest.size() >= size, the packet is also written into [dest].
|
||
|
// If auth_key is nonempty, encryption will be used.
|
||
|
static Status read(MutableSlice message, const AuthKey &auth_key, PacketInfo *info, MutableSlice *data,
|
||
|
int32 *error_code) TD_WARN_UNUSED_RESULT;
|
||
|
|
||
|
static size_t write(const Storer &storer, const AuthKey &auth_key, PacketInfo *info,
|
||
|
MutableSlice dest = MutableSlice());
|
||
|
|
||
|
private:
|
||
|
template <class HeaderT>
|
||
|
static std::tuple<uint32, UInt128> calc_message_ack_and_key(const HeaderT &head, size_t data_size);
|
||
|
|
||
|
static std::tuple<uint32, UInt128> calc_message_key2(const AuthKey &auth_key, int X, Slice to_encrypt);
|
||
|
|
||
|
template <class HeaderT>
|
||
|
static size_t calc_crypto_size(size_t data_size);
|
||
|
|
||
|
template <class HeaderT>
|
||
|
static size_t calc_crypto_size2(size_t data_size);
|
||
|
|
||
|
static size_t calc_no_crypto_size(size_t data_size);
|
||
|
|
||
|
static Status read_no_crypto(MutableSlice message, PacketInfo *info, MutableSlice *data) TD_WARN_UNUSED_RESULT;
|
||
|
|
||
|
static Status read_crypto(MutableSlice message, const AuthKey &auth_key, PacketInfo *info,
|
||
|
MutableSlice *data) TD_WARN_UNUSED_RESULT;
|
||
|
static Status read_e2e_crypto(MutableSlice message, const AuthKey &auth_key, PacketInfo *info,
|
||
|
MutableSlice *data) TD_WARN_UNUSED_RESULT;
|
||
|
template <class HeaderT, class PrefixT>
|
||
|
static Status read_crypto_impl(int X, MutableSlice message, const AuthKey &auth_key, HeaderT **header_ptr,
|
||
|
PrefixT **prefix_ptr, MutableSlice *data, PacketInfo *info) TD_WARN_UNUSED_RESULT;
|
||
|
|
||
|
static size_t write_no_crypto(const Storer &storer, PacketInfo *info, MutableSlice dest);
|
||
|
|
||
|
static size_t write_crypto(const Storer &storer, const AuthKey &auth_key, PacketInfo *info, MutableSlice dest);
|
||
|
static size_t write_e2e_crypto(const Storer &storer, const AuthKey &auth_key, PacketInfo *info, MutableSlice dest);
|
||
|
template <class HeaderT>
|
||
|
static void write_crypto_impl(int X, const Storer &storer, const AuthKey &auth_key, PacketInfo *info, HeaderT *header,
|
||
|
size_t data_size);
|
||
|
};
|
||
|
} // namespace mtproto
|
||
|
} // namespace td
|