1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #pragma once
8 
9 #include "td/utils/BigNum.h"
10 #include "td/utils/common.h"
11 #include "td/utils/Slice.h"
12 #include "td/utils/Status.h"
13 
14 #include <utility>
15 
16 namespace td {
17 namespace mtproto {
18 
19 class DhCallback;
20 
21 class DhHandshake {
22  public:
23   void set_config(int32 g_int, Slice prime_str);
24 
25   static Status check_config(int32 g_int, Slice prime_str, DhCallback *callback);
26 
has_config()27   bool has_config() const {
28     return has_config_;
29   }
30   void set_g_a_hash(Slice g_a_hash);
31   void set_g_a(Slice g_a_str);
has_g_a()32   bool has_g_a() const {
33     return has_g_a_;
34   }
35   string get_g_a() const;
36   string get_g_b() const;
37   string get_g_b_hash() const;
38   Status run_checks(bool skip_config_check, DhCallback *callback) TD_WARN_UNUSED_RESULT;
39 
40   BigNum get_g() const;
41   BigNum get_p() const;
42   BigNum get_b() const;
43   BigNum get_g_ab();
44 
45   std::pair<int64, string> gen_key();
46 
47   static int64 calc_key_id(Slice auth_key);
48 
49   enum Flags { HasConfig = 1, HasGA = 2 };
50 
51   template <class StorerT>
store(StorerT & storer)52   void store(StorerT &storer) const {
53     auto flags = 0;
54     if (has_config_) {
55       flags |= HasConfig;
56     }
57     if (has_g_a_) {
58       flags |= HasGA;
59     }
60     storer.store_int(flags);
61 
62     if (has_config_) {
63       // prime_, prime_str_, b_, g_, g_int_, g_b_
64       storer.store_string(prime_str_);
65       storer.store_string(b_.to_binary());
66       storer.store_int(g_int_);
67       storer.store_string(g_b_.to_binary());
68     }
69     if (has_g_a_) {
70       storer.store_string(g_a_.to_binary());
71     }
72   }
73   template <class ParserT>
parse(ParserT & parser)74   void parse(ParserT &parser) {
75     auto flags = parser.fetch_int();
76     if (flags & HasConfig) {
77       has_config_ = true;
78     }
79     if (flags & HasGA) {
80       has_g_a_ = true;
81     }
82     if (has_config_) {
83       // prime_, prime_str_, b_, g_, g_int_, g_b_
84       prime_str_ = parser.template fetch_string<std::string>();
85       prime_ = BigNum::from_binary(prime_str_);
86 
87       b_ = BigNum::from_binary(parser.template fetch_string<string>());
88 
89       g_int_ = parser.fetch_int();
90       g_.set_value(g_int_);
91 
92       g_b_ = BigNum::from_binary(parser.template fetch_string<string>());
93     }
94     if (has_g_a_) {
95       g_a_ = BigNum::from_binary(parser.template fetch_string<string>());
96     }
97   }
98 
99  private:
100   static Status check_config(Slice prime_str, const BigNum &prime, int32 g_int, BigNumContext &ctx,
101                              DhCallback *callback) TD_WARN_UNUSED_RESULT;
102 
103   static Status dh_check(const BigNum &prime, const BigNum &g_a, const BigNum &g_b) TD_WARN_UNUSED_RESULT;
104 
105   string prime_str_;
106   BigNum prime_;
107   BigNum g_;
108   int32 g_int_ = 0;
109   BigNum b_;
110   BigNum g_b_;
111   BigNum g_a_;
112 
113   string g_a_hash_;
114   bool has_g_a_hash_{false};
115   bool ok_g_a_hash_{false};
116 
117   bool has_config_ = false;
118   bool has_g_a_ = false;
119 
120   BigNumContext ctx_;
121 };
122 
123 }  // namespace mtproto
124 }  // namespace td
125