Mtproto: use non-deterministic padding scheme

GitOrigin-RevId: 3f6ab9ed7b9bbc8ad3ddfabe7d324175cb7e6d49
This commit is contained in:
Arseny Smirnov 2019-07-04 12:56:10 +02:00
parent b938ca635c
commit 13627727ef
9 changed files with 54 additions and 13 deletions

View File

@ -100,6 +100,10 @@ size_t Transport::max_append_size() const {
return 0;
}
bool Transport::use_random_padding() const {
return false;
}
} // namespace http
} // namespace mtproto
} // namespace td

View File

@ -42,6 +42,7 @@ class Transport : public IStreamTransport {
TransportType get_type() const override {
return {TransportType::Http, 0, secret_};
}
bool use_random_padding() const override;
private:
string secret_;

View File

@ -31,6 +31,7 @@ class IStreamTransport {
virtual size_t max_prepend_size() const = 0;
virtual size_t max_append_size() const = 0;
virtual TransportType get_type() const = 0;
virtual bool use_random_padding() const = 0;
};
unique_ptr<IStreamTransport> create_transport(TransportType type);

View File

@ -27,6 +27,8 @@ struct PacketInfo {
bool no_crypto_flag;
bool is_creator{false};
bool check_mod4{true};
bool use_random_padding{false};
uint32 size{0};
};
} // namespace mtproto

View File

@ -27,6 +27,7 @@ void RawConnection::send_crypto(const Storer &storer, int64 session_id, int64 sa
info.no_crypto_flag = false;
info.salt = salt;
info.session_id = session_id;
info.use_random_padding = transport_->use_random_padding();
auto packet = BufferWriter{Transport::write(storer, auth_key, &info), transport_->max_prepend_size(),
transport_->max_append_size()};

View File

@ -61,7 +61,7 @@ void IntermediateTransport::write_prepare_inplace(BufferWriter *message, bool qu
size_t append_size = 0;
if (with_padding()) {
append_size = static_cast<uint32>(Random::secure_int32()) % 16;
append_size = Random::secure_uint32() % 16;
MutableSlice append = message->prepare_append().truncate(append_size);
CHECK(append.size() == append_size);
Random::secure_bytes(append);
@ -170,15 +170,16 @@ void ObfuscatedTransport::init(ChainBufferReader *input, ChainBufferWriter *outp
string rheader = header;
std::reverse(rheader.begin(), rheader.end());
UInt256 key = as<UInt256>(rheader.data() + 8);
if (secret_.size() == 17) {
secret_ = secret_.substr(1);
Slice secret_view = secret_;
if (secret_view.size() == 17) {
secret_view.remove_prefix(1);
}
auto fix_key = [&](UInt256 &key) {
if (secret_.size() == 16) {
if (secret_view.size() == 16) {
Sha256State state;
sha256_init(&state);
sha256_update(as_slice(key), &state);
sha256_update(secret_, &state);
sha256_update(secret_view, &state);
sha256_final(&state, as_slice(key));
}
};

View File

@ -115,6 +115,10 @@ class OldTransport : public IStreamTransport {
return TransportType{TransportType::Tcp, 0, ""};
}
bool use_random_padding() const override {
return false;
}
private:
TransportImpl impl_{false};
ChainBufferReader *input_;
@ -126,6 +130,7 @@ class ObfuscatedTransport : public IStreamTransport {
ObfuscatedTransport(int16 dc_id, std::string secret)
: dc_id_(dc_id), secret_(std::move(secret)), impl_(secret_.size() >= 17) {
emulate_tls_ = secret_.size() >= 17 && secret_[0] == '\xee';
use_random_padding_ = secret_.size() >= 17;
}
Result<size_t> read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT;
@ -168,11 +173,15 @@ class ObfuscatedTransport : public IStreamTransport {
TransportType get_type() const override {
return TransportType{TransportType::ObfuscatedTcp, dc_id_, secret_};
}
bool use_random_padding() const override {
return use_random_padding_;
}
private:
int16 dc_id_;
std::string secret_;
bool emulate_tls_{false};
bool use_random_padding_{false};
bool is_first_tls_packet_{true};
std::string header_;
TransportImpl impl_;

View File

@ -158,11 +158,10 @@ std::pair<uint32, UInt128> Transport::calc_message_key2(const AuthKey &auth_key,
return std::make_pair(as<uint32>(msg_key_large_raw) | (1u << 31), res);
}
template <class HeaderT>
size_t Transport::calc_crypto_size2(size_t data_size) {
size_t enc_size = HeaderT::encrypted_header_size();
size_t raw_size = sizeof(HeaderT) - enc_size;
namespace {
size_t do_calc_crypto_size2_basic(size_t data_size, size_t enc_size, size_t raw_size) {
size_t encrypted_size = (enc_size + data_size + 12 + 15) & ~15;
std::array<size_t, 10> sizes{{64, 128, 192, 256, 384, 512, 768, 1024, 1280}};
for (auto size : sizes) {
if (encrypted_size <= size) {
@ -174,6 +173,29 @@ size_t Transport::calc_crypto_size2(size_t data_size) {
return raw_size + encrypted_size;
}
size_t do_calc_crypto_size2_rand(size_t data_size, size_t enc_size, size_t raw_size) {
size_t rand_data_size = td::Random::secure_uint32() & 0xff;
size_t encrypted_size = (enc_size + data_size + rand_data_size + 12 + 15) & ~15;
return raw_size + encrypted_size;
}
} // 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 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));
} else {
info->size = narrow_cast<uint32>(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;
}
@ -332,7 +354,7 @@ void Transport::write_crypto_impl(int X, const Storer &storer, const AuthKey &au
if (info->version == 1) {
size = calc_crypto_size<HeaderT>(data_size);
} else {
size = calc_crypto_size2<HeaderT>(data_size);
size = calc_crypto_size2<HeaderT>(data_size, info);
}
size_t pad_size = size - (sizeof(HeaderT) + data_size);
@ -365,7 +387,7 @@ size_t Transport::write_crypto(const Storer &storer, const AuthKey &auth_key, Pa
if (info->version == 1) {
size = calc_crypto_size<CryptoHeader>(data_size);
} else {
size = calc_crypto_size2<CryptoHeader>(data_size);
size = calc_crypto_size2<CryptoHeader>(data_size, info);
}
if (size > dest.size()) {
return size;
@ -388,7 +410,7 @@ size_t Transport::write_e2e_crypto(const Storer &storer, const AuthKey &auth_key
if (info->version == 1) {
size = calc_crypto_size<EndToEndHeader>(data_size);
} else {
size = calc_crypto_size2<EndToEndHeader>(data_size);
size = calc_crypto_size2<EndToEndHeader>(data_size, info);
}
if (size > dest.size()) {
return size;

View File

@ -97,7 +97,7 @@ class Transport {
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_crypto_size2(size_t data_size, PacketInfo *info);
static size_t calc_no_crypto_size(size_t data_size);