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