1 /*
2
3 Copyright (c) 2007-2018, Un Shyam, Arvid Norberg, Steven Siloti
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30
31 */
32
33 #if !defined TORRENT_DISABLE_ENCRYPTION
34
35 #include <cstdint>
36 #include <algorithm>
37 #include <random>
38
39 #include "libtorrent/aux_/disable_warnings_push.hpp"
40
41 #include <boost/multiprecision/integer.hpp>
42 #include <boost/multiprecision/cpp_int.hpp>
43
44 // for backwards compatibility with boost < 1.60 which was before export_bits
45 // and import_bits were introduced
46 #if BOOST_VERSION < 106000
47 #include "libtorrent/aux_/cppint_import_export.hpp"
48 #endif
49
50 #include "libtorrent/aux_/disable_warnings_pop.hpp"
51
52 #include "libtorrent/random.hpp"
53 #include "libtorrent/aux_/alloca.hpp"
54 #include "libtorrent/pe_crypto.hpp"
55 #include "libtorrent/hasher.hpp"
56
57 namespace libtorrent {
58
59 namespace mp = boost::multiprecision;
60
61 namespace {
62 // TODO: it would be nice to get the literal working
63 key_t const dh_prime
64 ("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563");
65 }
66
export_key(key_t const & k)67 std::array<char, 96> export_key(key_t const& k)
68 {
69 std::array<char, 96> ret;
70 auto* begin = reinterpret_cast<std::uint8_t*>(ret.data());
71 std::uint8_t* end = mp::export_bits(k, begin, 8);
72
73 // TODO: it would be nice to be able to export to a fixed width field, so
74 // we wouldn't have to shift it later
75 if (end < begin + 96)
76 {
77 int const len = int(end - begin);
78 std::memmove(begin + 96 - len, begin, aux::numeric_cast<std::size_t>(len));
79 std::memset(begin, 0, aux::numeric_cast<std::size_t>(96 - len));
80 }
81 return ret;
82 }
83
84 void rc4_init(const unsigned char* in, std::size_t len, rc4 *state);
85 std::size_t rc4_encrypt(unsigned char *out, std::size_t outlen, rc4 *state);
86
87 // Set the prime P and the generator, generate local public key
dh_key_exchange()88 dh_key_exchange::dh_key_exchange()
89 {
90 aux::array<std::uint8_t, 96> random_key;
91 aux::random_bytes({reinterpret_cast<char*>(random_key.data())
92 , static_cast<std::ptrdiff_t>(random_key.size())});
93
94 // create local key (random)
95 mp::import_bits(m_dh_local_secret, random_key.begin(), random_key.end());
96
97 // key = (2 ^ secret) % prime
98 m_dh_local_key = mp::powm(key_t(2), m_dh_local_secret, dh_prime);
99 }
100
101 // compute shared secret given remote public key
compute_secret(std::uint8_t const * remote_pubkey)102 void dh_key_exchange::compute_secret(std::uint8_t const* remote_pubkey)
103 {
104 TORRENT_ASSERT(remote_pubkey);
105 key_t key;
106 mp::import_bits(key, remote_pubkey, remote_pubkey + 96);
107 compute_secret(key);
108 }
109
compute_secret(key_t const & remote_pubkey)110 void dh_key_exchange::compute_secret(key_t const& remote_pubkey)
111 {
112 // shared_secret = (remote_pubkey ^ local_secret) % prime
113 m_dh_shared_secret = mp::powm(remote_pubkey, m_dh_local_secret, dh_prime);
114
115 std::array<char, 96> buffer;
116 mp::export_bits(m_dh_shared_secret, reinterpret_cast<std::uint8_t*>(buffer.data()), 8);
117
118 static char const req3[4] = {'r', 'e', 'q', '3'};
119 // calculate the xor mask for the obfuscated hash
120 m_xor_mask = hasher(req3).update(buffer).final();
121 }
122
123 std::tuple<int, span<span<char const>>>
encrypt(span<span<char>> iovec)124 encryption_handler::encrypt(
125 span<span<char>> iovec)
126 {
127 TORRENT_ASSERT(!m_send_barriers.empty());
128 TORRENT_ASSERT(m_send_barriers.front().enc_handler);
129
130 int to_process = m_send_barriers.front().next;
131
132 span<span<char>> bufs;
133 bool need_destruct = false;
134 if (to_process != INT_MAX)
135 {
136 TORRENT_ALLOCA(abufs, span<char>, iovec.size());
137 bufs = abufs;
138 need_destruct = true;
139 int num_bufs = 0;
140 for (int i = 0; to_process > 0 && i < iovec.size(); ++i)
141 {
142 ++num_bufs;
143 int const size = int(iovec[i].size());
144 if (to_process < size)
145 {
146 new (&bufs[i]) span<char>(
147 iovec[i].data(), to_process);
148 to_process = 0;
149 }
150 else
151 {
152 new (&bufs[i]) span<char>(iovec[i]);
153 to_process -= size;
154 }
155 }
156 bufs = bufs.first(num_bufs);
157 }
158 else
159 {
160 bufs = iovec;
161 }
162
163 int next_barrier = 0;
164 span<span<char const>> out_iovec;
165 if (!bufs.empty())
166 {
167 std::tie(next_barrier, out_iovec)
168 = m_send_barriers.front().enc_handler->encrypt(bufs);
169 }
170
171 if (m_send_barriers.front().next != INT_MAX)
172 {
173 // to_process holds the difference between the size of the buffers
174 // and the bytes left to the next barrier
175 // if it's zero then pop the barrier
176 // otherwise update the number of bytes remaining to the next barrier
177 if (to_process == 0)
178 {
179 if (m_send_barriers.size() == 1)
180 {
181 // transitioning back to plaintext
182 next_barrier = INT_MAX;
183 }
184 m_send_barriers.pop_front();
185 }
186 else
187 {
188 m_send_barriers.front().next = to_process;
189 }
190 }
191
192 #if TORRENT_USE_ASSERTS
193 if (next_barrier != INT_MAX && next_barrier != 0)
194 {
195 int payload = 0;
196 for (auto buf : bufs)
197 payload += int(buf.size());
198
199 int overhead = 0;
200 for (auto buf : out_iovec)
201 overhead += int(buf.size());
202 TORRENT_ASSERT(overhead + payload == next_barrier);
203 }
204 #endif
205 if (need_destruct)
206 {
207 for (auto buf : bufs)
208 buf.~span<char>();
209 }
210 return std::make_tuple(next_barrier, out_iovec);
211 }
212
decrypt(crypto_receive_buffer & recv_buffer,std::size_t & bytes_transferred)213 int encryption_handler::decrypt(crypto_receive_buffer& recv_buffer
214 , std::size_t& bytes_transferred)
215 {
216 TORRENT_ASSERT(!is_recv_plaintext());
217 int consume = 0;
218 if (recv_buffer.crypto_packet_finished())
219 {
220 span<char> wr_buf = recv_buffer.mutable_buffer(int(bytes_transferred));
221 int produce = 0;
222 int packet_size = 0;
223 std::tie(consume, produce, packet_size) = m_dec_handler->decrypt(wr_buf);
224 TORRENT_ASSERT(packet_size || produce);
225 TORRENT_ASSERT(packet_size >= 0);
226 TORRENT_ASSERT(produce >= 0);
227 bytes_transferred = std::size_t(produce);
228 if (packet_size)
229 recv_buffer.crypto_cut(consume, packet_size);
230 }
231 else
232 bytes_transferred = 0;
233 return consume;
234 }
235
switch_send_crypto(std::shared_ptr<crypto_plugin> crypto,int pending_encryption)236 bool encryption_handler::switch_send_crypto(std::shared_ptr<crypto_plugin> crypto
237 , int pending_encryption)
238 {
239 bool place_barrier = false;
240 if (!m_send_barriers.empty())
241 {
242 auto const end = std::prev(m_send_barriers.end());
243 for (auto b = m_send_barriers.begin(); b != end; ++b)
244 pending_encryption -= b->next;
245 TORRENT_ASSERT(pending_encryption >= 0);
246 m_send_barriers.back().next = pending_encryption;
247 }
248 else if (crypto)
249 place_barrier = true;
250
251 if (crypto)
252 m_send_barriers.push_back(barrier(crypto, INT_MAX));
253
254 return place_barrier;
255 }
256
switch_recv_crypto(std::shared_ptr<crypto_plugin> crypto,crypto_receive_buffer & recv_buffer)257 void encryption_handler::switch_recv_crypto(std::shared_ptr<crypto_plugin> crypto
258 , crypto_receive_buffer& recv_buffer)
259 {
260 m_dec_handler = crypto;
261 int packet_size = 0;
262 if (crypto)
263 {
264 int consume = 0;
265 int produce = 0;
266 std::vector<span<char>> wr_buf;
267 std::tie(consume, produce, packet_size) = crypto->decrypt(wr_buf);
268 TORRENT_ASSERT(wr_buf.empty());
269 TORRENT_ASSERT(consume == 0);
270 TORRENT_ASSERT(produce == 0);
271 }
272 recv_buffer.crypto_reset(packet_size);
273 }
274
rc4_handler()275 rc4_handler::rc4_handler()
276 : m_encrypt(false)
277 , m_decrypt(false)
278 {
279 m_rc4_incoming.x = 0;
280 m_rc4_incoming.y = 0;
281 m_rc4_outgoing.x = 0;
282 m_rc4_outgoing.y = 0;
283 }
284
set_incoming_key(span<char const> key)285 void rc4_handler::set_incoming_key(span<char const> key)
286 {
287 m_decrypt = true;
288 rc4_init(reinterpret_cast<unsigned char const*>(key.data())
289 , std::size_t(key.size()), &m_rc4_incoming);
290 // Discard first 1024 bytes
291 char buf[1024];
292 span<char> vec(buf, sizeof(buf));
293 decrypt(vec);
294 }
295
set_outgoing_key(span<char const> key)296 void rc4_handler::set_outgoing_key(span<char const> key)
297 {
298 m_encrypt = true;
299 rc4_init(reinterpret_cast<unsigned char const*>(key.data())
300 , std::size_t(key.size()), &m_rc4_outgoing);
301 // Discard first 1024 bytes
302 char buf[1024];
303 span<char> vec(buf, sizeof(buf));
304 encrypt(vec);
305 }
306
307 std::tuple<int, span<span<char const>>>
encrypt(span<span<char>> bufs)308 rc4_handler::encrypt(span<span<char>> bufs)
309 {
310 span<span<char const>> empty;
311 if (!m_encrypt) return std::make_tuple(0, empty);
312 if (bufs.empty()) return std::make_tuple(0, empty);
313
314 int bytes_processed = 0;
315 for (auto& buf : bufs)
316 {
317 auto* const pos = reinterpret_cast<unsigned char*>(buf.data());
318 int const len = int(buf.size());
319
320 TORRENT_ASSERT(len >= 0);
321 TORRENT_ASSERT(pos);
322
323 bytes_processed += len;
324 rc4_encrypt(pos, std::uint32_t(len), &m_rc4_outgoing);
325 }
326 return std::make_tuple(bytes_processed, empty);
327 }
328
decrypt(span<span<char>> bufs)329 std::tuple<int, int, int> rc4_handler::decrypt(span<span<char>> bufs)
330 {
331 if (!m_decrypt) return std::make_tuple(0, 0, 0);
332
333 int bytes_processed = 0;
334 for (auto& buf : bufs)
335 {
336 auto* const pos = reinterpret_cast<unsigned char*>(buf.data());
337 int const len = int(buf.size());
338
339 TORRENT_ASSERT(len >= 0);
340 TORRENT_ASSERT(pos);
341
342 bytes_processed += len;
343 rc4_encrypt(pos, std::uint32_t(len), &m_rc4_incoming);
344 }
345 return std::make_tuple(0, bytes_processed, 0);
346 }
347
348 // All this code is based on libTomCrypt (http://www.libtomcrypt.com/)
349 // this library is public domain and has been specially
350 // tailored for libtorrent by Arvid Norberg
351
rc4_init(const unsigned char * in,std::size_t len,rc4 * state)352 void rc4_init(const unsigned char* in, std::size_t len, rc4 *state)
353 {
354 std::size_t const key_size = sizeof(state->buf);
355 aux::array<std::uint8_t, key_size> key;
356 std::uint8_t tmp, *s;
357 int keylen, x, y, j;
358
359 TORRENT_ASSERT(state != nullptr);
360 TORRENT_ASSERT(len <= key_size);
361 if (len > key_size) len = key_size;
362
363 state->x = 0;
364 while (len--) {
365 state->buf[state->x++] = *in++;
366 }
367
368 /* extract the key */
369 s = state->buf.data();
370 std::memcpy(key.data(), s, key_size);
371 keylen = state->x;
372
373 /* make RC4 perm and shuffle */
374 for (x = 0; x < int(key_size); ++x) {
375 s[x] = x & 0xff;
376 }
377
378 for (j = x = y = 0; x < int(key_size); x++) {
379 y = (y + state->buf[x] + key[j++]) & 255;
380 if (j == keylen) {
381 j = 0;
382 }
383 tmp = s[x]; s[x] = s[y]; s[y] = tmp;
384 }
385 state->x = 0;
386 state->y = 0;
387 }
388
rc4_encrypt(unsigned char * out,std::size_t outlen,rc4 * state)389 std::size_t rc4_encrypt(unsigned char *out, std::size_t outlen, rc4 *state)
390 {
391 std::uint8_t x, y, *s, tmp;
392 std::size_t n;
393
394 TORRENT_ASSERT(out != nullptr);
395 TORRENT_ASSERT(state != nullptr);
396
397 n = outlen;
398 x = state->x & 0xff;
399 y = state->y & 0xff;
400 s = state->buf.data();
401 while (outlen--) {
402 x = (x + 1) & 255;
403 y = (y + s[x]) & 255;
404 tmp = s[x]; s[x] = s[y]; s[y] = tmp;
405 tmp = (s[x] + s[y]) & 255;
406 *out++ ^= s[tmp];
407 }
408 state->x = x;
409 state->y = y;
410 return n;
411 }
412
413 } // namespace libtorrent
414
415 #endif // TORRENT_DISABLE_ENCRYPTION
416